PHPでwebアプリを作成していると、動的に生成したファイルをダウンロードさせたい場合があります。
ありがちなパターンとしては、DBの内容をcsv形式でダウンロードさせる等です。
このとき、同じデータを複数のフォーマットで返したい場合があります。
例えば、注文No12345のデータを提供したいが、下記のように拡張子で書式が決まるといった状況です。
http://example.com/order/12345.xml http://example.com/order/12345.yaml http://example.com/order/12345.csv |
この際、*.xml、*.yaml、*.csvの各フォーマット毎で異なるPGを用意すると、管理が煩雑です。
今回の記事では、PHPで1本のプログラムで、複数フォーマットを取り扱う場合のパターンを説明します。
例はPHPですがperlやruby等、他の言語でも考え方は同じです。
特定フォルダ以下の全URLを、単一のプログラムに応答させる
まずはapacheで、所定フォルダ以下に対するあらゆるURLに対して、単一のプログラムが応答するように設定します。このような構成は一般にフロントコントローラと呼ばれます。※フロントコントローラの説明については、Martin FowlerのPoEAAが詳しいです。
フロントコントローラの構成はwebサーバ側の助けが要るので、apacheでの設定が必要です。
具体的には、対象のフォルダに、以下の内容で.htaccessファイルを作成します。(.htaccessファイルは最初の例だとDOCUMENT_ROOT/orderフォルダの下に置きます)
RewriteEngine on RewriteRule .* index.php |
ちなみに余談ですが、Windowsの場合はエクスプローラから.htaccessと言う名前のファイルを作ろうとすると、以下のように、”ファイル名を入力して下さい”というエラーが表示されます。

この場合は、一旦a.htaccess等のファイル名で作成した後、コマンドプロンプトよりrenameコマンドで変更するとピリオドから始まるファイルを作成できます。

次に、肝心のindex.phpを作成します。
とりあえずテストなので、適当な文字を返すだけのPGにしておきます。
<?php print "test"; |
これで、対象フォルダ(http://example.com/order/ 以下)の全URLに対して、order/index.phpが応答するようになりました。
以下のフォルダにテスト用のファイルを置いたので確認ができます。
http://nanoappli.com/dev/201101_frontController/
試しに以下のようなURLでアクセスしてみると、”/dev/201101_frontController/”以下に対しては、何であってもindex.phpが応答していることが分かります。
http://nanoappli.com/dev/201101_frontController/foo
http://nanoappli.com/dev/201101_frontController/foo.xml
http://nanoappli.com/dev/201101_frontController/foo.csv
http://nanoappli.com/dev/201101_frontController/foo/bar.txt
これで、フロントコントローラの設定が完了しました。
アクセスされたURLをPHP側で認識する
次にindex.php側のプログラムを少し改良し、自分がどんなURLでアクセスされてきたを認識できるようにします。これはphp側のグローバル変数、$_SERVER[“REQUEST_URI”]を利用することで、URLが判別可能です。
※ちなみに、URL判別からは話が外れますが、HTTP_HOSTでサーバ名や、PHP_SELFで自身のプログラム名の取得も可能です。
動作確認のため、/dev/201101_frontController2/index.phpに以下のプログラムを作成しました。
アクセスされたURL:<br /> <?php echo htmlspecialchars( $_SERVER["REQUEST_URI"] ); ?> <br /><br /> アクセスされたURL(ホスト名付):<br /> <?php echo htmlspecialchars( "http://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] ); ?> <br /><br /> 実際に応答したPG名:<br /> <?php echo htmlspecialchars( $_SERVER['PHP_SELF'] ); ?> <br /><br /> |
例えば、http://nanoappli.com/dev/201101_frontController2/foo/bar.csvへアクセスすると、以下のように$_SERVER[“REQUEST_URI”]の値を取得できます。

これで、PHP側にて自身が何のURLでコールされたかを自覚出来るようになりました。
URLの拡張子に応じて処理を分岐する
ここまでくれば、後はPHPの文字列処理だけになります。
例えば、最初の例(http://example.com/order/12345.xml)で、注文Noが5桁の数字という制限があったとした場合、以下の処理で伝票番号と拡張子を取得できます。
アクセスされたURL:
<?php echo $_SERVER["REQUEST_URI"] ?> <br /><br /> function checkUrl() { // 数字5桁 + xmlまたはcsvで終わるURLのみOKとみなす // $pattern = "/\/dev\/201101_frontController3\/([0-9]{5})\.(xml|csv)$/"; $pattern = "/\/order\/([0-9]{5})\.(xml|csv)$/"; $matchResult = preg_match( $pattern, $_SERVER["REQUEST_URI"], $matches ); if ( $matchResult <= 0 ) { print "URLの形式が不正です"; return; } print "伝票No:" . $matches[1] . "<br />"; print "フォーマット:" . $matches[2] . "<br />"; } checkUrl(); ?> |
上記のPGは、以下のURLで動作確認できます。URLのファイル名部分(12345.xml)を色々変更して試してみてください。
http://nanoappli.com/dev/201101_frontController3/12345.xml
プログラム内で、データ生成のキー(伝票No)と、フォーマットの文字列(拡張子)まで取得できれば、後はPHPのプログラムでデータ検索と,処理分岐を行うだけです。
(データ処理自体は、普通のPHPプログラムなのでこの記事では割愛します)
以上で、複数フォーマットのデータを1本のプログラムで生成させる,シンプルな仕組みが出来ました。
まとめ
1.特定URL以下へのアクセスを一本化するために、以下の内容で.htaccessファイルを作成する。
RewriteEngine on RewriteRule .* index.php |
2.PHPでは、$_SERVER[“REQUEST_URI”]でアクセスされたURLを検出できる。
3.上記2.で取得した文字列を解析して、データ生成のキーと、フォーマットの文字列(拡張子)を取得する。
関連記事
コメントを残す