ネット上のファイルをダウンロードするページを作ります。アクセス時のブラウザの表示を次に示します。
ダウンロード時のセキュリティのために、ディレクトリトラバーサル対策とCSRF対策を行います。ディレクトリトラバーサル対策は、リクエストのパスに不正な内容を指定することで、本来アクセス権のないファイルを閲覧、改ざん、削除されてしまう脆弱性のことで、ファイルを開く場合は、固定ディレクトリ+ファイル名にします。CSRF(クロスサイト・リクエストフォージェリ)対策は、ログイン後のユーザーが行える処理の不正実行することで、ユーザーからのリクエストを本人のリクエストだと判別する仕組み「セッションID」を使用します。
ブラウザに「ロード」ボタンを表示する「load.php」を次に示します。ファイル変数「loadfile」に「/file/demo.pdf」、セッションID変数「session_id」にsession_id関数の戻り値をそれぞれ設定し、ダウンロード処理「loadstart.php」を呼び出します。
load.php
<?php session_start(); ?> <form action="loadstart.php" method='post'> <input name="loadfile" type="hidden" value="<?php echo htmlspecialchars('/file/demo.pdf', ENT_COMPAT, 'UTF-8'); ?>" /> <input name="session_id" type="hidden" value="<?php echo htmlspecialchars(session_id(), ENT_COMPAT, 'UTF-8'); ?>" /> <input type="submit" value='ロード' /> </form>
ディレクトリトラバーサル対策とCSRF対策を行い、指定されたファイルをネット上からダウンロードする「loadstart.php」を次に示す。ディレクトリトラバーサル対策のために、受け取ったファイル変数「loadfile」に「..」が含まれていないかチェックし、固定ディレクトリ「/xxxx/xxxx/」の配下でアクセスします。CSRF対策のためにsession_id関数を実行し、受け取ったセッションID変数「session_id」と戻り値を比較し同じであることを確認します。
loadstart.php
<?php /* ディレクトリトラバーサル対策 */ $DIR_PATH = '/xxxx/xxxx/'; ini_set('open_basedir', $DIR_PATH); function get_name($str) { if (strpos($str, '..') !== false) { echo '相対パスは使用不可'; exit(); } return str_replace('\0', '', $str); } $file = get_name(basename($_POST['loadfile'])); //ファイル名取得 $dir = get_name(dirname($_POST['loadfile'])); //ディレクトリ名取得 /* ディレクトリトラバーサル対策 */ /* CSRF対策 */ session_start(); $id = session_id(); $post = $_POST['session_id']; if (session_id() !== $_POST['session_id']) { echo '不正な処理です'; exit(); } /* CSRF対策 */ chdir($DIR_PATH . $dir); //当該ディレクトリに移動 $mime_name = mime_content_type($file); //ダウンロードするファイルのMIMEタイプを取得 $file_length = filesize($file); header("Content-Disposition: attachment; filename=$file"); header("Content-Length:$file_length"); header("Content-Type:$mime_name"); readfile($file); ?>
ファイル構成は、同じフォルダにディレクトリ「file」を作成し、作成したディレクトリにpdfファイル「demo.pdf」を置きます。ブラウザから次のURLを入力します。
http://localhost/download/load.php
表示された「ロード」ボタンをクリックすると、pdfファイル「demo.pdf」がダウンロードされます。