Stručně: Nastavte session.upload_progress.enabled=0 v php.ini, v poolu PHP-FPM nebo v konfiguraci serveru Apache, nikdy pomocí ini_set() ani .user.ini, a poté restartujte všechny workery PHP. Trvalým se opatření stane teprve tehdy, když je hodnota uzamčena proti opětovnému zapnutí, platí v každém provozním režimu a každé nainstalované verzi PHP a po aktualizacích se znovu ověřuje.
Malé nastavení s dvojím účinkem
Málokterému jednotlivému nastavení PHP se dostalo tolik pozornosti. Když php.net 21. října 2026 zveřejnil záplaty proti PHP2Shell, stálo session.upload_progress.enabled=0 na seznamu přechodných opatření. O dva dny později následovalo upozornění k CVE-2026-115560 a doporučená pomoc byla totéž nastavení.
Mnoho správců ho v těch dnech rychle nastavilo. Zda platí všude, je jiná otázka. Typické mezery se vyjmenují snadno: hodnota je jen v konfiguraci CLI, druhá verze PHP byla zapomenuta, nebo hostingový panel soubor při dalším uložení přepsal. Tento článek ukazuje, jak opatření zavést tak, aby platilo i za tři měsíce.
Důležité předem: Vypnutí nenahrazuje aktualizaci PHP. Podle odborných zpráv samotné session.upload_progress.enabled=0 neuzavře obě zranitelnosti PHP2Shell. Čeho se CVE-2026-115560 přesně týká, vysvětluje stránka CVE-2026-115560: upozornění k session upload progress.
Co funkce dělá a kdo ji potřebuje
Session upload progress během nahrávání souboru průběžně zapisuje postup do session, aby aplikace mohla zobrazit ukazatel průběhu. V PHP je funkce standardně zapnutá. Příručka PHP sama upozorňuje, že přitom se názvy souborů a polí dodané odesílatelem dostanou nekontrolovaně do úložiště session, a doporučuje funkci vypnout, pokud ji aplikace nepoužívá.
Zda ji vaše aplikace používá, zjistíte čistě čtecím hledáním v kódu:
# Hledá použití funkce průběhu v kódu aplikace
grep -rn --include="*.php" -e "upload_progress" -e "PHP_SESSION_UPLOAD_PROGRESS" /var/www/
Pokud hledání nic nenajde, můžete funkci vypnout bez znatelných následků. Pokud jsou nálezy, aplikace ztratí jen zobrazení průběhu, ne nahrávání. Moderní formuláře měří průběh většinou stejně v prohlížeči.
Nastavit session.upload_progress.enabled na správném místě
Nastavení má podle příručky PHP režim INI_PERDIR. To znamená: lze ho zadat v php.ini, v konfiguraci serveru, v .htaccess (jen mod_php) a v .user.ini (jen FPM a CGI), ale ne za běhu. php.net vylučuje .user.ini jako místo pro toto opatření. Následující tabulka ukazuje rozumná místa podle provozního režimu.
| Provozní režim | Doporučené místo | Uzamkne proti přepsání? | Poté restartovat |
|---|---|---|---|
| PHP-FPM | soubor poolu s php_admin_flag |
ano | každou službu FPM |
| PHP-FPM | php.ini SAPI FPM | ne, .user.ini by mohl přepsat |
každou službu FPM |
| Apache s mod_php | VirtualHost nebo konfigurace serveru s php_admin_flag |
ano | Apache celý |
| php-cgi, LiteSpeed, FrankenPHP | php.ini příslušného běhového prostředí | ověřit podle uspořádání | všechny procesy běhového prostředí |
| Image Dockeru | vlastní soubor v /usr/local/etc/php/conf.d/ při sestavení |
ano, pokud není povoleno přepsání | kontejner vytvořit znovu |
Obě robustní varianty vypadají takto:
; PHP-FPM, např. /etc/php/8.3/fpm/pool.d/seite1.conf
php_admin_flag[session.upload_progress.enabled] = off
# Apache s mod_php, ve VirtualHost nebo pro celý server
<IfModule php_module>
php_admin_flag session.upload_progress.enabled off
</IfModule>
Navíc se vyplatí zápis v php.ini každého webového SAPI jako základní hodnota. Pak nastavení platí i pro nové pooly, které někdo později založí. Proč php_admin_flag dělá rozdíl, popisuje článek php_admin_value: uzamknutí nastavení proti přepsání.
Ověřit účinnost z webu
Příkazová řádka často čte jiné php.ini než webový server. php -i proto dokazuje málo. Také php-fpm8.3 -i ukazuje jen hodnoty z php.ini, ne zápisy z poolů. Spolehlivý je jen dotaz, který skutečně běží přes pool.
Postupujte takto:
- Restartujte všechny služby PHP, například
systemctl restart php8.3-fpm, nebo Apache u mod_php. Bez restartu běží stará hodnota dál. - Do webrootu umístěte krátký kontrolní soubor s náhodným názvem, který vypíše jen aktuální hodnotu.
- Soubor jednou zavolejte přes skutečnou doménu a zapište výsledek.
- Soubor ihned smažte a krok zopakujte pro každý web a každý pool.
<?php
// Kontrolní soubor: umístit jen krátce, poté ihned smazat
header('Content-Type: text/plain');
echo 'session.upload_progress.enabled = ', var_export(ini_get('session.upload_progress.enabled'), true), "\n";
echo 'PHP ', PHP_VERSION, ' / SAPI ', PHP_SAPI, "\n";
Očekává se prázdná hodnota nebo '0'. Pokud tam stojí '1', vaše nastavení se v tomto poolu neuplatňuje. Po aktualizaci PHP navíc zkontrolujte, zda jsou restartováni všichni workeři, jak je popsáno v článku Restart PHP-FPM a všech workerů.
Kontrolní soubory nikdy nenechávejte ležet. Prozrazují verze a konfiguraci a jsou oblíbeným cílem automatizovaných skenů.
Aby nastavení trvale zůstalo
Většina návratů ke starému stavu nevzniká útočníky, ale provozem. Nový pool se zkopíruje ze staré šablony, aktualizace balíčku vytvoří nové php.ini, nebo někdo v hostingovém panelu přepne verzi PHP. Proti takovým návratům pomáhají pevné návyky.
- Pokrýt všechny verze: Na mnoha serverech běží paralelně několik verzí PHP. Každá má vlastní konfigurační složky a potřebuje zápis.
- Upravit šablony: Šablony poolů, role Ansible, soubory Dockerfile a šablony panelů obsahují hodnotu, aby ji nové weby dědily automaticky.
- Využívat nastavení panelu: V hostingových panelech patří hodnota do dodatečných direktiv, které panel předvídá, jinak další změna ruční práci přepíše.
- Po aktualizacích ověřit: Kontrola z předchozího oddílu patří do kontrolního seznamu každé aktualizace PHP.
- Dokumentovat: Zaznamenat datum, server, pooly a výsledek. To později pomůže vůči vedení, pojišťovně nebo auditorům.
Kdo .user.ini vůbec nepoužívá, může načítání takových souborů úplně vypnout pomocí user_ini.filename = v php.ini. Týká se to ale všech nastavení, která tam aplikace ukládají. Tento krok proto předem otestujte, zejména u CMS, která zapisují vlastní soubory .user.ini.
Ostatní přechodná opatření od php.net, například limity pro post_max_size a limit paměti přes cgroup, jsou souhrnně na stránce Okamžitá opatření, když zatím nemůžete záplatovat. Jak PHP zásadně řadí své úrovně konfigurace, vysvětluje php.ini vysvětleno.
Jak konkrétně pomáhá PHP SOS?
- Zjistit stav: Zmapujeme všechny verze PHP, provozní režimy a pooly na vašich serverech a načteme platné hodnoty z webu.
- Nastavit čistě: Nastavení zapíšeme uzamčené do poolů a konfigurace serveru a kontrolovaně restartujeme všechny workery.
- Otestovat funkci: Formuláře pro nahrávání a správu médií po přechodu zkontrolujeme.
- Zabránit návratům: Šablony, nasazení a nastavení panelů upravíme a stav zdokumentujeme v rámci zpevnění serveru.
Časté dotazy
Proč session.upload_progress.enabled=0 nefunguje přes ini_set()?
Podle příručky PHP patří nastavení do režimu INI_PERDIR. Proto ho nelze za běhu měnit pomocí ini_set(). php.net uvádí jako správná místa php.ini, pool FPM nebo konfiguraci serveru a .user.ini výslovně vylučuje.
Funguje nahrávání souborů i po vypnutí?
Ano. Vypne se jen hlášení průběhu, které PHP během nahrávání zapisuje do session. Samotné nahrávání běží dál. Dotčeny jsou jen aplikace, které svůj ukazatel průběhu staví právě na této funkci PHP.
Může aplikace funkci znovu zapnout?
Přes soubor .htaccess u mod_php nebo .user.ini u PHP-FPM je to v zásadě možné, dokud hodnota není uzamčena. Pomocí php_admin_flag v poolu nebo v konfiguraci Apache tomu zabráníte.
Musím hodnotu po příští aktualizaci PHP vrátit zpět?
Ne, není to nutné. Většina aplikací funkci nepotřebuje a příručka PHP sama radí ji v takových případech vypnout. Po každé aktualizaci jen ověřte, zda hodnota stále platí.