Aktuálna situácia: PHP2Shell. Dve kritické zraniteľnosti PHP (CVSS 9.2) umožňujú spustenie škodlivého kódu bez prihlásenia. Záplaty od 21. 10. 2026.Čo treba urobiť teraz →

Ako PHP spracúva nahrávanie súborov

Medzi kliknutím na Nahrať a vaším kódom leží v PHP celý reťazec spracovania. Táto stránka vysvetľuje multipart/form-data, dočasné súbory, $_FILES, limity a súvislosť s PHP2Shell.

Stav 4 min čítaniaZnalosti o PHP

Stručne: Keď prehliadač nahráva súbor, odošle požiadavku POST vo formáte multipart/form-data, v ktorej polia formulára a obsah súborov nasledujú za sebou ako jednotlivé časti. PHP túto požiadavku rozloží samo, každú časť so súborom zapíše do dočasného súboru v upload_tmp_dir, údaje uloží do $_FILES a až potom spustí váš skript. Skript súbor presunie pomocou move_uploaded_file(); všetko, čo sa nepresunie, PHP na konci požiadavky zmaže.

Cesta súboru od prehliadača až do skriptu

Pre rozhodovateľov je dôležité predovšetkým jedno: nahrávanie nie je úkon samotnej aplikácie. Veľká časť práce prebieha v interpreteri PHP skôr, než sa kód CMS alebo obchodu vôbec zapojí. Preto chyby v tejto časti PHP postihujú každý web, či už má formulár na nahrávanie, alebo nie.

Priebeh v prehľade:

  1. Odošle sa formulár s method="POST" a enctype="multipart/form-data".
  2. Webový server prijme požiadavku a odovzdá ju PHP, podľa spôsobu prevádzky cez PHP-FPM, mod_php alebo iné rozhranie.
  3. PHP skontroluje limity, napríklad post_max_size, a rozloží obsah podľa oddeľovacieho reťazca, takzvanej boundary.
  4. Bežné polia skončia v $_POST, časti so súbormi sa zapíšu do dočasných súborov a opíšu sa v $_FILES.
  5. Až teraz sa spustí skript, súbor skontroluje a presunie na cieľové miesto.
  6. Na konci požiadavky PHP zmaže všetky dočasné súbory, ktoré sa nepresunuli.

multipart/form-data: štruktúra požiadavky na nahrávanie

Požiadavka na nahrávanie je čistý text s vloženými údajmi súboru. Hlavička Content-Type uvádza boundary a v obsahu tento reťazec oddeľuje jednotlivé časti. Každá časť má vlastné hlavičky s názvom poľa a prípadne názvom súboru. Veľmi skrátený, neškodný príklad:

POST /bewerbung HTTP/1.1
Content-Type: multipart/form-data; boundary=----trenner42

------trenner42
Content-Disposition: form-data; name="vorname"

Erika
------trenner42
Content-Disposition: form-data; name="lebenslauf"; filename="lebenslauf.pdf"
Content-Type: application/pdf

%PDF-1.7 ... Dateiinhalt ...
------trenner42--

Všetky údaje v tomto texte pochádzajú od odosielateľa, vrátane názvu súboru a Content-Type danej časti. PHP ich prevezme do $_FILES, ale nekontroluje ich vierohodnosť.

Pole $_FILES

Pre pole s názvom lebenslauf obsahuje $_FILES['lebenslauf'] podľa príručky PHP tieto kľúče:

Kľúč Obsah Dôveryhodné?
name pôvodný názov súboru u odosielateľa nie
full_path cesta nahlásená prehliadačom, od PHP 8.1.0 nie
type typ MIME podľa prehliadača, PHP ho nekontroluje nie
size veľkosť v bajtoch zisťuje PHP
tmp_name cesta k dočasnému súboru na serveri prideľuje PHP
error chybový kód spracovania nahrávania nastavuje PHP

Pri poliach s hranatými zátvorkami v názve, napríklad bilder[], obsahuje každý kľúč pole s jedným záznamom na súbor. Aplikácia potom prechádza napríklad $_FILES['bilder']['error'] a cez ten istý index pristupuje k tmp_name a name.

Formulár môže pred poľom pre súbor navyše odoslať skryté pole MAX_FILE_SIZE. Podľa príručky je to iba pokyn pre prehliadač, ktorý sa dá ľahko obísť. Spoľahnúť sa môžete výlučne na hranice, ktoré presadzuje server: v PHP, vo webovom serveri a v samotnej aplikácii.

Limity: direktívy php.ini pre nahrávanie

Tieto direktívy riadia spracovanie nahrávania. Štandardné hodnoty pochádzajú z príručky PHP a platia, ak ich nepredefinuje žiadny súbor php.ini.

Direktíva Štandard Zmeniteľná v
file_uploads 1 iba systémová konfigurácia
upload_tmp_dir prázdna (systémový temp) iba systémová konfigurácia
upload_max_filesize 2M php.ini, pool, konfigurácia adresára
post_max_size 8M php.ini, pool, konfigurácia adresára
max_file_uploads 20 php.ini, pool, konfigurácia adresára
enable_post_data_reading 1 php.ini, pool, konfigurácia adresára

