PHPの `post_max_size`を超えるファイルを適切に処理するにはどうすればよいですか?


86

私はファイルを電子メールに添付するPHPフォームに取り組んでおり、アップロードされたファイルが大きすぎる場合を適切に処理しようとしています。

php.iniファイルアップロードの最大サイズに影響を与える2つの設定があることを学びました:upload_max_filesizepost_max_size

ファイルのサイズがを超える場合upload_max_filesize、PHPはファイルのサイズを0として返します。それで問題ありません。確認できます。

しかし、それを超えるpost_max_sizeと、スクリプトはサイレントに失敗し、空白のフォームに戻ります。

このエラーをキャッチする方法はありますか?


1
php.iniにアクセスできますか?post_max_sizeは、upload_max_filesizeよりも大きく設定する必要があります。また、ca2.php.net / manual
Matt McCormick 2010年

@Matt McCormick-MAX_FILE_SIZE入力はうまく機能します-ファイルサイズがそれを超えると、ファイルサイズは0と表示されます。これは、私がすでに処理したケースです。これは悪意のあるユーザーによって回避される可能性がありますが、通常のユーザーに対しては正常に失敗しようとしているだけなので、ここでは私の目的を果たします。
ネイサンロング

回答:


55

ドキュメントから:

投稿データのサイズがpost_max_sizeより大きい場合、$ _ POSTおよび$ _FILESスーパーグローバルは空です。これは、さまざまな方法で追跡できます。たとえば、データを処理するスクリプトに$ _GET変数を渡します。つまり、<form action = "edit.php?processed = 1">で、$ _ GET ['processed']がセットする。

残念ながら、PHPがエラーを送信するようには見えません。また、空の$ _POST配列を送信するため、スクリプトが空白のフォームに戻るのはそのためです。POSTとは見なされません。(私見ではかなり悪い設計決定)

このコメンターも面白いアイデアを持っています。

より洗練された方法は、post_max_sizeと$ _SERVER ['CONTENT_LENGTH']を比較することのようです。後者には、アップロードされたファイルと投稿データのサイズだけでなく、マルチパートシーケンスも含まれることに注意してください。


3
太字部分をお読みください。つまり、ファイルサイズがupload_max_filesizeを超える場合、ユーザーはフォームがpost_max_sizeを超えるとどうなるかを尋ねています。この問題を回避するには、post_max_sizeをupload_max_filesizeよりも高く設定する必要がありますが、OPには同じままにする理由がある場合があります。
マットマコーミック2010年

1
申し訳ありませんが、post_max_sizeとupload_max_filesizeを混同しました。+1
ペッカ2010年

@ Matt-post_max_sizeはupload_max_filesizeよりも高く設定されていますが、アップロードが両方を超えると失敗します。それは両者の間にある場合、私は0のファイルサイズを示していることを確認
ネイサン・ロング

1
あなたはそれを解決しました、しかしはいpost_max_sizeは利用可能です。ini_get( 'post_max_size')を実行するだけです。ini_get()を使用して、他のINI設定を確認することもできます。
マットマコーミック2010年

1
@ SavasVedova-それを指摘してくれてありがとう、しかし私はもうトラブルシューティングできません。数年経ちましたが、私はその会社やPHPで働いていません。:)
ネイサンロング

45

最大投稿サイズを超えるファイルをキャッチ/処理する方法があります。これは、エンドユーザーに何が起こったのか、誰に問題があるのか​​を伝えるため、私の好みです;)

if (empty($_FILES) && empty($_POST) &&
        isset($_SERVER['REQUEST_METHOD']) &&
        strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
    //catch file overload error...
    $postMax = ini_get('post_max_size'); //grab the size limits...
    echo "<p style=\"color: #F00;\">\nPlease note files larger than {$postMax} will result in this error!<br>Please be advised this is not a limitation in the CMS, This is a limitation of the hosting server.<br>For various reasons they limit the max size of uploaded files, if you have access to the php ini file you can fix this by changing the post_max_size setting.<br> If you can't then please ask your host to increase the size limits, or use the FTP uploaded form</p>"; // echo out error and solutions...
    addForm(); //bounce back to the just filled out form.
}
else {
    // continue on with processing of the page...
}

2
これは、php.iniでtrack_errors = Off、場合によってはdisplay_errors = Offおよびdisplay_startup_errors = Offの場合に機能します。そうしないと、質問のタイトルのように、PHPはそこまで到達せず、警告を送信しません。しかし、本番システムでは、これはphp.ini設定である必要があるため、これはうまく機能します。
raoulsson 2013

