application/octet-stream を使う事によって、通常はブラウザに表示されてしまうようなファイルをダウンロードさせる事ができます。 また、保存時のファイル名を正しくする為に Content-disposition を使用しています。 PHP のオンラインマニュアル にはそのものズバリのサンプルが readfile のページにあります。 例1 readfile() によるダウンロードの強制
<?php $file = 'monkey.gif'; if (file_exists($file)) { header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename='.basename($file)); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); readfile($file); exit; } ?>
リンク先のマニュアルでも説明されていますが、readfile はそもそもこのような目的で使われる事を想定しているようで、『メモリに関する問題はなく、 巨大なファイルを送ってもかまいません。』とあります。特殊な目的で出力する為に内容に加工を加えるような場合は、後述のような内容で読み込めばいいはずです。 但し、キャッシュ制御が有効の場合は際限なく読み込んでしまって out of memory エラーが出る場合があるので、ob_end_clean であらかじめキャンセルしておくといいと思います。 システム書き込みバッファの内容を出力したい場合、キャッシュ制御が有効の場合は flash と ob_flush の両方が必要です ファイルサイズは無くてもダウンロード可能ですが、ただ、存在しないとクライアント側で何パーセント処理済みかの表示が不可能になります。 fread を使用して読み込む
<? header( "Content-Type: application/octet-stream" ); header( "Content-disposition: attachment; filename={$_GET['download_target']}" ); $path = '../download/' . $_GET['download_target']; $size = filesize( $path ); header( "Content-Length: $size" ); $fp = fopen( $path, 'rb' ); if ( $fp ) { while( TRUE ) { if ( feof( $fp ) ) { break; } $ret = fread( $fp, 1024 ); print $ret; } fclose( $fp ); } ?>
ファイルの取得方法では、小さいファイルならば、file_get_contents で十分ですが、大きなファイルではメモリが大量に消費させる可能性を考慮する必要があります。さらに、大きなファイルでは PHP 側のタイムアウトの設定も必要になる可能性があります。また、他のサーバーから取り込む場合は、ファイルサイズを取得するのに cURL 関数が必要になります。( PHP 5.0.0 以降 では filesize がそのまま使えるようなニュアンスですが、stat() を http がサポートしていないので使えません ) ※ 参考 : max_execution_time (30/PHP_INI_ALL) ▼ PHP マニュアルの投稿の引用
<?php $remoteFile = 'http://us.php.net/get/php-5.2.10.tar.bz2/from/this/mirror'; $ch = curl_init($remoteFile); curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //not necessary unless the file redirects (like the PHP example we're using here) $data = curl_exec($ch); curl_close($ch); if ($data === false) { echo 'cURL failed'; exit; } $contentLength = 'unknown'; $status = 'unknown'; if (preg_match('/^HTTP\/1\.[01] (\d\d\d)/', $data, $matches)) { $status = (int)$matches[1]; } if (preg_match('/Content-Length: (\d+)/', $data, $matches)) { $contentLength = (int)$matches[1]; } echo 'HTTP Status: ' . $status . "\n"; echo 'Content-Length: ' . $contentLength; ?> Result: HTTP Status: 302 Content-Length: 8808759
cURL を使ったサンプル PHP : WEBでもコマンドラインでもHTTPでファイルをダウンロードする
|
【PHP + 特記事項の最新記事】
- PHP のファイルアップロードで画像ファイルを限定で行う為のテンプレートと注意事項と解説
- PHP の関数で規定されているキャッシュコントロールの無効 : session_cache_limiter( 'nocache' )
- PHP : 一定時間前のファイルの削除
- PHP : ${'日本語表示'} という可変変数と、${hello . "X"} という連結可変変数
- cp932 の SQLServer に対して、PHP の ODBC 関数に対して UTF8 変換で地道に対応し、特殊なUncode文字は、HTML 数値エンティティで保存する。
- pChart2 に JKゴシックとラノベポップを使ってサンプルを作りました
- PHP の ImageMagick で作成した PNG 画像にオフセットが設定されてしまった場合の対応方法
- PHP : 連想配列を「オブジェクト」に変換(キャスト)するとうまく動きますが、通常配列では参照できないようです
- PHP でエラーが表示されない場合の ini_set( 'display_errors', "1" ) 使用時の注意事項
- 特に変更しても支障の無い error_append_string php.ini ディレクティブを使用して PHP 全体のデバッグに利用する
- PHP : 日本語を使った変数( 特殊文字列で変数 ) / 変数名を文字列として扱う
- PHPの真偽値
- PHP : include_path の設定
- PHP : 漢字スペースも trim