公司業務中調用接口須要經過網關轉換,網關內的一些規則致使*在傳遞的過程當中存在問題,因此決定使用base64進行編碼處理。php
在使用過程當中發現網關對'='也有處理,致使個人傳參到接口方會丟失掉最後的等號,可是通過解碼後的居然是正確的!正則表達式
因而發現這麼長的時間,常用base64,可是對這個編碼的原理並不理解,因此就有了這篇學習記錄。bash
1.常見的編碼:網絡
2.計算機本質都是二進制,最小的數據單位是比特bit,一個字節有8個bit。學習
3.base64做用:計算機中任何數據都是按ascii碼存儲的,而ascii碼的128~255之間的值是不可見字符。而在網絡上交換數據時,好比說從A地傳到B地,每每要通過多個路由設備,因爲不一樣的設備對字符的處理方式有一些不一樣,這樣那些不可見字符就有可能被處理錯誤,這是不利於傳輸的。因此就先把數據先作一個Base64編碼,通通變成可見字符,下降錯誤率。ui
是基於A-Z、a-z、0-9以及'+' 和'/'共64個字符的編碼方式,由於2的6次方等於64,因此說只須要6個比特便可表示一個base64的字符。編碼
編碼表:'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
複製代碼
核心原理是將二進制數據進行分組,以6位一組進行分組,並在每組前面都填兩個高位 0,而後將 8 bit 的字節轉換成十進制,對照 BASE64 編碼表 (上表),獲得對應編碼後的字符。url
一個字節是8bit,一個base64的字符6bit,24是最小公倍數,因此3個字節能夠完整轉化爲4個base64字符;spa
可是咱們沒法控制須要編碼的數據正好是3的倍數,因此要進行補零---在不足3的倍數的字符串末尾用0x00進行填充;code
由於base64編碼中的下標0對應的字符是'A',而末尾填充上的0x00在分組補零後一樣是下標0x00,這樣就沒法分辨出究竟是末尾填充的0x00仍是二進制數據中的0x00。
因此引進了等號,這就是'='字符不在Base64字符集中,可是也出如今Base64編碼的緣由了。
以對6666P進行base64編碼的步驟說明
每一個字符轉化爲8bit:
6----->00110110
6----->00110110
6----->00110110
6----->00110110
P----->01010000
補位----->00000000
總體拼接結果:
001101100011011000110110001101100101000000000000
以6bit一組進行分割:
001101 100011 011000 110110 001101 100101 000000 000000
轉化爲base64編碼腳標:
13 35 24 54 13 37 0 0
獲取對應的base64編碼:
N j Y 2 N l A A
獲得結果:string(8) "NjY2NlA="
複製代碼
由編碼過程可知,編碼的結果的長度必定是4的倍數,因此當解碼的長度不等於4的倍數時,須要用等號進行補位。
這也就是去掉末尾的等號後進行解碼得出的原文不會出錯的緣由了!
瞭解過編碼過程後逆向回去即爲解碼過程,在此就再也不詳細敘述了。
可是標準的base64並不能知足全部場景的須要,好比URL編碼器會把中的「/」和「+」字符變爲形如「%XX」的形式,因此也就出現了實現思路一致的編碼變種:
(1)適應url的變種改進:不在末尾填充’=’號,並將「+」和「/」分別改爲了「-」和「_」
(2)適應正則表達式的變種:將「+」和「/」改爲了「!」和「-」
<?php
$a = "6666P";
$decbinStr= '';
//計算補位
$end = (3 - strlen($a)%3)%3;
for($i=0;$i<strlen($a);$i++){
//每一個字符轉化爲8bit
$decbin = str_pad(decbin(ord($a[$i])),8,"0",STR_PAD_LEFT);
$decbinStr .= $decbin ;
}
//增長補位
$decbinStr = $decbinStr. str_pad("",$end*8,"0");
//以6bit一組進行分割
$arr = str_split($decbinStr,6);
//轉化成對應的base64編碼
$result = implode("", array_map("getBase64Str",$arr));
//末尾補位的數據處理
for($j=0;$j<$end;$j++){
if($result[strlen($result)-1-$j] == 'A'){
$result[strlen($result)-1-$j] = "=";
}
}
//驗證下跟自帶的base64_encode結果是否一致
var_dump($result);
var_dump(base64_encode($a));
exit();
function getBase64Str($sixStr){
$number = bindec($sixStr);
$baseHash = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return $baseHash[$number];
}
複製代碼
固然也可使用位運算等方式進行實現,以上代碼僅表明我的的思路。