[PHP] $_FILES[hoge]がundefinedになる問題

3 min read

はっきりとした理由は結局分かってはないんだけれど…。

状況

1GBのファイルをアップロードできるアプリ。ファイルサイズが1GB以上の場合はエラーメッセージを返却する作り。 しかし、1.2GBのファイルをアップロードしたときに $_FILES['hoge']が undefined になってしまった。

仮説

memory_limit, post_max_size, upload_max_filesize のいずれか、もしくは全ての設定値が1.2GBに対して足りないため、$_FILES['hoge'] が作られないのではないか。(このとき、php.ini の設定は1GBのアップロードに最適化させていた)

php.ini の設定

1GBアップロードの想定はこんな感じで設定してた。
memory_limit = 1230M
post_max_size = 1130M
upload_max_filesize = 1024M

2GB のアップロードに対応できる想定の値に変更。

memory_limit = 2460M
post_max_size = 2260M
upload_max_filesize = 2048M

検証結果

2GBまで対応させることで1.2GBのアップロードで問題が起きなくなった。 1.2GBではなく2.2GBをアップロードすると同様の問題が発生するように想定できる。イタチごっこなので対応したい。

対応

PHP - ファイルアップロードの例外処理はこれぐらいしないと気が済まない - Qiita」から丸パクリみたいな形になって恐縮だが、おおむね以下のような形で実装した。
  • $_FILES['upfile'] が存在するか確認
  • $_FILES['upfile']['error'] の内容を確認 → 致命的っぽいエラーは Exception を投げる
  • $_FILES['upfile']['size'] で定義した上限値との比較
try {
    if (
        !isset($_FILES['upfile']['error']) ||
        !is_int($_FILES['upfile']['error'])
    ) {
        throw new RuntimeException('パラメータが不正です');
    }

    switch ($_FILES['upfile']['error']) {
        case UPLOAD_ERR_OK: // OK
            break;
        case UPLOAD_ERR_NO_FILE:   // ファイル未選択
            throw new RuntimeException('ファイルが選択されていません');
        case UPLOAD_ERR_INI_SIZE:  // php.ini定義の最大サイズ超過
        case UPLOAD_ERR_FORM_SIZE: // フォーム定義の最大サイズ超過
            throw new RuntimeException('ファイルサイズが大きすぎます');
        default:
            throw new RuntimeException('その他のエラーが発生しました');
    }

    // ここで定義するサイズ上限のオーバーチェック
    if ($_FILES['upfile']['size'] > 1000000) {
        $message = 'ファイルサイズが大きすぎます。';
    }

} catch (Exception $e) {
    $message = $e->getMessage();
}

php.ini で設定した値の上限を超えた場合、つまり今回のように $_FILES['hoge'] が見つからない場合は、以下の条件で拾う事ができるはず。

!isset($_FILES['upfile']['error'])