仕事で使える魔法のLAMP(40):ファイルのアップロードを制限する今回は、HTTPクライアントがアップロードしてくるファイルの扱いについて解説します。});POSTデータの最大サイズを制限する第37回から、PHPの実行時設定の中でも、初期設定のまま放置しない方が良い項目を紹介し、それぞれの設定変更法を解説しています。第38回(前々回)と第39回(前回)で、HTTPクライアントが送信してくるリクエストデータに関係する設定項目について解説してきました。今回は、残った数少ない設定項目を片付け、リクエストデータの扱いに関する解説は今回でおしまいとします。今回最初に取り上げるのは「post_max_size」ディレクティブです。このディレクティブは、POSTメソッドで受け取るリクエストデータの最大サイズを指定するものです。WebブラウザなどのHTTPクライアントからデータを送信する方法には、GETメソッドとPOSTメソッドの2つがありますが、これはPOSTメソッドに関係するものです。GETメソッドは、送信したい値をURLに付け加えて送るので、もともと大きな値は送信できません。データ量を制限する設定項目もありません。前回も解説した通り、PHPではPOSTメソッドおよびGETメソッドでリクエストデータを受信すると、自動的にそのデータを配列変数に格納します。変数を保存する場所はメモリ空間です。巨大なデータを受信すると、それだけメモリを消費します。これは入力フォームを1つも作らなかったページにも起こりうることです。POSTで大きなデータを送り付けるだけでメモリを消費させることができます。従って、「post_max_size」の設定値はあまり大きくするべきではありません。初期設定値は8Mbytesですが、ファイルを送信するならともかく、フォームの入力データを送信するようなアプリケーションで、このような大きなサイズのPOSTデータを送信することはまずないでしょう。小さな値にしてもよいと思います。大きなファイルを送信することを前提としたアプリケーションでは、設定値を大きくすることも考えるべきでしょう。結局のところ、第37回で紹介した「memory_limit」と同様に、アプリケーションの処理内容次第となります。ここでは普通にフォームのデータを送信する場合だけを想定し、64Kbytesとしておきます。このように小さい値に設定しても、ファイル送信の部分だけ「post_max_size」の設定値を大きくするといったことも可能です。「post_max_size」を16、つまり16byteに設定して、試してみましょう。PHPが実行できるディレクトリに、print_post.phpという名前で以下に挙げるコードを保存してください。中身は単純、$POST変数を表示するだけのものです。<?phpprint_r($_POST);?>post_max_sizeの設定は、データだけでなく、パラメータ名やパラメータ同士のの連結に使う文字もすべて合わせたデータのサイズを制限します。パラメータ名と値は「=」で連結し、複数のパラメータは「&」で連結しますが、その分も合わせたデータサイズを制限するのです。curlコマンドで2つのパラメータを送信してみます。1234)結果を見ると、2つのパラメータとそれぞれのデータが送信できていることが分かります。この例で送信した文字「foo=bar&baz=1234」は16文字。制限に収まっています。1文字追加して、次のように実行してみましょう。http://www3026ub.sakura.ne.jp/print_post.phpArray()post_max_sizeの設定値を超えてしまい、リクエストデータを確認しようにも、存在しないということになってしまいました。PHPでは、post_max_sizeの設定で制限した値を超えたデータを送信すると、リクエストデータすべてが無視されるためです。制限の範囲内にあるパラメータだけが処理されるというようなことはないので、大きなデータを受信するようなアプリケーションを実装する場合はこの点に留意する必要があります。5.3.9が入手可能になったことを紹介しました。5.3.9にアップデートできないときに、リクエストデータの最大値を制限するという方法を紹介しました。今回紹介したpost_max_sizeが、そのための設定です。5.3.9では、「max_input_vars」という、パラメータの最大数を制限するディレクティブも導入されました。こちらも設定しておきましょう。フォームを使った一般的なアプリケーションを動かすことを想定して、100としておきます。アップロードファイルをどこで受け付けるか?リクエストデータはファイルを含んでいることもあります。Webブラウザから、ファイルを選択して送信するときを考えれば分かるでしょう。このようにしてファイルを受信すると、ファイルそのものは変数には格納せず、ファイル名やファイルサイズなどの情報を変数に格納します。ファイルそのものはサーバ上のファイルシステムに保存するのです。ファイルは一般にデータサイズが大きいため、メモリには置かずに、受信したらそのままファイルシステムに書き込むようになっているのです。このようにファイルアップロード機能を利用するときに注意すべきディレクティブがいくつかあります。「file_uploads」ディレクティブは、ファイルアップロード機能を有効にするかどうかを設定します。初期設定値はOnですが、使わないことが分かっているならOffにしてもよいでしょう。このディレクティブは、ディレクトリによって設定を使い分けることができません。サーバ全体でファイルアップロードを受け付けることがないということでもない限り、Onのままにしておく方が良いでしょう。次に注意したいのが「upload_tmp_dir」ディレクティブです。これは、HTTPクライアントがアップロードしてきたファイルを格納するディレクトリを指定するものです。この場合は、標準的な一時ディレクトリを使う事になります。Linuxならば/tmpです。ここで、皆さんにお聞きしたいことが1つあります。/tmpの実体についてです。皆さんのLinuxサーバでは、/tmpの実体はディスクでしょうか。ディスクなら、どれくらいの容量のデータまで記録できるでしょうか。連載の解説で使わせていただいているさくらインターネットのVPSでdfを実行してみました。標準OSであるCentOSでの実行結果です。/home/tmpはディスクであり、/(ルートディレクトリ)直下にあることが分かります。このような場合、/の記録容量に注意しなければなりません。限界に近づいているときに、ファイルをアップロードしてしまうと、OSの動作に支障をきたすことが考えられるのです。念のため、upload_tmp_dirの設定は、/home以下に作成したディレクトリなどに変更しておきたいところです。別ディスクである/homeであれば、仮に記録容量の限界に達してもOSの動作に悪影響を及ぼすことはありません。いうことで、/home/uploadsというディレクトリをアップロードディレクトリにすることにしましょう。Serverの実行権限(ここではdaemon)で書き込み可能になるようにディレクトリを作成します。/home/uploadsもう1つ、別の環境を調べてみましょう。/tmpこちらの環境は、/tmpがディスクではなく、tmpfsというものになっています。ここに作成したファイルはメモリ上に保存されます。いわゆるRAMディスクのようなものです。このようなケースでは「upload_tmp_dir」を/tmpのままにしておくと、大きなファイルを受け付けたときに、メモリをかなり消費してしまいます。別の場所、しかもディスク上を指定しましょう。ここで挙げた例では、OSのディレクトリ構成は/のみになっているので、/以下にアップロードファイルを受け付けるディレクトリを作るほかありません。モニタリングシステムなどによるディスク容量の監視が必要でしょう。upload_tmp_dirの設定値として、Webサーバが公開しているディレクトリの配下を指定することは絶対にいけません。アップロードしたファイルが外部からアクセスできるようになってしまうことがあります。Webサーバの公開ディレクトリが、PHP実行可能な状態ならば、PHPスクリプトファイルを送り込んでそれを実行させるということも不可能ではありません。アップロードファイルの最大サイズアップロード対象のファイル1つ当たりの最大ファイルサイズを設定する、「upload_max_filesize」というディレクティブもあります。post_max_sizeと同じように、アプリケーションの処理内容やディスク容量なども合わせて考え、問題の起きない範囲でもっとも小さい値に設定しましょう。このディレクティブを設定するときは、1つ覚えておいてほしいことがあります。post_max_sizeより小さくしなければならないのです。HTTPクライアントがファイルをアップロードするときは、POSTメソッドで送信しますので、post_max_sizeによる制限を受けるということです。ファイルのアップロードという行為は、ほかのリクエストデータ同様に、無関係なPHPファイルに対して実行しても成功することがあります。いつものようにcurlを使えば簡単に試せます。次のようにして80Mbytesのファイルを作成します。パラメータ名=@ファイル名」とします。http://www3026ub.sakura.ne.jp/phpinfo.phpこれまでの連載で何度か使用した、phpinfo()を表示するPHPスクリプトに対し、80Mbytesのファイルを送信したことになります。送信中に/home/uploadsの中身を見ると、次のようにファイルをアップロードしている様子を確認できます。phpaidfT2このファイルはPHPスクリプトが終了すると同時に消去されますが、外部から自由にファイルを作成できる状況であるということが、よく分かるでしょう。サーバ全体では、「upload_max_filesize」の値は最小の「1」にしておき、ファイルアップロードを許可するアプリケーションごとに適切な値をそれぞれ指定するのが良いでしょう。設定値を0にすると制限がなくなってしまうようです。最後にディレクティブ「max_file_uploads」を紹介します。これは、一度に送信できるファイル数の上限を決めるディレクティブです。これを変更する必要はあまりないでしょう。まとめ今回の解説を踏まえて、php.iniを編集すると次の通りになります。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。