post_max_size musí byť väčšie než upload_max_filesize a memory_limit by podľa príručky malo byť spravidla väčšie než post_max_size. Ak do upload_tmp_dir nemožno zapisovať, PHP prejde na temp adresár systému. S open_basedir musí byť temp adresár povolený, inak nahrávanie zlyhá. Praktické hodnoty a ich dôsledky opisuje článok Rozumné obmedzenie post_max_size a upload_max_filesize.

Správne vyhodnotenie chybových kódov

Pole error hovorí, čo sa pri spracovaní stalo. Konštanty siahajú od UPLOAD_ERR_OK (0) cez UPLOAD_ERR_INI_SIZE (1), UPLOAD_ERR_FORM_SIZE (2), UPLOAD_ERR_PARTIAL (3) a UPLOAD_ERR_NO_FILE (4) až po UPLOAD_ERR_NO_TMP_DIR (6), UPLOAD_ERR_CANT_WRITE (7) a UPLOAD_ERR_EXTENSION (8).

<?php
declare(strict_types=1);

$datei = $_FILES['lebenslauf'] ?? null;
if ($datei === null) {
    exit('Keine Upload-Daten, eventuell wurde post_max_size überschritten.');
}

$meldung = match ($datei['error']) {
    UPLOAD_ERR_OK => null,
    UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE => 'Datei zu groß.',
    UPLOAD_ERR_NO_FILE => 'Keine Datei gewählt.',
    default => 'Upload fehlgeschlagen.',
};

if ($meldung === null && is_uploaded_file($datei['tmp_name'])) {
    $ziel = '/srv/app/uploads/' . bin2hex(random_bytes(16)) . '.pdf';
    move_uploaded_file($datei['tmp_name'], $ziel);
}

Príklad ukazuje iba mechaniku. Kontrolu typu súboru, uloženie mimo webrootu a zablokovanie spúšťania skriptov opisuje sprievodca Bezpečná implementácia nahrávania súborov v PHP.

Nahrávanie a PHP2Shell: čo znamenajú prechodné opatrenia

Zraniteľnosti PHP2Shell CVE-2026-109618 a CVE-2026-109619 sa týkajú spracovania v okolí požiadavky v interpreteri PHP. Preto php.net ako prechodné opatrenia uvádza okrem iného post_max_size = 8M (bez nahrávania) alebo 32M (s nahrávaním), upload_max_filesize pod touto hodnotou a session.upload_progress.enabled=0. Tieto hodnoty patria do php.ini, poolu FPM alebo konfigurácie servera, potom sa musia reštartovať všetky workery.

Odborní autori navyše navrhujú blokovať požiadavky multipart/form-data mimo skutočných ciest na nahrávanie na proxy alebo vo WAF. Ide o neoficiálne opatrenie s rizikom, že formuláre prestanú fungovať; zvažovanie opisuje článok Filtrovanie požiadaviek na nahrávanie na okraji. Žiadne z týchto opatrení nenahrádza aktualizáciu na PHP 8.5.12, 8.4.27, 8.3.36 alebo 8.2.35.

Ako PHP SOS konkrétne pomáha?

  • Zisťujeme, ktoré z vašich webov nahrávanie skutočne potrebujú a na akých cestách.
  • Nastavujeme limity a prechodné opatrenia pre každý pool, reštartujeme všetky workery a testujeme formuláre.
  • Kontrolujeme adresáre na nahrávanie, či neobsahujú spustiteľné súbory, a blokujeme spúšťanie skriptov v rámci zabezpečenia servera.
  • Nasadzujeme aktualizáciu PHP a dokumentujeme stav záplat pre každý web.

Časté otázky

Kam PHP ukladá nahrané súbory ako prvé?

Do dočasného adresára. Štandardne je to dočasný adresár systému; pomocou upload_tmp_dir sa dá zmeniť. Ak sa súbor v skripte nepresunie, PHP ho na konci požiadavky zmaže.

Môžem veriť poľu type v $_FILES?

Nie. Typ MIME hlási prehliadač a PHP ho podľa príručky nekontroluje. Aj name a full_path pochádzajú od odosielateľa. Skutočný typ súboru zistíte na strane servera podľa obsahu.

Prečo je $_FILES prázdne, hoci bol súbor odoslaný?

Zvyčajne bola celá požiadavka väčšia než post_max_size. PHP potom úplne vyprázdni $_POST aj $_FILES, bez chybového kódu v poli. Ďalšie príčiny sú chýbajúci enctype vo formulári alebo vypnuté file_uploads.

Pomôže proti PHP2Shell, ak v aplikácii zakážem nahrávanie?

Nie. Spracovanie údajov požiadavky prebieha v PHP skôr, než sa spustí kód aplikácie. Účinná je aktualizácia PHP a reštart všetkých workerov; prísnejšie limity sú iba prechodné opatrenie.

Aký je rozdiel medzi upload_max_filesize a post_max_size?

upload_max_filesize obmedzuje každý jednotlivý súbor, post_max_size celý obsah požiadavky vrátane všetkých súborov a polí. post_max_size preto musí byť väčšie než upload_max_filesize.

Zdroje

Okamžitý kontakt

Každá hodina sa počíta. Napíšte nám hneď.

Stručne opíšte systém, verziu PHP a svoje pozorovanie. Ozveme sa, vyjasníme situáciu a budeme pracovať na diaľku, kým nebude incident uzavretý a zdokumentovaný.

Okamžitá pomoc