Wie gehe ich mit Dateien um, die PHPs "post_max_size" überschreiten?

86

Ich arbeite an einem PHP-Formular, das eine Datei an eine E-Mail anfügt, und versuche, Fälle, in denen die hochgeladene Datei zu groß ist, ordnungsgemäß zu behandeln.

Ich habe erfahren, dass es zwei Einstellungen gibt php.ini, die sich auf die maximale Größe eines Datei-Uploads auswirken: upload_max_filesizeund post_max_size.

Wenn die Größe einer Datei überschritten wird upload_max_filesize, gibt PHP die Größe der Datei als 0 zurück. Ich kann das überprüfen.

Wenn es jedoch überschritten wird post_max_size, schlägt mein Skript stillschweigend fehl und kehrt zum leeren Formular zurück.

Gibt es eine Möglichkeit, diesen Fehler abzufangen?

Nathan Long
quelle
1
Haben Sie Zugriff auf php.ini? post_max_size sollte größer als upload_max_filesize eingestellt sein. Sie sollten auch <input type = "hidden" name = "MAX_FILE_SIZE" value = "30000" /> für das Formular verwenden, wie in ca2.php.net/manual/en/features.file-upload.post-method.php beschrieben
Matt McCormick
@Matt McCormick - die Eingabe MAX_FILE_SIZE funktioniert hervorragend - wenn die Dateigröße diese überschreitet, wird die Dateigröße jetzt als 0 angezeigt. Dies ist ein Fall, den ich bereits behandelt habe. Obwohl dies von einem böswilligen Benutzer umgangen werden kann, dient es hier meinen Zwecken, da ich nur versuche, für normale Benutzer ordnungsgemäß zu scheitern.
Nathan Long

Antworten:

55

Aus der Dokumentation :

Wenn die Größe der Post-Daten größer als post_max_size ist, sind die Superglobalen $ _POST und $ _FILES leer . Dies kann auf verschiedene Arten verfolgt werden, z. B. indem die Variable $ _GET an das Skript übergeben wird, das die Daten verarbeitet, dh <form action = "edit.php? Processed = 1">, und anschließend überprüft wird, ob $ _GET ['verarbeitet'] ist einstellen.

Leider sieht es nicht so aus, als würde PHP einen Fehler senden. Und da es ein leeres $ _POST-Array sendet, kehrt Ihr Skript zum leeren Formular zurück - es glaubt nicht, dass es sich um einen POST handelt. (IMHO eine ziemlich schlechte Designentscheidung)

Dieser Kommentator hat auch eine interessante Idee.

Ein eleganterer Weg scheint der Vergleich zwischen post_max_size und $ _SERVER ['CONTENT_LENGTH'] zu sein. Bitte beachten Sie, dass letztere nicht nur die Größe der hochgeladenen Datei plus Post-Daten, sondern auch mehrteilige Sequenzen umfasst.

Matt McCormick
quelle
3
Bitte lesen Sie den fettgedruckten Teil. Wenn die Dateigröße upload_max_filesize überschreitet, fragt der Benutzer, was passiert, wenn das Formular post_max_size überschreitet. post_max_size sollte höher als upload_max_filesize eingestellt werden, um dieses Problem zu vermeiden, aber das OP kann Gründe dafür haben, es gleich zu halten.
Matt McCormick
1
Entschuldigung, ich habe post_max_size und upload_max_filesize verwechselt. +1
Pekka
@Matt - post_max_size ist höher als upload_max_filesize eingestellt, aber ich erhalte immer noch den Fehler, wenn der Upload beide überschreitet. Wenn es zwischen den beiden liegt, sehe ich, dass die Dateigröße 0 anzeigt.
Nathan Long
1
Sie haben es gelöst, aber ja, post_max_size ist verfügbar. Mach einfach ini_get ('post_max_size'). Ini_get () kann auch verwendet werden, um andere INI-Einstellungen zu überprüfen.
Matt McCormick
1
@SavasVedova - danke, dass Sie darauf hingewiesen haben, aber ich kann keine Fehler mehr beheben. Es ist ein paar Jahre her und ich arbeite nicht mehr in dieser Firma oder in PHP. :)
Nathan Long
45

Es gibt eine Möglichkeit, Dateien zu fangen / zu verarbeiten, die die maximale Postgröße überschreiten. Dies ist meine bevorzugte Methode, da sie dem Endbenutzer mitteilt, was passiert ist und wer schuld ist.

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...
}
AbdullahAJM
quelle
2
Dies funktioniert, wenn track_errors = Off, möglicherweise auch display_errors = Off und display_startup_errors = Off in der php.ini. Andernfalls kommt PHP nicht einmal so weit und sendet die Warnung, wie im Fragentitel. In einem Produktionssystem sollte dies jedoch die Einstellung php.ini sein, damit dies hervorragend funktioniert.
Raoulsson
2
Diese nette Idee funktioniert in meinen Tests gut (PHP / 5.5.8). Es kann auch unter Berücksichtigung $_SERVER['CONTENT_LENGTH']und upload_max_filesizeunter Berücksichtigung verbessert werden .
Álvaro González
Führende auf von raoulsson ‚s Kommentar, ist es eine Möglichkeit , um die Warnung zu unterdrücken , wenn Sie nicht in einer Umgebung sind mit Fehlern unterdrückt?
Brendo
6

Wir haben das Problem bei SOAP-Anforderungen, bei denen eine Überprüfung der Leere von $ _POST und $ _FILES nicht funktioniert, da sie auch bei gültigen Anforderungen leer sind.

Deshalb haben wir eine Prüfung durchgeführt, bei der CONTENT_LENGTH und post_max_size verglichen wurden. Die ausgelöste Ausnahme wird später von unserem registrierten Ausnahmebehandler in einen XML-SOAP-FAULT umgewandelt.

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;
}
staabm
quelle
@ manuel-azar: Die hinzugefügten "break" -Stements sind nicht korrekt. die gehören nicht dorthin .. siehe 3v4l.org/ABfGs
staabm
Es ist nicht erforderlich, die Prüfung zu überprüfen, wenn die Größe überschritten wird. Es würde keine content_length geben, wenn es keine Datei gäbe. Sie müssen also nur überprüfen, ob content_length festgelegt ist und die Post- und Dateivariablen leer sind. Nein?
ADJenks
4

Aufbauend auf den Antworten von @Matt McCormick und @ AbdullahAJM finden Sie hier einen PHP-Testfall, in dem überprüft wird, ob die im Test verwendeten Variablen festgelegt sind und ob $ _SERVER ['CONTENT_LENGTH'] die Einstellung php_max_filesize überschreitet:

            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>';
                }
            }
Lance Cleveland
quelle
Dies ist der logischste Weg, dies zu tun. Überprüfen Sie einfach, ob _post leer ist, die Inhaltslänge jedoch nicht. Größen müssen nicht verglichen werden.
ADJenks
1

Dies ist eine einfache Möglichkeit, dieses Problem zu beheben:

Rufen Sie einfach "checkPostSizeExceeded" am Anfang Ihres Codes auf

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.'
                    );
        }
    }

Denken Sie daran, diese Zusatzfunktion zu kopieren:

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;
}
Doglas
quelle