8月31日にゆうびんホームページの郵便番号データが更新されました。
それに伴い、MySQL用郵便番号データも更新しました。
http://firegoby.jp/trac/changeset/10
8月31日にゆうびんホームページの郵便番号データが更新されました。
それに伴い、MySQL用郵便番号データも更新しました。
http://firegoby.jp/trac/changeset/10
CMSなどで画像をアップロードする機能を実装する際にその画像をDBに保存すると、サーバーを冗長化する際やサムネールを作成する機能を実装する際にいろいろと便利になるので、そのやり方をご紹介します。
上記のデメリットのうち付加が増大する点については、mod_rewriteを使用することで解決できます。
以下のようなテーブルを作成する。
画像のアップロードプログラムであらかじめ、mime_typeや画像の高さや幅を取得しておいてDBに保存しておくと、出力時になにかと都合がいいことが多いです。
画像のコンテンツは、m_contentに保存します。
base64でフォーマットするというような例も多いようですが、ここでは生で保存します。
CREATE TABLE `tbl_bin` ( `m_id` varchar(32) NOT NULL, `m_content` longblob NOT NULL, `mime_type` varchar(100) NOT NULL, `width` smallint(5) unsigned NOT NULL, `height` smallint(5) unsigned NOT NULL, `m_modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, PRIMARY KEY (`m_id`), KEY `m_modified` (`m_modified`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
以下はあくまでもサンプルです。
画像ファイルのコンテンツは以下のような感じでSQL文に挿入します。
$image = mysql_real_escpa_string(file_get_contents( $_FILE['image']['tmp_name'] ));
画像の幅や高さmime-typeは、getimagesize()で取得してください。
m_idには拡張子つきのファイル名を保存するのがベターです。
重複を避けるためにユーザーがつけたファイル名はさけて、自動的にファイル名を生成するようにしたほうがいいとおもいます。
以下の例では、プログラム名はmedia.phpで、キャッシュを保存するディレクトリ名はmedia/であることを前提にしています。
これらを変更したい場合は、必要に応じて読み替えてください。
もっとも簡単な例では、以下のようなプログラムで画像の出力が可能です。
(あらかじめDBに接続する構文を記述してください。)
// URLからファイル名の部分を取得
$url= parse_url($_SERVER['REQUEST_URI']);
$id = basename($url['path']);
// DBから画像データを取得
$sql = "select m_content, mime_type from tbl_bin
where m_id='".mysql_real_escape_string($id)."' limit 0,1";
$result = mysql_query($sql);
if (mysql_num_rows($result)) {
$data = mysql_fetch_assoc($result);
// キャッシュを保存
$fp = fopen(dirname(__FILE__).'/media/'.$id, 'w');
fwrite($fp, $data['m_content']);
fclose($fp);
// 画像を出力
header('Content-type: '.$data['mime_type'].';');
print $data['m_content'];
}else{
header("HTTP/1.0 404 Not Found");
print 'file not found';
}
上述のPHPスクリプトで、アクセスがあった際に画像を保存するようにしたので、次はmod_rewriteでキャッシュがあればそのキャッシュを使用するようにする。
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule media/ media.php [L]
実際に画像(media.php)にアクセスしてみてキャッシュができるかどうかを確認したあと、media.phpをあえてリネームするなどして、同じURLで画像が再び表示されればOK。
以降は画像にアクセスがあってもDBへ接続は発生しません。
画像が増えすぎてディスク容量を圧迫するようなら、Cronで定期的に古い画像を削除するなどの処理を行うことで緩和されます。
密かに、Tracのほうでは以前から公開していたのですが、MySQL用の郵便番号データを配布します。
実は、このデータは前から作ってあったのですが、Cronで定期的にゆうびんホームページの郵便番号データダウンロードをチェックして更新されたらSVNリポジトリにコミットするというスクリプトを設置して、本日見事にデータの更新が検出できたので、ここでご紹介させていただくことにしました。
MySQL用郵便番号データのダウンロード(更新日はこちらで確認してください。)
このパッケージ内には、郵便番号データのMySQL用SQLファイル及びテーブルのスキーマが同梱されています。
データはCronで深夜に毎日チェックしています。
配布用のzipファイル内に含まれているデータは実際にMySQLに流し込んでテスト済みですが、SVNリポジトリにあるデータはそうとは限らないのでお気を付けください。
SQLファイル内には郵便番号データすべてが含まれています。
次回以降のアップデートで流し込む際には、事前にデータの削除を行わないと重複して挿入されてしまいますのでご注意願います。
本データを利用したことによる如何なる損害にも補償しかねますので、あらかじめご了承ください。
このデータに関しましては、著作権を主張しません。
ご自由に再配布していただいて結構です。
ですが、ご褒美を頂けるなら、とても感謝します。
ここで書いてあることだけでは十分とは言えませんが、これだけでも心当たりがあるシステムがやまほどあるはずです。
MySQLへクエリーを発行する際に文字エンコーディングを指定する方法として、以下のような方法がよく紹介されていますが、これは間違いです。
// 誤った方法
mysql_query("set names utf8");
以下のようにmysql_set_charset()関数を使用しなければ、mysql_real_escape_string()関数が誤った文字エンコーディングを前提にしてエスケープしようとしてしまいます。
// 正しい方法
mysql_set_charset("utf8");
詳しい説明は以下のサイトなどを参考にどうぞ。
addslashes()というよく似た関数もありますが、それでは不完全です。
また、mysql_set_charset()と必ずセットで使用するべきです。
これは、MySQLを使っているかどうかに限らず、常に心がけるべきです。
header("Content-type: text/html; charset=UTF-8");
header()関数ではなく、php.iniやhttpd.confでもデフォルトのエンコーディングを指定できますので、可能な場合はそちらも使用した方がベターです。
可能であれば、mb_convert_encoding()に指定する変換前のエンコーディングはautoにしないで明示的に指定しましょう。
header()関数やphp.iniなどで出力エンコーディングを明示的にクライアントに知らせてあげれば、まっとうなブラウザなら期待通りのエンコーディングで返してくれます。
また、以下のような記述を入れて不正な文字エンコーディングを検出したらその後の処理を中断するべきです。
function check_encoding($key, $value) {
if (!mb_check_encoding($value, 'UTF-8')) {
die('不正な文字コード');
}
}
array_walk_recursive($array, 'check_encoding');
これは論外。
某有名SNSのPHP関連のコミュニティで、SJISを使うという回答がかなり多くてびびりました。
PHPのマニュアルにも以下のような記載があります。
注意: SJIS, BIG5, CP936, CP949, GB18030 は、読者がパーサ/コンパイラ、 文字エンコーディングと文字エンコーディングの問題点について精通していない限り 内部エンコーディングとして使用するべきではありません。
検証していませんが、mb_real_escape_string()も期待通り動くかどうか怪しいですし、EUC-JPやUTF-8を使用すれば、そんな検証をする必要もありません。
てっとりばやく使えるPHPだからこそマニュアルには従うべきですよね。
できれば、プリペアードSQLを使うのがベターなのですが。。。
まだ怪しいかんじなのでMySQLに関しては使ってないです。
テーマファイルを変えてみました。