1日で作るURL短縮サービス

キユー○○1日クッキング

Twitterなんかでは必需品となった、URL短縮サービス。一見難しそうですが、よく考えたらDBにハッシュとURLの対を登録しておけばOKな、なんとも実装がお手軽なサービス。

ということで、本日は、URL短縮サービスをサクっと作ってみましょう。

今回、実際にURL短縮サービス u.x0.toを作りました公開終了しました
旬が過ぎたら、何事もなかったようにサービスを抹消するつもりなので、恒久的に使おうとは思わないでね!(←
(抹消しました。。)

本日の材料

  • .htaccessが置けるサーバー
  • php環境とその知識
  • データベース環境と、SQLなどの知識

【手順1】短いドメインを用意する

最初から、一番の鬼門。短縮URLを謳うからには、ドメインも短いものがいいですよね。

どこの国のドメインかにもよりますが、意味のありげな1文字~2文字は競争率が高いです。.comや.jpなどの名の知れたドメインになると、3文字以上しか取れないのが一般的。

もし jp ドメインなら、3文字・4文字の空きを調べられる http://mijikai.jp/ が使えそうです。「短いjp」ってネーミングも良いなあ(

私の場合、レンタル鯖のサービスで運よく短いドメインを取得したので、滞りなく進みました。

【手順2】DBを整備する

ドメインが整ったら、下ごしらえ、DBを作ります。

単にURLを転送させるだけなら、テーブルは1つで事足ります。短縮URLのハッシュを入れるcolumnと、モノホンのURLを入れるcolumnの2つを用意してください。ハッシュの説明は次で。

今回は小規模なので、SQLiteを使います。もちろん大規模なサイトなら、MySQLとかのもっと良いDB環境を使うべきですけど、試しに作ってみる程度ならこれで十分。

【手順3】APIを整備する

次に、URLを短くするためのAPIを整備します。ここからはPHPの出番。

基本的には、元URLに対する短縮されたURLを生成して、そのペアをDBに格納すれば良いのですが、URL生成が意外と大きなヤマかもしれません。

ハッシュの作成方法

先ほど「ハッシュ」という言葉を使いましたが、これはいわゆる “http://u.x0.to/####” の #の部分。短縮URLを作るときは、この部分を作る必要が出てきます。

単純に乱数で文字を並べて、DBに同じハッシュの衝突が無くなるまで繰り返す処理にすると、特にデータ量が多い時、DBにかかる負担が大きくなってしまいます。。。

なので今回は、サーバーで別に「インデックス番号」を持って、短縮URLが生成されるごとに、その番号を元にハッシュを作り、インデックスを増やして次の短縮に備える、という手法で行います。

この原理はつまり、「APIにアクセスカウンタをつけて、その番号からハッシュを生み出す」ってことです。

ハッシュの規則

今回、ハッシュに使う文字は、アルファベットの大文字・小文字がそれぞれ26種類ずつと、0~9までの数字の10種類、計62種類とします。

また、過去のURLが潰されるのを防ぐために、ある番号から生み出されるハッシュは、一対一で対応するように設計します(最小完全ハッシュ関数)。

これは単純に、「進数変換」で実現できます。10進数の数字を62進数に変換すれば良いのです。

ハッシュ関数

では実際にはどのようなものになるのか、u.x0.to (公開終了)でも使っているPHPコードを用意しました。汚いソースでごめんなさい…

function create62Hash($id, $base = 0) {
	$shuffleTable = array(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61);
	$asciiTable = array(65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,48,49,50,51,52,53,54,55,56,57);
	$hashTable = array();
	$i = 0;

	do {
		$hashTable[$i] = chr($asciiTable[$shuffleTable[(int)(floor($id / pow(62, $i)) + $i) % 62]]);
		$i = count($hashTable);
	} while(($base > $i) || (pow(62, $i) <= $id));

	return implode("", $hashTable);
}

id に対象のインデックスを、baseには最低限用意する文字数を指定します。初期値である 0 なら制限はありません。

やってることは進数変換と一緒で、62進で1ケタずつ値を見て、それをchr()で対応する文字に変換しています。shuffleTable は、A, B, C... と文字が連続に見えるのを回避するためのものです。綺麗に0から61まで並んだ値ですが、この並びを使用側でシャッフルすることで、q, 2, R... などの不規則な並びにすることができます。

実際のサンプル

実際の動きをJavaScriptに移植してみました。「ハッシュ生成」でインデックスに対応するハッシュを生成します。「shuffle!」を押すと、shuffleTableをシャッフルします。

インデックスを大きな数字にして、試してみてください。

インデックス:
生成ハッシュ:
shuffleTable:

そして

前置きが長くなりました(ハッシュの実装方法書いてるサイトって少ないもん…)。あとは、このハッシュと、元々のURLの対をデータベースに追加するだけです。

で、後から気づいたんですけど、こういうことしてる割と著名なサイトは、こういうランダム性を持たせずただ単に順番にURLを定義していっているみたいです。じゃあなんでこんなところやったんだ俺は…orz

【手順4】index.phpを組む

index.phpでは、引数にハッシュを取り、そのハッシュをデータベースから探し出して、元のURLにリダイレクトする措置を取ります。

PEARにリダイレクトする関数があるほか、header()を使っても簡単にリダイレクトできますので、この辺りの実装は楽ですね。

【手順5】htaccessで仕上げる

最後の仕上げ、.htaccessです。

一番の肝は、RewriteEngineを使ったURLの変換です。"http://u.x0.to/####" というURLを、"http://u.x0.to/index.php?hash=####" の形に変換するために、RewriteEngineを活用します。

正直私は.htaccessにはそれほど理解が深くないのですが、今回の場合はたぶんこんな感じです。

RewriteEngine on
RewriteRule ^/([a-zA-Z0-9]+)$ /index.php?hash=$1

正規表現でハッシュの値が得られたら、その値を元に index.php に渡します。これで短縮URLサービスになりますよ。

できあがり

ということで、短縮URLサービスは大体こんな感じでできます。今回は特にハッシュ生成部に関して詳細に説明しました。それ以外の部分は、ネットで探して見つかる情報が多いので、今回は省いてます。

同じ仕組みで、API部を少し強化整備したのが、今回のサンプルで何度も出てきた u.x0.to です。どんな感じか程度に試せますよ。(公開終了。実際には、json/JSONPを使用した短縮用APIや、IPによる連続URL変換に対する制限、URLの後ろに".qr"と付けることでQRコードの出力などが行えました。

DBすら要らない場合

ところで、短縮URL自体に、元のアドレスの要素が入っている例というのもあります。短縮の効果は薄くなるかもしれませんが、URLから内容が推測できるというメリットもあります。

例えば、ニコニコ動画のアドレスを短縮しているnico.msなんかそうですね。元々 "http://www.nicovideo.jp/watch/sm######" なのが、"http://nico.ms/sm######" になります。

お気づきかと思いますが、やってることはただのURL変換ですから、DBどころかPHPすら書く必要もなくて、.htaccessで変換して終わりです。ドメインさえ取れればサービスになる超お手軽さ。

ユーザーが作ったこのサービス、1時間でドワンゴに買収されました。どんなシンプルな仕組みでも、有用性があれば日の目を見るということですね。

開発をもっと身近に

URL短縮サービスの作り方を説明したところで、「そんなん想像つくわ!」っていうWeb開発者からの罵声が飛んできそうですが…

私は情報系の大学に籍を置いていますが、私の周りには、目的があっても、『いざ開発しようとすると、何処から手をつけて良いのか分からない!』という人が(意外と)多いです。

今回の例は、実装の仕組みどうこうよりも、どのようなステップを踏んで考えれば良いか、開発に不慣れな方に理解していただき、Web開発を身近にして欲しいなぁ、という狙いがあります。URL短縮サービスはそのステップも少なく、かつきちんとWebサービスになるものなので、良い教材かと。

完成してから気づいたけど

開発どうこうでなくて、単に「俺はURL短縮サービス立ち上げて目立ちたいんだ」ってのが目的なら、わざわざこんな面倒なことしなくても、オープンソースのソフトウェアがわんさかありました…。

1日どころか1時間でできちゃう。英語ですが頑張って。

9 OpenSource URL shortening apps to make your own services
http://www.2expertsdesign.com/php/free-url-shortening-scripts

OSS、偉大です。