以前写过两篇博客(解决getImageData跨域问题、用php把图片编码嵌入到html)来介绍Base64相关函数解决项目中的问题,今天主要来探究Base64是如何工作的,做到之所以然并知其所以然。
Base64包含A-Z、a-z、0-9、+、/、=65个字符,其中“=”来做结尾填充之用,不在索引表内。下表数值代表字符的索引,如同PHP的数组,数值为键,字符为值,一一对应。
因为去掉“=”后,Base64只有64个字符,那么可以用2^6表示,也就是说可以用6个bit的二进制表示;而标准的字符是8个bit,那么取二者的最小公倍数24,也就说3个标准字符可以用4个Base64字符来表示,由此也可以看出Base64编码后占用空间变大了。
以字符串“hello world”为例来说说Base64实现原理
- 分组,每3个字符为一组。([hel]、[lo ]、[wor]、[ld])
- 对照ASCII码表,分别获取字符串的ASCII编码。([104 101 108]、[108 111 32]、[119 111 114]、[108 100])
- 依次把ASCII编码转成二进制。([01101000 01100101 01101100]、[01101100 01101111 00100000]、[01110111 01101111 01110010]、[01101100 01100100])
- 把每组中8*N个bit改为6*N个bit,并且保证每组有24个bit,不足的在高位补0。([011010 000110 010101 101100]、[011011 000110 111100 100000]、[011101 110110 111101 110010]、[011011 000110 010000 000000])
- 在每组6bit前面都填两个高位0,得到4个8bit的字节,转成10进制并对照Base64编码表 ,得到对应编码后的字符。(aGVsbG8gd29ybGQ=,其中最右侧的“=”号是最后一组6个0填充的换来的)
echo base64_encode('hello world'); // aGVsbG8gd29ybGQ=
上面举得例子中的字符串须在ASCII编码范围内,中文就不行。下面来说说在UTF-8编码内中文的的实现方法,中文在UTF-8编码中占三个字节,“永”字的对应的十进制为“ 230 176 184”,对应的十六进制为“e6 b0 b8”,换算成二进制“00110010 00110001 00110001”,然后套用上面的方法可以得出Base64编码“5rC4”
echo base64_encode('永'); // 5rC4
注:下面的为中文转十进制、十六进制方法,via 网络
$string = "永";
$length = strlen($string);
$result = array();
// 十进制
for($i=0;$i<$length;$i++){
if(ord($string[$i])>127){
$result[] = ord($string[$i]).' '.ord($string[++$i]).' '.ord($string[++$i]);
}
}
print_r($result);
echo '<br>';
// 十六进制
$strings = array();
foreach($result as $v){
$dec = explode(" ",$v);
$strings[] = dechex($dec[0])." ".dechex($dec[1])." ".dechex($dec[2]);
}
print_r($strings);