2
このきちんとしたアイデアは、私のテスト(PHP / 5.5.8)ではうまく機能しています。また$_SERVER['CONTENT_LENGTH']upload_max_filesize考慮に入れて拡張することもできます。
アルバロゴンサレス

からに大手raoulssonのコメントを、あなたが抑制エラーのある環境でいないのであれば警告を抑止する方法はありますか?
brendo 2014年

6

$ _POSTと$ _FILESの空のチェックが機能しないSOAPリクエストの問題が発生しました。これは、有効なリクエストでも空であるためです。

したがって、CONTENT_LENGTHとpost_max_sizeを比較してチェックを実装しました。スローされた例外は、後で登録済みの例外ハンドラーによってXML-SOAP-FAULTに変換されます。

private function checkPostSizeExceeded() {
    $maxPostSize = $this->iniGetBytes('post_max_size');

    if ($_SERVER['CONTENT_LENGTH'] > $maxPostSize) {
        throw new Exception(
            sprintf('Max post size exceeded! Got %s bytes, but limit is %s bytes.',
                $_SERVER['CONTENT_LENGTH'],
                $maxPostSize
            )
        );
    }
}

private function iniGetBytes($val)
{
    $val = trim(ini_get($val));
    if ($val != '') {
        $last = strtolower(
            $val{strlen($val) - 1}
        );
    } else {
        $last = '';
    }
    switch ($last) {
        // The 'G' modifier is available since PHP 5.1.0
        case 'g':
            $val *= 1024;
            // fall through
        case 'm':
            $val *= 1024;
            // fall through
        case 'k':
            $val *= 1024;
            // fall through
    }

    return $val;
}

@ manuel-azar:追加された「ブレーク」ステメントは正しくありません。それらはそこに属していません..3v4l.org
ABfGsを

サイズがを超えているかどうかを確認する必要はありません。ファイルがない場合、content_lengthはありません。したがって、content_lengthが設定されており、post変数とfile変数が空であるかどうかを確認する必要があります。番号?
ADJenks

4

@Matt McCormickと@AbdullahAJMの回答に基づいて、テストで使用される変数が設定されていることを確認し、$ _ SERVER ['CONTENT_LENGTH']がphp_max_filesize設定を超えているかどうかを確認するPHPテストケースを次に示します。

            if (
                isset( $_SERVER['REQUEST_METHOD'] )      &&
                ($_SERVER['REQUEST_METHOD'] === 'POST' ) &&
                isset( $_SERVER['CONTENT_LENGTH'] )      &&
                ( empty( $_POST ) )
            ) {
                $max_post_size = ini_get('post_max_size');
                $content_length = $_SERVER['CONTENT_LENGTH'] / 1024 / 1024;
                if ($content_length > $max_post_size ) {
                    print "<div class='updated fade'>" .
                        sprintf(
                            __('It appears you tried to upload %d MiB of data but the PHP post_max_size is %d MiB.', 'csa-slplus'),
                            $content_length,
                            $max_post_size
                        ) .
                        '<br/>' .
                        __( 'Try increasing the post_max_size setting in your php.ini file.' , 'csa-slplus' ) .
                        '</div>';
                }
            }

これはそれを行うための最も論理的な方法です。_postが空であるが、コンテンツの長さが空でないかどうかを確認するだけです。サイズを比較する必要はありません。
ADJenks

1

これは、この問題を解決する簡単な方法です。

コードの先頭で「checkPostSizeExceeded」を呼び出すだけです

function checkPostSizeExceeded() {
        if (isset($_SERVER['REQUEST_METHOD']) and $_SERVER['REQUEST_METHOD'] == 'POST' and
            isset($_SERVER['CONTENT_LENGTH']) and empty($_POST)//if is a post request and $_POST variable is empty(a symptom of "post max size error")
        ) {
            $max = get_ini_bytes('post_max_size');//get the limit of post size 
            $send = $_SERVER['CONTENT_LENGTH'];//get the sent post size

            if($max < $_SERVER['CONTENT_LENGTH'])//compare
                throw new Exception(
                    'Max size exceeded! Were sent ' . 
                        number_format($send/(1024*1024), 2) . 'MB, but ' . number_format($max/(1024*1024), 2) . 'MB is the application limit.'
                    );
        }
    }

この補助関数をコピーすることを忘れないでください:

function get_ini_bytes($attr){
    $attr_value = trim(ini_get($attr));

    if ($attr_value != '') {
        $type_byte = strtolower(
            $attr_value{strlen($attr_value) - 1}
        );
    } else
        return $attr_value;

    switch ($type_byte) {
        case 'g': $attr_value *= 1024*1024*1024; break;
        case 'm': $attr_value *= 1024*1024; break;
        case 'k': $attr_value *= 1024; break;
    }

    return $attr_value;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.