PHP'nin "post_max_size" değerini aşan dosyaları incelikle nasıl işleyebilirim?


86

Bir e-postaya dosya ekleyen bir PHP formu üzerinde çalışıyorum ve yüklenen dosyanın çok büyük olduğu durumları incelikle ele almaya çalışıyorum.

php.iniBir dosya yüklemesinin maksimum boyutunu etkileyen iki ayar olduğunu öğrendim : upload_max_filesizeve post_max_size.

Bir dosyanın boyutu aşarsa upload_max_filesize, PHP dosyanın boyutunu 0 olarak döndürür. Sorun değil; Bunu kontrol edebilirim.

Ama aşarsa post_max_size, senaryom sessizce başarısız oluyor ve boş forma geri dönüyor.

Bu hatayı yakalamanın bir yolu var mı?


1
Php.ini'ye erişiminiz var mı? post_max_size, upload_max_filesize değerinden daha büyük ayarlanmalıdır. Ayrıca ca2.php.net/manual/en/features.file-upload.post-method.php
Matt McCormick

@Matt McCormick - MAX_FILE_SIZE girişi harika çalışıyor - dosya boyutu bunu aşarsa, dosya boyutu artık 0 olarak görünüyor, bu zaten halihazırda ele aldığım bir durumdur. Bu, kötü niyetli bir kullanıcı tarafından atlanabilse de, buradaki amaçlarıma hizmet ediyor, çünkü sadece normal kullanıcılar için zarif bir şekilde başarısız olmaya çalışıyorum.
Nathan Long

Yanıtlar:


55

Gönderen belgeler :

Gönderi verilerinin boyutu post_max_size değerinden büyükse, $ _POST ve $ _FILES süper küreselleri boştur . Bu, çeşitli şekillerde izlenebilir, örneğin verileri işleyen betiğe $ _GET değişkenini ileterek, yani <form action = "edit.php? Processing = 1"> ve ardından $ _GET ['işlendi'] olup olmadığını kontrol ederek Ayarlamak.

Ne yazık ki, PHP bir hata gönderiyor gibi görünmüyor. Ve boş bir $ _POST dizisi gönderdiği için, betiğiniz boş forma dönmesinin nedeni budur - bunun bir POST olduğunu düşünmez. (Oldukça zayıf bir tasarım kararı IMHO)

Bu yorumcunun da ilginç bir fikri var.

Post_max_size ve $ _SERVER ['CONTENT_LENGTH'] arasında karşılaştırma yapmak daha zarif görünüyor. Lütfen ikincisinin yalnızca yüklenen dosyanın boyutunu ve gönderi verilerini değil, aynı zamanda çok parçalı dizileri de içerdiğini unutmayın.


3
Lütfen kalın yazılan bölümü okuyun. Yani, dosya boyutu upload_max_filesize değerini aşarsa, kullanıcı form post_max_size değerini aştığında ne olacağını soruyor. post_max_size, bu sorunu önlemek için upload_max_filesize'dan daha yüksek bir değere ayarlanmalıdır, ancak OP'nin bunu aynı tutmak için nedenleri olabilir.
Matt McCormick

1
Üzgünüm, post_max_size ve upload_max_filesize'ı karıştırdım. +1
Pekka

@Matt - post_max_size IS, upload_max_filesize değerinden daha yüksek ayarlanmış, ancak yükleme her ikisini de aşarsa yine de hatayı alıyorum. İkisinin arasına düşerse, dosya boyutunun 0 gösterdiğini görüyorum.
Nathan Long

1
Çözdünüz, ama evet post_max_size mevcut. Sadece ini_get ('post_max_size') yapın. ini_get () ayrıca diğer INI ayarlarını kontrol etmek için de kullanılabilir.
Matt McCormick

1
@SavasVedova - bunu belirttiğiniz için teşekkürler, ancak artık sorun gideremiyorum. Birkaç yıl oldu ve artık o şirkette veya PHP'de çalışmıyorum. :)
Nathan Long

45

Maksimum gönderi boyutunu aşan dosyaları yakalamanın / işlemenin bir yolu var, bu, son kullanıcıya ne olduğunu ve kimin hatalı olduğunu anlattığı için tercih ettiğim budur;)

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
Bu, php.ini'de track_errors = Off, muhtemelen display_errors = Off ve display_startup_errors = Off olduğunda çalışır. Aksi takdirde PHP o kadar uzağa gidemez ve soru başlığında olduğu gibi uyarı göndermez. Ancak bir üretim sisteminde bu php.ini ayarı olmalıdır, bu yüzden bu harika çalışıyor.
raoulsson

2
Bu temiz fikir, testlerimde iyi çalışıyor (PHP / 5.5.8). Ayrıca alma artırılabilir $_SERVER['CONTENT_LENGTH']ve upload_max_filesizehesaba.
Álvaro González

Raoulsson'un yorumundan yola çıkarak , hataların bastırıldığı bir ortamda değilseniz uyarıyı bastırmanın bir yolu var mı?
2014

6

$ _POST ve $ _FILES boşluklarının kontrolünün çalışmadığı, çünkü geçerli isteklerde de boş oldukları için SOAP istekleri için sorun yaşadık.

Bu nedenle CONTENT_LENGTH ve post_max_size'ı karşılaştırarak bir kontrol uyguladık. Atılan İstisna daha sonra kayıtlı istisna işleyicimiz tarafından bir XML-SABUN-HATASINA dönüştürülür.

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: eklenen "break" komutları doğru değil. bunlar
staabm

Boyutun aşıp aşmadığını kontrol etmek gereksizdir. Dosya olmasaydı content_length olmazdı. Bu nedenle, içerik_uzunluğunun ayarlanıp ayarlanmadığını ve gönderi ve dosya değişkenlerinin boş olup olmadığını kontrol etmeniz yeterlidir. Hayır?
ADJenks

4

@Matt McCormick'in ve @ AbdullahAJM'nin yanıtlarına dayanarak, testte kullanılan değişkenlerin ayarlandığını kontrol eden ve ardından $ _SERVER ['CONTENT_LENGTH'] php_max_filesize ayarını aşıp aşmadığını kontrol eden bir PHP test durumu:

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

Bunu yapmanın en mantıklı yolu budur. _Post'un boş olup olmadığını ancak içerik uzunluğunun boş olup olmadığını kontrol edin. Boyutları karşılaştırmaya gerek yok.
ADJenks

1

Bu, bu sorunu çözmenin basit bir yoludur:

Kodunuzun başında "checkPostSizeExceeded" çağırmanız yeterli

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

Bu yardımcı işlevi kopyalamayı unutmayın:

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.