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 ', ' + ', ' / ' を取り除いた文字セット

idをベースに短縮URLの文字列を作成する 

 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


Summary

 以上が 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

 

この記事のカテゴリ

プログラミング

この記事のタグ

PHP , 効率化

Socialシェアボタン

スポンサーリンク