だるろぐ

だるいぶろぐです

画像をDBに保存してmod_rewriteを利用していい感じに扱う

http://neta.ywcafe.net/000774.html
これをやった。ここ見れば十分。

ソース一式

http://github.com/hirafoo/image_db
試す場合は

  • DBIx::Class とかを入れる。他適宜入れる
  • mysql用意する
  • image_db ってデータベース作る
  • config/create.sql を使ってテーブル作る
  • config/httpd/image_db_vhost.conf を自分の環境に合わせて編集してapache起動する
./script/file2db.pl images/hirafoo_normal.jpg
./script/file2db.pl images/hirafoo_hanten.jpg
./script/file2db.pl images/hirafoo_color.jpg
  • アクセスする

で。アクセスしたりファイル消したりログを見たりすれば、ファイル生成、mod_rewriteが動く様子が分かるかと。

本文

何をやっているのかというと

  • 画像もDBに保存したい
  • mysqlではblob型などを使えばバイナリがそのまま保存できる
  • imgタグのsrc要素にスクリプトを指定し、content-typeはimage/jpgとかにしてbodyで画像を返せばいい
  • スクリプトはDBに問い合わせを行い、格納した画像をデコードして返せばいい
  • しかし毎回そんな事してたら死ねる
  • そこでapachemod_rewriteを活用し、
    1. 画像があれば画像をそのまま返す
    2. 画像が無かった場合のみ、スクリプトに画像を生成させ、裏でDBからHDDに画像を保存しつつ、表では画像をbodyに返してやる
    3. 次回以降のアクセスでは、画像が既にあるので、スクリプトを解さず画像を返せる

という。面白い。

ハマりどころ

RewriteCondによるファイル存在チェックで、バーチャルホストのディレクティブの中では !-f が効かない。知らなかった。
なので DOCUMENT_ROOT をくっつけてフルパスでチェックする。

    RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f

参考:mod_rewriteの質問です。「RewriteCond %{REQUEST_FILENAME} !-f… - 人力検索はてな

どんな時に使うの

遊んでるだけなので何とも言えないのだけど。
例えば。

  • svn co htdocs/images したら死にたくなった
  • ls htdocs/images したらシェルが応答しなくなった

そんな環境で使うと嬉しくなるかもしれません。
小さいファイルが膨大にあるよりは、でかいファイルが1個あるだけの方が好きなので。
ブランチ切る度に使いもしないファイルがどばっと生まれるとか苦痛です。
普段はlibやviewだけcoして既存のと差し替えて使ってたりする。


あと今回は apache -> DB だったけど、間にsquid挟むとかで遊べる気もする。

小細工どころ

__PACKAGE__->resultset_attributes({
    alias => 'image',
    from  => [{image => 'image'}],
});
  • いちいちORMと同名メソッド作ってまでモデルクラス作るのが面倒です
package ImageDB::ResultSet::Image;
use base qw/DBIx::Class::ResultSet ImageDB::Model::Image/;
  • configファイルをフルパスで書くのも、デプロイ場所が変わるたびにファイルパス書き換えるのも嫌です
    my $dist = $INC{"ImageDB/Utils.pm"};
    my $file = dir($dist)->parent->parent->parent->subdir('config')->file('database.yaml');
    my $config = LoadFile($file);

デモ

http://imagedb.hirafoo.net/
mozilla系だと、キャッシュ消してもイマイチ様子が伝わらないようだ。
IEchromeだといい感じに見える。
負荷の様子見てそのうち落とします。


終わり。
そういえば前職でこれやろうとしたら残念な事情によりやらなかった記憶が。