第 19 章 ファイルアップロードの処理

目次
POST メソッドによるアップロード
陥りやすい落とし穴
複数ファイルのアップロード
PUT メソッドのサポート

POST メソッドによるアップロード

PHP は、全てのRFC-1867対応ブラウザ(Netscape Navigator 3 以上、 MicrosoftからのパッチをあてたMicrosoft Internet Explorer 3または パッチ無しのそれ以降の版を含みます)からファイルのアップロードを 受けることができます。 この機能では、テキストとバイナリファイルの両方のアップロードが可能です。 PHPの認証機構およびファイル操作関数を用いて、アップロードを許可する ユーザーとアップロード後にそのファイルを使用して行う動作を完全に制御する ことが可能です。

PHPはNetscape ComposerおよびW3CのAmayaクライアントにより使用される PUTメソッドによるファイルアップロードもサポートしていることに注意 して下さい。詳細は、PUTメソッドのサポート を参照下さい。

ファイルアップロード画面は、次のような特別なフォームを作成すること により、作成することができます。

例 19-1ファイルアップロード用のフォーム

<FORM ENCTYPE="multipart/form-data" ACTION="_URL_" METHOD="POST">
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="1000">
Send this file: <INPUT NAME="userfile" TYPE="file">
<INPUT TYPE="submit" VALUE="Send File">
</FORM>
_URL_ はPHPファイルを指す必要があります。hidden フィールド MAX_FILE_SIZEは、input フィールド file の前に置く必要があります。 この値は、取得可能なファイルの最大サイズを規定します。この値はバイ ト数で指定します。

警告

MAX_FILE_SIZEはブラウザへの勧告に過ぎません。この最大値を 出し抜くのは簡単なことなので信頼してはいけません。しかし、 PHP側の最大サイズの設定は信頼できるものです。

PHPでは、アップロードに成功した場合、次の変数がコールされるスク リプトで定義されます。ただし、php.iniregister_globals がOnになっていると仮定します。track_varsが on の場合、PHP 3 では、 これらの変数は、グローバル配列$HTTP_POST_VARSの 中でも利用可能です。 以下の変数名は、上の例で使用されているようにアップロードされたファ イルの名前として'userfile'を使用していることを仮定していることに注 意して下さい。

上記の変数のうち、"$userfile" は、アップロードフォームの TYPE=fileを有するINPUTフィールドのNAMEフィールドの値と関連すること に注意して下さい。上のアップロード用フォームの例においては、その NAME フィールドの値を "userfile" としています。

PHP 4では、この動作は若干異なり、アップロードされたファイルの情報 が新しいグローバル配列$HTTP_POST_FILESに代入さ れます。この機能は、track_varsを On にした場合にのみ 使用可能です。しかし、track_varsは、PHP 4.0.2以降のバー ジョンのPHPでは常に On になっています。

$HTTP_POST_FILESの内容は以下のようになります。 この例では、アップロードファイル名として上の例と同様に'userfile'を 使用していることを仮定していることに注意して下さい。

$HTTP_POST_FILES['userfile']['name']

クライアントマシンにおけるファイルの元の名前

$HTTP_POST_FILES['userfile']['type']

この情報がブラウザで指定された場合、ファイルのMIME型。 例としては、"image/gif"となります。

$HTTP_POST_FILES['userfile']['size']

アップロードされたファイルのバイト単位のサイズ。

$HTTP_POST_FILES['userfile']['tmp_name']

アップロードされたファイルをサーバー上で保持するファイルのテン ポラリファイル名。

php.iniupload_tmp_dirディレクティブで 他の場所を指定しない限り、ファイルはサーバーにおけるデフォルトのテ ンポラリディレクトリに保存されます。サーバーのデフォルトディレクト リは、PHP を実行する環境において環境変数 TMPDIRを設 定することにより変更することができます。しかし、PHP スクリプトの内 部からputenv() 関数により設定しても上手くいきま せん。この環境変数は、アップロードされたファイルに他の処理を行う際 にも同様に使用することが可能です。

例 19-2ファイルのアップロードを検証する

以下の例は、3.0.16より後のバージョンのPHP 3または 4.0.2 より後の バージョンの PHP 4 用です。is_uploaded_file() およびmove_uploaded_file()の関数のエントリを 参照下さい。

<?php 
if (is_uploaded_file($userfile)) {
    copy($userfile, "/place/to/put/uploaded/file");
} else {
    echo "ファイルアップロード攻撃を受けた可能性があります : ファイル名 '$userfile'.";
}
/* ...もしくは... */
move_uploaded_file($userfile, "/place/to/put/uploaded/file");
?>

これ以前のバージョンのPHPでは、次のような処理を行う必要がありま す。

注意 これは、4.0.2 より後のバージョンの PHP 4 では動作し ません。これは、これより後のバージョンでPHPの内部機 能が変更されたことによるものです。

<?php 
/* アップロードされたファイルを確認 */ 
function is_uploaded_file($filename) {
    if (!$tmp_file = get_cfg_var('upload_tmp_dir')) {
        $tmp_file = dirname(tempnam('', ''));
    }
    $tmp_file .= '/' . basename($filename);
    /* ユーザーはphp.iniで最後にスラッシュを指定しているかもしれません... */
    return (ereg_replace('/+', '/', $tmp_file) == $filename);
}

if (is_uploaded_file($userfile)) {
    copy($userfile, "/place/to/put/uploaded/file");
} else {
    echo "ファイルアップロード攻撃を受けた可能性があります : ファイル名 '$userfile'.";
}
?>

アップロードされたファイルを受け取る PHP スクリプトは、アップロー ドされたファイルを用いて何をするべきかを決めるために必要なロジック を全て実装する必要があります。例えば、変数 $file_sizeを使用して、小さすぎたり、大きすぎた りするファイルを捨てることができます。指定した型以外のファイルを全 て捨てるために変数$file_typeを用いることができ ます。何らかの方法により、テンポラリディレクトリからファイルを削除 したり、他の場所に移動したりする必要があります。

移動または名前の変更が行われていない場合、リクエストの終了時にその ファイルはテンポラリディレクトリから削除されます。