Velikost nahrávaných souborů

Školení, která pořádám

Když chcete pomocí HTML formuláře na server nahrávat soubory a zpracovávat je v PHP, tak pokud nezapomenete formuláři nastavit správný enctype, nečeká na vás u normálních souborů moc záludností.

Problémy mohou nastat až u velkých souborů, ve výchozím nastavení větších než 2 MB. V tom případě musíte nastavit direktivu upload_max_filesize. Další omezení existuje na velikost všech formulářových dat, to se nastavuje direktivou post_max_size. Aby toho nebylo málo, může mít PHP omezenou pomocí direktivy memory_limit i celou paměť, kterou může zabrat. A protože nahrané soubory projdou pamětí přidělenou PHP, musí mít dostatečnou hodnotu i tato direktiva. Velké soubory se také obvykle déle zpracovávají, takže nelze zapomenout ani na max_input_time.

Aby těch omezení nebylo málo, může se přidat i webový server, např. v případě Apache direktivou LimitRequestBody. Asi nejlepší by bylo velikost omezit rovnou u klienta. Dokumentace PHP se zmiňuje o položce MAX_FILE_SIZE, která ale pokud vím není nikde standardizovaná a prohlížeče ji ignorují, takže má nepříliš valný význam pouze v PHP (protože mi útočník může podstrčit libovolnou hodnotu této položky, tak se na ni nelze spolehnout).

Pro direktivy PHP by tedy měl platit vztah memory_limit > post_max_size > upload_max_filesize. Pokud je překročena direktiva upload_max_filesize, dozvíme se to díky chybě UPLOAD_ERR_INI_SIZE. Pokud je ale překročena direktiva post_max_size, nedozvíme se to nijak a pole $_POST a $_FILES zůstanou prázdné. Řešit se to dá např. použitím formuláře <form action="?sent=1" method="post" enctype="multipart/form-data"> a kódu:

<?php
if ($_FILES) {
    // normální zpracování formuláře
} elseif (isset($_GET["sent"])) {
    // neposlala se žádná data, pravděpodobně byl překročen post_max_size
} else {
    // první načtení stránky
}
?>

Druhou možností je konktrolovat proměnnou $_SERVER["REQUEST_METHOD"] – pokud má hodnotu POST a přesto je pole $_FILES prázdné, tak nutně došlo k překročení velikosti odesílaných dat.

Pokud se data chystáte ukládat do databáze, je nutné nastavit ještě proměnnou max_allowed_packet (výchozí hodnota je 1 MB).

Jakub Vrána, Seznámení s oblastí, 13.7.2005, diskuse: 17 (nové: 0)

Diskuse

kamil:

MAX_FILE_SIZE prohlížeče neignorují (alespoň tedy IE). Je to docela užitečná věc, zbytečně se na server nepřenáší příliš velké soubory. Kontrola je samozřejmě pak nutná i v php, tohle je jen takové usnadnění, něco jako kontroly formulářů v javascriptu.

ikona Jakub Vrána OpenID:

Jak se projevuje to, že prohlížeče MAX_FILE_SIZE neignorují? Čekal bych, že na mě vybafnou nějakou chybovou hlášku při vkládání souboru nebo odesílání formuláře nebo ho třeba odmítnou odeslat, a nic takového se neděje.

zdenek:

pokud uploadovany soubor je vetsi nez MAX_FILE_SIZE, bude v promenne $_FILES['soubor']['error'] hodnota UPLOAD_ERR_FORM_SIZE, ale nejsem si jisty jestli plati vzdy a vsude (podle manualu u php > 4.2.0)

ikona Jakub Vrána OpenID:

To, že MAX_FILE_SIZE zohledňuje PHP, je známá věc a je to uvedeno i v článku. Řeč je o tom, jestli na to berou ohled také prohlížeče. V článku je uvedeno, že ne, a já na tom i přes názor Kamila trvám. Řekl bych, že Kamil pouze nerozpoznal, že zpracování souboru zarazilo až PHP a ne už prohlížeč.

Tomas:

A jak zamezit chybe pri vetsim souboru:
PHP Warning:  MAX_FILE_SIZE of 102400 bytes exceeded - file [p_soubor=004.jpg] not saved in Unknown on line 0

ikona Jakub Vrána OpenID:

Nastavením direktivy error_reporting v php.ini, případně vypnutím zobrazování chyb direktivou display_errors tamtéž.

Tomas:

A jde vypnout jen tato hlaska? Ja je nezobrazuji na monitor ale zapisuji si je do logu at mam prehled o moznych problemech.

ikona Jakub Vrána OpenID:

Nejjednodušší je pole MAX_FILE_SIZE vůbec nepředávat. V článku je popsáno, že to stejně nemá valný smysl.

Leo:

Na zaklade diskuze na Builderu (http://forum.builder.cz/read.php?20,1641122) jsem prisel na to, ze elegantnejsi test bude porovnat post_max_size s hlavickou $_SERVER['CONTENT_LENGTH'], kterou u post dat posila klient (neni v ni jen velikost uploadovaneho souboru a dat, ale i rezie na multipart). Leo

Millee:

Zdravím,
pokud pouziju <input type="hidden" name="MAX_FILE_SIZE" value="1000" /> , tak se mi to stejne zacne odesilat na server... chtelo by to neco, kdyby se to mohlo zarazit jeste pred odeslaním. To si to pak muzu osetrit napriklad pomoci $_FILES['img']['size']... ,nebo ne? Diky za odpoved

ikona Jakub Vrána OpenID:

O žádné kontrole na straně klienta nevím. Možná by to šlo v některých prohlížečích zařídit JavaScriptem, ale ani na to bych si nevsadil.

Daw:

jde to pomoci JScriptu, ktery ale podporuje jenom MSIE (mozna i Opera - to strilim).

function VelikostSouboru(soubor)
{
    var obj = new ActiveXObject("Scripting.FileSystemObject");
    var us = obj.GetFile(soubor);
    return(us.Size); // velikost v bytech
}

kozotoč:

bůhví, do jaké míry ten či onen klientský prohlížeč umožňuje, aby jeho javascript ve stránce zjišťoval velikost souboru.

MAX_FILE_SIZE bych symbolicky predaval pro budouci generace (prohlizecu) :)

a jen doplním, že parametr `sent` může být i jako <input type="hidden" ..

ikona Jakub Vrána OpenID:

Parametr sent se ve skrytém formulářovém poli poslat nemůže, protože pokud je překročena velikost posílaných dat, tak bude prázdný i tento parametr.

Honza Odvárko:

> Pokud se data chystáte ukládat do databáze, je nutné nastavit ještě proměnnou max_allowed_packet (výchozí hodnota je 16 MB).

Sím, stačí max_allowed_packet nastavit jakožto lokální proměnnou, nebo musím ovlivnit globální? Pátral jsem v dokumentaci, ale zaboha se mi nepovedlo limit nastavit bez změny globální, k čemuž mívá ověem právo jen root. Na serveru s více uživateli asi se změnou nepochodím, mám pravdu?

Díky

Shuster:

Je mozne pomocou PHP uploadnut aj 40 - 90MB subor?
Samozrejme s prislusnymi nastaveniami.
Neovplyvnuje to max_execution_time?
Ak by upload suboru mal trvat dlhsie

Flexa:

Díky za vysvětlení. Už jsem začínal být přesvědčený, že se mi zbláznil server a při překročení upload_max_filesize mi svévolně stránku reloadne.

Vložit příspěvek

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2016 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.