ホームページ >バックエンド開発 >PHPチュートリアル >Base64エンコード原理の分析とPHP実装
Base64 は、64 個の印刷可能な文字に基づくバイナリ データの表現方法です。 2 の 6 乗は 64 に等しいため、6 ごとが単位となり、特定の印刷可能な文字に対応します。
3 ビットには 24 ビットがあり、4 つの Base64 ユニットに対応します。つまり、3 バイトを 4 つの印刷可能文字で表す必要があります。電子メールの転送エンコードとして使用できます。
Base64 の印刷可能な文字には、文字 A ~ Z、a ~ z、数字 0 ~ 9 が含まれるため、合計 62 文字になります。他の 2 つの印刷可能な記号はシステムによって異なります。
たとえば、mime (多目的メール拡張機能) では、Base64 で使用される 64 個の印刷可能な文字
A-Za-z: 大文字と小文字がそれぞれ 26 文字
0- 9: 数字を 10 個追加します
+: プラス記号
/: スラッシュ
合計 64 文字、等号「=」は接尾語として使用されます
対応する変換関係は
0-63: A-Za-z0-9+/
変換時、3 バイトのデータが24 ビット バッファに次々と入力され、最初に来たバイトが上位ビットを占めます。データが 3 バイト未満の場合、バッファ内の残りのビットは 0 で埋められます。次に、毎回 6 ビット (26=64 であるため) を取り出し、値に従って ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ の文字をエンコードされた出力として選択します。すべての入力データが変換されるまで続行します。
元のデータ長が 3 の整数倍ではない場合、入力データが最後に 1 つ残っている場合は、エンコード結果の後に「=」を 2 つ追加します。 、エンコード結果「=」の後に 1 を追加します。データが残っていない場合は、データ復元の正確性を確保するため、何も追加しません。
分析例:
エンコーディング: "Lailaiji"
ASCII テーブルを検索して対応する関係を見つけます
L:0x4c | a:0x61 | i:0x69 | l:0x6C | j:0x6A
つまりバイナリに変換されます: 0100 1100 , 0110 0001 , 0110 1001 , 0110 1001 , 0110 101 0 、0110 1001
th ステップ 1: まず 3 バイトのデータを取得します: 0100 1100、0110 0001、0110 1001、次にこれらの 3 バイトから 6 ビット (010011) を取り出し、最上位ビットに 2 ビット 00 を追加して 1 バイトにします、つまり 0001 0011、残りの 18 ビットもこのように循環し、最終的にこれら 3 バイトは 4 バイトに拡張されます: 0001 0011, 0000 0110, 0000 0101, 0010 1001
2 番目のステップ、残りからバイト シーケンスの最初のステップを繰り返し、3 バイト未満の場合は 3 番目のステップに進みます
この時点で、残りのバイトは 0110 1010、0110 1001 で、3 バイト未満です。下位ビットから 0 まで加算する必要があり、0110 1010、0110 1001、0000 0000 になります。最初の手順を繰り返して、0001 1010、0010 0110、0010 0100、0000 0000、
後続の演算の後、設定されたビット シーケンスを取得します:
0011, 0000 0110, 0000 0101, 0010 1001
0001 1011, 0000 0110, 0000 0101, 0010
0001 1010,0010 0110, 0010 0100, 0000 0000
10 進数に変換: 19, 6, 5, 41, 27, 6, 5, 41, 26, 38, 36, 0
対応する文字: T、G、F、p、b、G、F、p、a、m、k、A
特に注意が必要なのは、最後のバイトです。 0000 0000 は 0x00 で、テーブルを参照すると A です。最後の 8 ビットは補足的なため、A
ではなく = 記号に変換する必要があります。 したがって、最終結果は次のようになります: TGFpbGFpamk =
PHP 実装:
<?php$input = '赖来基';$obj = new MyBase64();$output = $obj->encode($input);echo "Encode:",$output.PHP_EOL;$output = $obj->decode($output);echo "Decode:",$output.PHP_EOL;class MyBase64{ private $_table = array(); private $_revtable = array(); public function __construct(){ $this->_initTable(); } public function decode($string) { $orign_len = strlen($string); $j = 0; $ret = null; for($i=0; $i<$orign_len; $i+=4) { $chr1 = $this->getRevChr($string[$i]); $chr2 = $this->getRevChr($string[$i+1]); $chr3 = $this->getRevChr($string[$i+2]); $chr4 = $this->getRevChr($string[$i+3]); $_chr1 = $chr1<<2 | ($chr2&0x3F) >>4; $_chr2 = ($chr2&0x0F)<<4 | ($chr3&0xFC) >>2; $_chr3 = ($chr3&0x03)<<6 | $chr4; $ret .= chr($_chr1); $ret .= chr($_chr2); $ret .= chr($_chr3); } $ret = rtrim($ret); return $ret; } private function getRevChr($chr) { if(isset($this->_revtable[$chr])) { return $this->_revtable[$chr]; }else{ return 0; } } public function _decode($string) { $orign_len = strlen($string); $de = null; $kv = array_flip($this->_table); $b = null; for($i = 0 ;$i < $orign_len;$i++) { $chr = $string[$i]; if($chr != '='){ $c = $kv[$chr]; }else{ $c = chr(0); } printf("%x",$c); $b[] = pack('C',$c); echo PHP_EOL; } for($i = 0 ;$i < count($b);$i+=3){ $ch1 = ($b[$i]<<2) | ($b[$i+1]>>4); $ch2 = ($b[$i+1]<<4) | ($b[$i+2]>>2); $ch3 = ($b[$i+2]<<6) | ($b[$i+3]); printf('%08b,%08b,%08b',$ch1,$ch2,$ch3); echo PHP_EOL; printf('%08b,%08b',($b[$i]<<2) , ($b[$i+1]>>4)); echo PHP_EOL; } } public function encode($string) { $orign_len = strlen($string); $len = intval(ceil($orign_len/3)*3); $bin = pack('a'.$len,$string); $gen = null; for($i=0; $i<$len; $i+=3) { $ch1 = ord($bin[$i]) >> 2; $ch2 = ((ord($bin[$i]) & 0x03) << 4) | (ord($bin[$i+1]) >> 4); $ch3 = ((ord($bin[$i+1]) & 0x0F) << 2) | ((ord($bin[$i+2]) & 0xC0) >> 6); $ch4 = ord($bin[$i+2]) & 0x3F; $gen.= $this->_table[$ch1]; $gen.= $this->_table[$ch2]; $gen.= $this->_table[$ch3]; $gen.= $this->_table[$ch4]; } if($orign_len-$len){ $gen = substr($gen,0, -abs($orign_len-$len)); for($i=0;$i<$len-$orign_len;$i++) { $gen .= '='; } } return $gen; } private function _initTable() { $tbl = array(); for($i=ord('A');$i<=ord('Z');$i++) { $tbl[] = chr($i); } for($i=ord('a');$i<=ord('z');$i++) { $tbl[] = chr($i); } for($i=ord('0');$i<=ord('9');$i++) { $tbl[] = chr($i); } $tbl[] = '+'; $tbl[] = '/'; $reverse = array_flip($tbl); $this->_table = $tbl; $this->_revtable = $reverse; }}