PHP 实现 base64 编码

Base64 是一种基于64个可打印字符来表示二进制数据的表示方法,编码后的数据比原始数据略长,为原来的 4/3。编码表由64 个字符组成:26个大写英文字母 + 26个小写英语字母 + 数字0-9 + 符号 "+" + 符号 "/",其 ASCII 值为 0-63

编码过程:

 1、每 3 个字节组成一组,(3*8)组成一串24个进制位;例:111001101001010110001111
 2、将 24 个进制位分 4 组,每组 6 个进制位,在前补 00 扩展成 32 个进制位 = 4 个字节;例:00111001 00101001 00010110 00001111
 3、将每个字节转十进制,匹配编码表对应字符,组成新的 4 个字符

Base64 编码表

image.png

满足 3 个字节情况下(utf-8 字符集一个中文字符等于 3 个字节)

原文本 Min 经过 base64 编码后等到新字符 TWlu

image.png

不满足 3 个字节,2 个字节情况下,在编码后的字符末尾填充1个 = 号

原文本 Mi 经过 base64 编码后等到新字符 TWk=

image.png

不满足 3 个字节,1 个字节情况下,在编码后的字符末尾填充 2 个 = 号

原文本 M 经过 base64 编码后等到新字符 TQ==

image.png

utf-8 中文字符『敏』,其对应的16进制是 E6958F,转换二进制为:111001101001010110001111 占三个字节
image.png

代码

<?php


namespace Patterns\Algorithm;


class Base64
{
    private $_encode_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    private $_strpad = ['==', '=', ''];

    /**
     * 输入字符以3个字节分组,3 个字节 = base64 4个字节
     * 3个字节为一组
     * * 第一个字符 = 输入第一个字符右移 2 位
     * * 第二个字符 = 输入第一个字符左移 4 位 + 输入第二个字符右移 4 位
     * * 第三个字符 = 输入第一个字符左移 2 位 + 输入第三个字符右移 6 位
     * * 第四个字符 = 取输入第三个字符右 6 位
     * base64 编码
     * @param string $str
     * @return string
     */
    public function encodebit(string $str):string
    {
        $strLen = strlen($str);
        $subIndex = 0;
        $subStr = $out = '';

        while ($strLen > 2){
            $subStr = substr($str, $subIndex, 3);
            $fir = ord($subStr[0]) >> 2;
            $sc = ((ord($subStr[0]) & 3) << 4) + ((ord($subStr[1])) >> 4);
            $th = ((ord($subStr[1]) & 15) << 2) + (ord($subStr[2]) >> 6);
            $end = ord($subStr[2]) & 63;

            $out .= $this->_encode_table[$fir];
            $out .= $this->_encode_table[$sc];
            $out .= $this->_encode_table[$th];
            $out .= $this->_encode_table[$end];

            $subIndex += 3;
            $strLen -= 3;
        }

        if(0 === $strLen){
            return $out;
        }

        $str = substr($str, $subIndex);
        $out .= $this->_encode_table[ord($str[0]) >> 2];

        if($strLen > 1){
            $out .= $this->_encode_table[((ord($str[0]) & 3) << 4) + (ord($str[1]) >> 4)];
            $out .= $this->_encode_table[(ord($str[1]) & 15) << 2];
            $out .= '=';
        } else {
            $out .= $this->_encode_table[(ord($str[0]) & 3) << 4];
            $out .= '==';
        }

        return $out;
    }

    /**
     * 编码
     * base64 将 3 个字节转成 4 个字节
     *  每 3 个字节组成一组,(3*8)组成一串24个进制位
     *  将 24 个进制位分 4 组,每组 6 个进制位,在前补 00 扩展成 32 个进制位 = 4 个字节
     *  将每个字节转十进制,匹配编码表对应字符,组成新的 4 个字符
     *
     * 不足 3 个字节情况:
     *  2 个字节:按照上述步骤可组成新的 3 个字符,在末尾补充 1 个 = 号,即 xxx=
     *  1 个字节:按照上述步骤可组成新的 2 个字符,在末尾补充 2 个 = 号,即 xx==
     * @param string $data
     * @return string
     */
    public function encode(string $data):string
    {
        $strLen = strlen($data);
        $subIndex = 0;
        $out = '';

        $offset = ceil($strLen / 3);
        for($i = 0; $i < $offset; $i++){
            $binstr = '';
            $subStr = substr($data, $subIndex, 3);
            $strLen = strlen($subStr);
            for($k = 0; $k < $strLen; $k++){
                $decbin = decbin(ord($subStr[$k]));
                $binstr .= str_pad($decbin, 8, 0, STR_PAD_LEFT);
            }

            $out .= $this->bintoChar($strLen, $binstr);

            $subIndex += 3;
        }

        $out .= $this->_strpad[$strLen - 1];

        return $out;
    }

    /**
     * 将8位二进制组成的进制位进行分组,6 位一组:每组在前方增 00 填充成 8 位,不足8位则在后方补 0
     * @param int $strSize
     * @param string $bin
     * @return string
     */
    private function bintoChar(int $strSize, string $bin):string
    {
        $subIndex = 0;
        $char = '';

        while ($strSize >= 0){
            $substr = '00' . substr($bin, $subIndex, 6);
            $substr = str_pad($substr, 8, 0, STR_PAD_RIGHT);
            $char .= $this->_encode_table[bindec($substr)];

            $subIndex += 6;
            $strSize--;
        }

        return $char;
    }
}

$base64 = new Base64();

$str = 'test';

echo 'base: ' . base64_encode($str),PHP_EOL;

echo 'base: ' . $base64->encodebit($str). PHP_EOL;

echo 'base: ' . $base64->encode($str) . PHP_EOL;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容

  • Base64编码由来 Base64最早是用来解决电子邮件的传输问题。 传统的电子邮件是1982年定下技术规范的,详...
    Ashton阅读 2,579评论 0 6
  • 1、Base64编码原理 下图为Base64编码索引表: 字符选用了"A-Z、a-z、0-9、+、/" 64个可打...
    M_JCs阅读 1,761评论 1 9
  • 文/BeanDou 最近,很多周围年轻的同事,都在口口相传这样一句话,我热爱工作,工作使我快乐,这是一句老掉牙的口...
    豆三叶阅读 5,630评论 3 5
  • 逸去的小孩子们也不想了 这是你永生的使命啊 摇出摇篮小小的颠簸 蹲踞着的小孩子们一同 欢笑才算是孩童们奇怪的化身 ...
    cc51150cd730阅读 251评论 0 1
  • 明天休息,要睡好! 中午醒来,洗个澡! 然后出去,浪一浪!
    小龙耶阅读 96评论 0 0