PHPでファイル送信を行う

ソフトウェアやその他のファイルをダウンロードするようなページを作ることを考える。サーバ上にファイルを置いてそのファイルへのリンクを作成すれば目的は達成できるだろう。が、例えばダウンロードしに来た人に名前やメールアドレスなどを入力してもらい、ある一定の条件をクリアした人だけにダウンロードをさせるようなサイトを考えたときには、入力とダウンロードを行うスクリプトなりCGIなりを考えなければならないだろう。

ということで、そこだけ取り出したコードを示してみよう。

一括送信方式

引数で指定したファイルを(URLではない)を一括送信する。PHPのマニュアルなどによく出ているものだ。


ほとんどの場合これで問題はない。が、私の場合300MBを超える巨大なファイルを送信したら、半分くらいでサーバが送信を停止してしまう現象に悩まされた。ブラウザから見るとファイルのダウンロードが中断したようになる。あるいは、正常にファイルがダウンロードできたように見える。いずれにしても正しい動きではない。

原因は、PHPのスクリプトが動作できる時間設定がデフォルトでは30秒に制限されているからだ。ダウンロードのスクリプトは巨大なファイルになると30秒では終了しない。そこで、set_time_limit()関数を使ってタイムアウトを適当な時間に設定する。2分くらいでよいだろうか。

さて、これで動作するようにはなった。ところが、ユーザがダウンロードのボタンを押してからブラウザになんらかの表示が現れるまでに時間がかかる。なんとかこれを改善する方法はないか。

ファイルを少しずつ送信する方式

ブラウザにファイル保存のダイアログや通知バーが表示されるのが遅くなるのは、PHPスクリプトが動作してreadfile)が呼ばれ、実際にブラウザに最初のデータが届くのに時間がかかっているからのようだ。readfile()関数は、指定された全データを一度読み込んで動作する。なので巨大なファイルではその読み込みに時間がかかる。そこで、ファイルの内容を少しずつ読み込みながら少しずつブラウザに送信してやれば問題は解決するのではないか?

結果はビンゴ。どうやらこれで問題は起こらないようだ。


1メガ単位で送信している。状況によってもっと小さくしても良いかもしれない。これで実用的な速度で使えるのではないだろうか。