0%

Base64编码原理解析

一、什么是Base64编码?

所谓Base64,就是说选出64个字符—-小写字母a-z、大写字母A-Z、数字0-9、符号”+”、”/“(再加上作为垫字的”=”,实际上是65个字符)—-作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。

具体来说,转换方式可以分为四步:
第一步,将每三个字节作为一组,一共是24个二进制位。
第二步,将这24个二进制位分为四组,每个组有6个二进制位。
第三步,在每组前面加两个0,扩展成32个二进制位,即四个字节。
第四步,根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0 A  17 R   34 i   51 z
  1 B  18 S   35 j   52 0
  2 C  19 T   36 k   53 1
  3 D  20 U   37 l   54 2
  4 E  21 V   38 m   55 3
  5 F  22 W   39 n   56 4
  6 G  23 X   40 o   57 5
  7 H  24 Y   41 p   58 6
  8 I  25 Z   42 q   59 7
  9 J  26 a   43 r   60 8
  10 K  27 b   44 s   61 9
  11 L  28 c   45 t   62 +
  12 M  29 d   46 u   63 /
  13 N  30 e   47 v
  14 O  31 f   48 w   
  15 P  32 g   49 x
  16 Q  33 h   50 y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getip() {
static $ip = '';
$ip = $_SERVER['REMOTE_ADDR'];
if(isset($_SERVER['HTTP_CDN_SRC_IP'])) {
$ip = $_SERVER['HTTP_CDN_SRC_IP'];
} elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach ($matches[0] AS $xip) {
if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
}
return $ip;
}

Base64编码对照表

二、编码过程解析

1、举个栗子
假如,我们要对字符串yangxinmin进行Base64编码。
1、先将yangxinmin按3个字节为一组地分开,如yangxinmin
2、为了省事,这里我们不全部转换,就以yan为例
3、将yan 3个字母的ASCII码查出来,分别是:121、97、110
4、然后将121、97、110这3个数字转换成二进制,分别是:01111001、01100001、01101110
5、将上一步3个二进制串拼装到一串:011110010110000101101110
6、然后将011110010110000101101110,从左往右数,6位为一组分开,如:011110、010110、000101、101110
7、然后将这4组二进制转换成十进制数,分别是:30、22、5、46
8、再将上一步的4个数字,对照上面的Base64编码对照表,得到结果为:eWFu,这就是我们需要的Base64编码。

前面我们说到是将字符串3个字节一组分开,但如果不足3个字节怎么办呢?比如,yay

2、两个字节的情况处理
ya为例:
1、接着上面栗子第5步,将ya的二进制串拼装到一串:0111100101100001
2、然后将0111100101100001,从左往右数,6位为一组分开,到最后一组时,显示位数不够,于是在最后一组的前面和后面分别加2个0,就变成了:011110、010110、$\color{red}{00000100}$
3、然后将这3组二进制转换成十进制数,分别是:30、22、4
4、再将上一步的3个数字,对照上面的Base64编码对照表,得到结果为:eWE,$\color{red}{这里还有一个规定:少于3个字节一组的字符串,少几个就要补几个=号}$,于是最终结果为:$\color{red}{eWE=}$
这也解释了我们平常看到了Base64编码中时常出现多个=号的原因。

3、一个字节的情况处理
同两个字节类似处理,只是结尾多了一个 =

4、对汉字的处理
汉字本身可以有多种编码,比如gb2312、utf-8、gbk等等,每一种编码的Base64对应值都不一样。下面的例子以utf-8为例。
首先,“严” 字的utf-8编码为E4B8A5(如果不知道怎么查编码,点击这里,输入汉字先进行url编码,再将%去除转换成大写,就是我们需要的uft-8编码),写成二进制就是三字节的”11100100 10111000 10100101”。将这个24位的二进制字符串,按照第2节中的规则,转换成四组一共32位的二进制值”00111001 00001011 00100010 00100101”,相应的十进制数为57、11、34、37,它们对应的Base64值就为5、L、i、l。
所以,汉字”严”(utf-8编码)的Base64值就是5Lil。

三、总结

1、Base64编码,是一种编码算法,不是加密算法,主要作用是为了将二进制数据转换成文本格式。
2、Base64编码的常见的应用场景有两种:一是将图片转换成Base64编码输出到网页;二是做数字签名时,将二进制摘要数据(如PHP中hash_hmac(‘sha256’, …)函数)转换成Base64文本,见自己的另一篇文章JWT Token原理解析第三节内容。
3、Base64编码的缺点是传输效率会降低,因为它把原始数据的长度增加了1/3。
因为标准的Base64编码会出现+、/和=,所以不适合把Base64编码后的字符串放到URL中。一种针对URL的Base64编码可以在URL中使用的Base64编码,它仅仅是把+变成-,/变成_,见自己的另一篇文章JWT Token原理解析第三节内容。

参考:http://www.ruanyifeng.com/blog/2008/06/base64.html Base64编码原理