LoginSignup
1

More than 3 years have passed since last update.

16進数形式の文字列をBASE64形式にして2/3に圧縮する

Last updated at Posted at 2019-06-17

16進数形式の文字列について

ハッシュ値を生成したりuniqidなどでユニークな文字列を生成した際、16進数形式で文字列が生成されます。例えば、

  • 画像アップロードされた場合に1d5c1b66fefdec9ed1fb54af60dc27d957e60ca6.jpgといったランダムな文字列を生成してファイル名が重複しないように制御
  • メール認証のために https://~~.jp/auth?key=16115b7e66a2068c1eb24f75d6ab826f8e658be4といったURLを生成

などというときに使ったりすると思います。

もう少し文字列を圧縮しませんか?

このままでも問題ありませんが、16進数からBASE64に変換すれば、安全に使用可能な文字種の範囲内で文字数を圧縮できます。
文字数が短くなればDB等の容量削減や、URL等が短くなることによる通信量削減になります。
また、一部のメーラーでメール本文内のURLが折り返されて切れてしまう可能性も少しだけ減らせます。

16進数 BASE64
3バイト (16777216通り)の情報を6文字 ($16^6 = 16777216$)で表せる 3バイトの情報を4文字 ($64^4=16777216$)で表せる

したがって、16進数と比べてBASE64だと文字数を$\frac{2}{3}$に圧縮できます。

PHPでの具体的な手順

具体的には、16進数バイナリ文字列BASE64 という二段階で変換をかけていきます。
また、BASE64の文字列の中で+, /, =はシステムとの相性が悪いケースが多いので、より安全な記号に変換します。

// BASE64に変換する
$str = '変換前16進数文字列';
$str = strtr(base64_encode(pack('H*', $str)), ['+' => '-', '/' => '_', '=' => '']);

// 16進数に戻す
$str = bin2hex(base64_decode(strtr($str, ['-' => '+', '_' => '/'])));

// ※PHP5.4未満の場合は [~~] を array(~~) に置き換えてください。

結果

c42ffbaacf25ba233cbf731d33001ed341eb6a31xC_7qs8luiM8v3MdMwAe00HrajE
40文字から27文字に減りました。

注意点

変換対象の文字列が奇数文字数だと、16進数に戻したときに末尾に余分な0が追加されてしまいます。
文字数が奇数になる可能性がある、かつ、16進数に戻せるようにする必要がある場合は、強引ですが以下のようにして回避します。

// 奇数の場合は「~」の文字を足し、戻すときに~の文字がついていれば末尾の0を取り除く
// ※「~」の文字列が許容されている前提

// BASE64に変換する
$str = (strlen($str) % 2 ? '~' : '') . strtr(base64_encode(pack('H*', $str)), ['+' => '-', '/' => '_', '=' => '']);
// 16進数に変換する
$str = substr(bin2hex(base64_decode(strtr($str, ['-' => '+', '_' => '/', '~' => '']))), 0, strpos($str, '~') === 0 ? -1 : strlen($str));

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1