PHPで短縮URL用の文字列を作成する方法の紹介です。
Twitter や チャットサービス などで リンクを貼る時、URL文字数の長さの問題から、短縮URLサービスを利用することは 珍しいことではありません。Googleのサービスでは ドメインが ' goo.gl
' から始まる、 ' Google URL Shortener
'が広く知られています。
短縮URL を作成するには、' Google API
' を使うか、自前で作成する時は ランダムな文字列を生成することで作成することが可能です。
ですが、 ' Google URL Shortener は ' 1 ユーザー 100万リクエストまで / day
' の制約があったり、自前で作成する時は URLセーフな文字列を選択することから始まり、永続的に使用する場合、ユニークな文字列を生成したか確認する必要があります。
そんな短縮URLですが、安全に短く、そして簡単で便利に短縮URLを作成できる javascript用のスニペットが gist 上に公開されてあったので、そのコードを PHPで書き直してみました。
' http://co.bswns.net/article/256
' : 記事用URL
↓↓
' http://co.bswns.net/s/5d
' : ソーシャルシェア用URL ( リダイレクト専用 )
Base58を使って、上記のような URL圧縮用の エンコード & デコードが できる文字列を生成する。
* Base58 : Base64の文字列から' 0
', ' O
', ' I
', ' l
', ' +
', ' /
' を取り除いた文字セット
MySQLや Postgresql などを代表する RDBMSで ブログやニュースサイト、何かの投稿を管理する場合、indexの1つとして、数値型 (integer) + auto-increment で ' id
' を付けている設計が多いと思います。また、カラム id は基本 ' unique
' オプションを付けるので重複するようなことはありません。
っということで、データーベースのテーブルの ' id (int型の数値) ' を軸として 10進数を58進数のに変換するコードが下記になります。
/**
* このコードは https://gist.github.com/inflammable/2929362に、
* 投稿されている javascriptコードを PHPで書き直しました。
*/
class ShortURL
{
public function __construct()
{
//base58に準拠する場合
$this->baseString = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
// 文字列の並びを変えると発行される文字列も変わります
// $this->baseString = 'hwqAQ4JfZTLvU79xX5YEdrHRMe3NjPyuioGKmpFbDkcSntBzgVW621a8Cs';
// 圧縮URLとして限定するなら 'O', 'l', 'I', '-', '_'を追加した 計63文字でも問題ありません
// $this->baseString = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNPOQRSTUVWXYZ-_";
$this->baseLength = strlen($this->baseString);
}
/**
* @return String
*/
public function encode($num)
{
if (!is_numeric($num)) {
throw new Exception('TypeError : $num of value must be integer.');
}
$encode = "";
while ($num) {
$remainder = $num % $this->baseLength;
$num = floor($num / $this->baseLength);
$encode .= $this->baseString[$remainder];
}
return strrev($encode);
}
/**
* @return Integer
*/
public function decode($str)
{
if (!is_string($str)) {
throw new Exception('not string');
}
$decode = 0;
while ($str) {
$position = strrpos($this->baseString, $str[0]);
if ($position < 0) {
throw new Exception('"decode" can\'t find "' + $str[0] + '" in the alphabet: "' + $this->baseString + '"');
}
$power = strlen($str) - 1;
$decode += $position * pow($this->baseLength, $power);
$str = substr($str, 1);
}
return $decode;
}
}
上で作成したクラスの ' encode(int)
' メソッド 利用して ' 4294967295
' をエンコードすると58進数で表記された文字列が返ってきます。
$mysqlMaxValue = 4294967295; // * MySQLのint型の最大値 ( unsigned ) 10桁
echo (new ShortURL())->encode($mysqlMaxValue); // 7xwQ9g 7桁
上記の ' encode
' メソッドで出来た文字列( 58進数 ) を ' decode( string )
' メソッドで復号化すると数値で返ってきます。ソーシャルシェアで使う専用の圧縮されたURLを、 ID にリダイレクトさせれば ショートURLの機能も比較的簡単に実装することができそうです。
// 4294967295をエンコードして出来た58進数
$decode = '7xwQ9g';
echo (new ShortURL())->decode($encoded); // 4294967295
また、大きい数字を扱う時も問題なく encode, decodeが可能です。
$infinit = 99999999999999999; // 9999兆 ... 99
$encoded = (new ShortURL())->encode($infinit); // esSbqW65EK
echo (new ShortURL())->decode($encoded) . "\n"; // 99999999999999999
以上が PHP で 圧縮URL用の文字列を作成する紹介でした。Base58を元にした技術は、bitcoin のアドレスや flickrの短縮URLで実際に使用されているようです。
下記のようなタイトルをURLのパラメーターに渡している時には特に重宝できそうです。
# タイトルをURLに渡した例
http://co.bsnws.net/a/phpで短縮URL用の文字列を作成する # id = 256を参照
# 実際には下のように認識される
http://co.bsnws.net/a/php%e3%81%a7%e7%9f%ad%e7%b8%aeURL%e7%94%a8%e3%81%ae%e6%96%87%e5%ad%97%e5%88%97%e3%82%92%e4%bd%9c%e6%88%90%e3%81%99%e3%82%8b
## 圧縮されたURL
http://co.bswns.net/s/5d
また、コード自体はシンプルなので、他の言語用に書き直すことも難しくありません。
Gist : Pythonで書き直したURL圧縮用のコード
GitHubGist : inflammable/base58.js