Stručně: php_admin_value a php_admin_flag nastavují hodnoty PHP v poolu PHP-FPM nebo v konfiguraci Apache tak, aby je aplikace nemohly změnit ani pomocí ini_set(), ani pomocí .htaccess. Přesně to php.net pro přechodná opatření k PHP2Shell požaduje, například u memory_limit=-1. Po nastavení se musí služba restartovat a hodnota by se měla ověřit z webu.
Proč „nastaveno“ neznamená „uzamčeno“
Ve dnech po 21. říjnu 2026 zapsalo mnoho správců přechodná opatření od php.net do svého php.ini. Jeden detail doporučení přitom často zapadl: memory_limit=-1 má být nastaveno tak, aby ho aplikace nemohly přepsat. php.net k tomu výslovně uvádí php_admin_value v poolu FPM nebo v konfiguraci Apache.
Důvod je prostý. Mnoho CMS, e-shopů a frameworků nastavuje své vlastní hodnoty, například vyšší limit paměti pro importy. Pokud je hodnota jen v php.ini, aplikace ji při dalším volání přepíše. Ochranné opatření pak existuje na papíře, ne v běžícím procesu.
Netýká se to jen PHP2Shell. Každé zpevnění, od vypnutých chybových výstupů po limity nahrávání, je jen tak silné jako jeho nejslabší úroveň.
Kdo smí nastavení PHP vůbec měnit
PHP zná čtyři režimy změny. Každé nastavení má jeden z nich a určuje, na kterých místech lze nastavit. Významy pocházejí z příručky PHP.
| Režim | Kde lze hodnotu nastavit | Příklady |
|---|---|---|
INI_USER |
ve skriptu pomocí ini_set() a v .user.ini |
několik hodnot za běhu |
INI_PERDIR |
php.ini, .htaccess, httpd.conf, .user.ini |
post_max_size, session.upload_progress.enabled |
INI_SYSTEM |
jen php.ini nebo httpd.conf |
file_uploads, disable_functions |
INI_ALL |
všude, i pomocí ini_set() |
memory_limit, display_errors, open_basedir |
Nebezpečné jsou především hodnoty INI_ALL: lze je změnit z libovolného skriptu. Hodnoty INI_PERDIR sice nelze měnit pomocí ini_set(), ale přes .htaccess u mod_php nebo .user.ini u PHP-FPM ano. Kdo má právo zápisu do webrootu, tedy i vložený kód, může takové soubory vytvořit.
php_admin_value v poolu FPM a v Apache
U PHP-FPM jsou hodnoty v souboru poolu. Příručka PHP uvádí: hodnoty nastavené pomocí php_admin_value a php_admin_flag nelze přepsat pomocí ini_set(). Pro hodnoty zapnuto-vypnuto použijte php_admin_flag, pro všechny ostatní php_admin_value.
; /etc/php/8.3/fpm/pool.d/seite1.conf (výňatek)
[seite1]
user = seite1
group = seite1
listen = /run/php/seite1.sock
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 24M
php_admin_flag[session.upload_progress.enabled] = off
php_admin_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php/seite1-fehler.log
php_admin_value[open_basedir] = /var/www/seite1/:/tmp/seite1/
memory_limit=-1 patří podle php.net do konfigurace jen společně s limitem paměti přes kontejner nebo cgroup. Jak to zvládnout pomocí systemd, je v článku Nastavení limitů paměti pomocí systemd a cgroups.
U Apache s mod_php patří direktivy do konfigurace serveru nebo do VirtualHost. Podle příručky PHP nejsou v .htaccess povoleny a po nastavení je nemůže změnit ani .htaccess, ani ini_set().
<VirtualHost *:443>
ServerName www.example.de
DocumentRoot /var/www/seite1/public
<IfModule php_module>
php_admin_value memory_limit -1
php_admin_value post_max_size 32M
php_admin_value upload_max_filesize 24M
php_admin_flag session.upload_progress.enabled off
php_admin_flag display_errors off
</IfModule>
</VirtualHost>
Dvě jemnosti z příručky: Chcete-li dříve nastavenou hodnotu smazat, použijte jako hodnotu none. A konstanty PHP jako E_ALL nemají v konfiguraci Apache žádný význam; pro error_reporting tam musíte zadat číselnou hodnotu.
Které hodnoty uzamknout
Ne každé nastavení musí být uzamčeno. Smysl to má u všeho, co se týká bezpečnosti nebo slouží jako přechodné opatření:
- Přechodné hodnoty php.net k PHP2Shell:
memory_limit,post_max_size,upload_max_filesize,session.upload_progress.enableda u PHP 8.5fatal_error_backtraces. - Chybový výstup a protokolování:
display_errors,display_startup_errors,log_errors,error_log. - Přístup k souborům a izolace:
open_basedir,upload_tmp_dir,session.save_path. - Síťové přístupy z PHP:
allow_url_includea, pokud ji aplikace nepotřebuje,allow_url_fopen. - Zakázané funkce přes
disable_functions, které v poolu podle příručky doplňují seznam z php.ini, nenahrazují ho. Podrobnosti v průvodci Správné použití disable_functions.
U session.upload_progress.enabled je uzamčení zvlášť důležité, protože by hodnotu jinak šlo přes .user.ini znovu zapnout. Více v článku Vypnutí session.upload_progress: správně a trvale.
Ověřit, že uzamčení platí
Po každé změně službu restartujte a hodnotu ověřte z webu. Krátký, ihned smazaný kontrolní soubor ukáže, zda pool hodnotu drží, i když ji aplikace chce změnit:
<?php
// Kontrolní soubor: krátce umístit, jednou zavolat přes doménu, ihned smazat
header('Content-Type: text/plain');
$vorher = ini_get('memory_limit');
$versuch = @ini_set('memory_limit', '256M');
echo "memory_limit: $vorher\n";
echo 'Änderung per ini_set() ', ($versuch === false ? 'blockiert' : 'MÖGLICH'), "\n";
Očekává se -1 a „blockiert“. Pokud je výstup „MÖGLICH“, hodnota není nastavena přes php_admin_value nebo služba ještě nebyla restartována. Kontrolu zopakujte pro každý pool a každou verzi PHP.
Uzamčené hodnoty vedete centrálně, například v šabloně poolu nebo ve své správě konfigurace. Hostingové panely někdy ručně upravené soubory poolů při dalším uložení přepíší; tam patří hodnoty do polí, která panel předvídá.
Jak PHP své úrovně konfigurace celkově řadí, vysvětluje php.ini vysvětleno: struktura, úrovně a přednost. Úplná přechodná opatření jsou na stránce Okamžitá opatření, když zatím nemůžete záplatovat.
Závěr: teprve uzamčeno je skutečně nastaveno
Přechodná opatření php.net k PHP2Shell přivedla do povědomí rozdíl, který se dříve často přehlížel: hodnota v php.ini je u mnoha nastavení jen návrh, hodnota v php_admin_value je předpis. U pohodlných hodnot, jako je časové pásmo, je rozdíl nepodstatný. U bezpečnostních nastavení a přechodných opatření rozhoduje o tom, zda opatření v běžícím provozu vůbec zabírá.
Pracnost je přehledná: hrstka řádků na pool nebo VirtualHost, restart, krátká kontrola. Udržujte seznam uzamčených hodnot krátký a odůvodněný, aby vývojáři chápali, proč jejich aplikace nesmí hodnotu změnit. A seznam udržujte ve svých šablonách, aby ho nové weby dědily automaticky.
Jak konkrétně pomáhá PHP SOS?
- Načíst úrovně: Pro každý web zjistíme, které hodnoty z php.ini, poolu, Apache,
.htaccessnebo.user.iniskutečně platí. - Nastavit uzamčení: Bezpečnostně relevantní hodnoty a přechodná opatření k PHP2Shell zapíšeme jako
php_admin_valuepopř.php_admin_flaga restartujeme služby. - Otestovat aplikaci: Ověříme, zda aplikace s uzamčenými hodnotami běží bez chyb, a vyhodnotíme chybový log.
- Udržovat šablony: V rámci zpevnění serveru převezmeme hodnoty do šablon poolů a dokumentace.
Časté dotazy
Jaký je rozdíl mezi php_value a php_admin_value?
Obojí nastaví hodnotu PHP. Hodnoty z php_value může aplikace později změnit, například pomocí ini_set() nebo .htaccess. Hodnoty z php_admin_value a php_admin_flag jsou podle příručky PHP uzamčeny pro ini_set(), u Apache i pro .htaccess.
Mohu php_admin_value zapsat do souboru .htaccess?
Ne. Podle příručky PHP není php_admin_value v souborech .htaccess povoleno. Patří do konfigurace serveru Apache nebo do VirtualHost, u PHP-FPM do souboru poolu.
Co se stane, když chce aplikace změnit uzamčenou hodnotu?
Volání ini_set() selže a vrátí false, uzamčená hodnota zůstane. Dobře naprogramované aplikace si s tím poradí. Po přechodu přesto zkontrolujte chybový log a nejdůležitější funkce.
Musím po změně v poolu restartovat?
Ano. PHP-FPM čte soubory poolů při startu nebo při opětovném načtení služby. U Apache s mod_php platí totéž pro konfiguraci serveru. Bez restartu běží stará hodnota dál.
Lze disable_functions v poolu rozšířit?
Ano, s jednou zvláštností: podle příručky PHP disable_functions v poolu FPM hodnoty z php.ini nepřepisuje, ale doplňuje. Pool tedy může zakázat další funkce, ale žádnou povolit.