PHP Base64 编码与解码算法实现
Base64编码原理
Base64将二进制数据转换为由64个字符组成的文本序列,包含:A-Z、a-z、0-9、+、/。每个字符对应6位二进制值,3字节原始数据(24位)可转换为4个Base64字符。
编码过程示例
以字符串"123"为例:字符ASCII值转为二进制(00110001 00110010 00110011),分割为6位组:
- 001100 → 12 → 'M'
- 010011 → 19 → 'T'
- 001000 → 8 → 'I'
- 110011 → 51 → 'z'
结果:MTIz。当字节数非3倍数时需补位:
- 1字节剩余:补4个0,结果末尾加"=="(如"4" → "NA==")
- 2字节剩余:补2个0,结果末尾加"="(如"12" → "MTI=")
解码过程
根据末尾等号数量判断补位情况:
- 无等号:4字符直接转为3字节
- 一个=:最后3字符转2字节(右移2位)
- 两个==:最后2字符转1字节(右移4位)
PHP实现代码
字符与数值转换
function convertToBase64Char($value) {
if ($value < 26) return chr(65 + $value);
if ($value < 52) return chr(71 + $value);
if ($value < 62) return chr($value - 4);
return $value == 62 ? '+' : '/';
}
function convertFromBase64Char($byte) {
if ($byte < 91) return $byte - 65;
if ($byte < 123) return $byte - 71;
if ($byte < 127) return $byte + 4;
return $byte == 43 ? 62 : 63;
}
编码函数
function base64Encode($input) {
$length = strlen($input);
$blocks = intdiv($length, 3);
$remainder = $length % 3;
$output = '';
for ($i = 0; $i < $blocks; $i++) {
$offset = $i * 3;
$triplet = (ord($input[$offset]) << 16)
| (ord($input[$offset+1]) << 8)
| ord($input[$offset+2]);
$output .= convertToBase64Char($triplet >> 18);
$output .= convertToBase64Char(($triplet >> 12) & 63);
$output .= convertToBase64Char(($triplet >> 6) & 63);
$output .= convertToBase64Char($triplet & 63);
}
if ($remainder == 1) {
$lastByte = ord($input[$blocks*3]) << 4;
$output .= convertToBase64Char($lastByte >> 6);
$output .= convertToBase64Char($lastByte & 63) . '==';
} elseif ($remainder == 2) {
$lastTwo = (ord($input[$blocks*3]) << 8) | ord($input[$blocks*3+1]);
$lastTwo <<= 2;
$output .= convertToBase64Char($lastTwo >> 12);
$output .= convertToBase64Char(($lastTwo >> 6) & 63);
$output .= convertToBase64Char($lastTwo & 63) . '=';
}
return $output;
}
解码函数
function base64Decode($encoded) {
$len = strlen($encoded);
$padCount = 0;
if ($len > 1 && $encoded[$len-1] == '=') $padCount++;
if ($len > 2 && $encoded[$len-2] == '=') $padCount++;
$mainPart = substr($encoded, 0, $len - ($padCount ? 4 : 0));
$output = '';
$blockCount = strlen($mainPart) / 4;
for ($i = 0; $i < $blockCount; $i++) {
$offset = $i * 4;
$quad = (convertFromBase64Char(ord($mainPart[$offset])) << 18)
| (convertFromBase64Char(ord($mainPart[$offset+1])) << 12)
| (convertFromBase64Char(ord($mainPart[$offset+2])) << 6)
| convertFromBase64Char(ord($mainPart[$offset+3]));
$output .= chr($quad >> 16);
$output .= chr(($quad >> 8) & 255);
$output .= chr($quad & 255);
}
if ($padCount == 1) {
$lastBlock = substr($encoded, -4);
$value = (convertFromBase64Char(ord($lastBlock[0])) << 6)
| convertFromBase64Char(ord($lastBlock[1]));
$output .= chr($value >> 4);
} elseif ($padCount == 2) {
$lastBlock = substr($encoded, -4);
$value = (convertFromBase64Char(ord($lastBlock[0])) << 12)
| (convertFromBase64Char(ord($lastBlock[1])) << 6)
| convertFromBase64Char(ord($lastBlock[2]));
$output .= chr($value >> 10);
$output .= chr(($value >> 2) & 255);
}
return $output;
}