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 编码表

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

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

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

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

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

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

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

代码

<?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;

黄铭博客
请先登录后发表评论
  • latest comments
  • 总共0条评论