Stručně: PHP CLI (Command Line Interface) je varianta PHP pro příkazovou řádku. Spouští skripty bez webového serveru, například pro úlohy cron, Composer nebo údržbu. Má vlastní výchozí hodnoty, často vlastní php.ini a někdy dokonce jinou verzi než web. Proto php -v není spolehlivým důkazem, že je web po PHP2Shell záplatován.
Co je PHP CLI?
Příručka PHP uvádí dvě hlavní oblasti nasazení PHP: skripty pro weby a skripty v příkazové řádce. Pro to druhé existuje samostatné SAPI s názvem cli. Nepotřebuje webový server ani prohlížeč, jen interpret PHP. Podle příručky se hodí především pro úlohy, které pravidelně běží přes cron v Linuxu nebo přes plánovač úloh ve Windows.
Typické příklady z firemní praxe: noční importy v e-shopu, odesílání newsletterů, čištění cache, aktualizace přes Composer nebo nástroje příkazové řádky CMS jako WP-CLI či konzole Symfony. Ve Windows se soubor jmenuje php.exe, varianta CGI php-cgi.exe.
Na rozdíl od PHP-FPM není CLI služba. Každé volání spouští nový proces, podle příručky znovu načítá konfiguraci a končí, když je skript hotový. Restart po aktualizaci proto není nutný. Výjimkou jsou dlouho běžící procesy spuštěné přes CLI, například workery front frameworků nebo démony pod systemd či Supervisor. Běží dny s jednou načteným interpretem a po aktualizaci PHP je nutné je restartovat stejně jako webové workery.
Pro jednatele a vedení projektů to znamená: i úlohy na pozadí patří do inventáře a do každého plánu aktualizací.
Čím se CLI liší od webové verze?
CLI podle příručky přepisuje některá nastavení napevno. Nelze je změnit přes php.ini, jen za běhu pomocí ini_set():
| Direktiva | Hodnota v CLI | Zdůvodnění podle příručky |
|---|---|---|
html_errors |
vypnuto | značky HTML v terminálu překážejí |
implicit_flush |
zapnuto | výstupy se mají zobrazit okamžitě |
max_execution_time |
0 (neomezeně) | skripty v příkazové řádce často běží dlouho |
register_argc_argv |
zapnuto | skripty vždy dostanou $argc a $argv |
output_buffering |
vypnuto | pevně dané, funkce vyrovnávací paměti zůstávají použitelné |
max_input_time |
vypnuto | CLI nezná GET, POST ani nahrávání |
Další rozdíl: CLI nepřechází do adresáře skriptu. Kdo zavolá php -f ordner/skript.php z /tmp, pracuje dál v /tmp. Relativní cesty v úlohách cron jsou proto častým zdrojem chyb.
Malý skript, který má běžet jen v příkazové řádce:
<?php
if (PHP_SAPI !== 'cli') {
http_response_code(403);
exit('Nur für die Kommandozeile.');
}
$tage = (int) ($argv[1] ?? 30);
$grenze = time() - $tage * 86400;
$alt = 0;
foreach (glob(__DIR__ . '/cache/*.tmp') ?: [] as $datei) {
if (filemtime($datei) < $grenze) { $alt++; }
}
fwrite(STDOUT, "Dateien älter als $tage Tage: $alt\n");
Kontrola PHP_SAPI zabraňuje tomu, aby se skript údržby spustil přes prohlížeč, pokud omylem leží ve webovém adresáři. Příručka výslovně radí kontrolovat SAPI takto, místo aby se spoléhalo na přítomnost $argv.
Nejdůležitější volby PHP CLI
Následující volby pocházejí z přehledu voleb v příručce PHP a jsou pro správce zvlášť užitečné:
php -vukazuje číslo verze CLI.php --iniukazuje, které konfigurační soubory se načítají.php -mvypisuje zkompilované a načtené moduly.php -ivoláphpinfo()a vypíše výsledek jako text.php -l datei.phpkontroluje jen syntaxi (lint). Od PHP 8.3 i pro více souborů najednou.php -r 'code'provede kód přímo, bez<?php.php -d name=wertnastaví položku INI pro toto volání.php -nignoruje php.ini úplně.php --ri nameukazuje konfiguraci rozšíření.
php --ini
php -m | grep -i -E "opcache|sodium|pdo"
php --ri session | grep upload_progress
php -l src/Controller.php src/Model.php
Vestavěný webový server: jen pro vývoj
Příkazem php -S localhost:8000 spustí CLI malý webový server. Příklad výstupu v příručce uvádí jako výchozí bod PHP 5.4.0. Příručka je jednoznačná: server slouží pro vývoj, není plnohodnotným webovým serverem a neměl by běžet ve veřejných sítích ani v produkci. Pokud na serveru běží trvale a je dostupný zvenčí, je to nález, který byste měli odstranit.
CLI, cron a bezpečnost po PHP2Shell
Známá hlášení o PHP2Shell uvádějí jako postižené provozní režimy PHP-FPM, mod_php, php-cgi, FrankenPHP a LiteSpeed. CLI nezpracovává požadavky ze sítě. Pro bezpečnost je přesto důležité ve třech ohledech:
- Chybný důkaz:
php -vukazuje verzi CLI. Web může používat jinou verzi a backporty distribucí často zobrazené číslo nemění. Jak stav správně doložit, popisuje článek Kontrola verze PHP a stavu záplat a Proč php -v ukazuje stejné číslo. - Perzistence přes cron: Útočníci po průniku rádi využívají úlohy cron, které pravidelně spouštějí skript PHP. Pokyny k vyhledávání nabízí článek Rozpoznání skrytých úloh cron jako zadních vrátek.
- Stejný balíček: CLI pochází většinou ze stejného zdroje balíčků jako PHP-FPM a patří do aktualizace.
Jak konkrétně pomáhá PHP SOS?
- Porovnat verze: Porovnáme stav CLI a webu a doložíme, kterou verzi váš web skutečně vydává.
- Zkontrolovat úlohy cron: Vypíšeme všechny plánované úlohy PHP všech uživatelů a přiřadíme je k aplikacím.
- Zabezpečit údržbu: Skripty údržby přesuneme z webového adresáře a nastavíme kontroly SAPI.
- Pečovat trvale: V rámci smlouvy o bezpečnostní údržbě udržujeme CLI, webové SAPI a úlohy cron společně aktuální.
Časté dotazy
Ukazuje php -v verzi mého webu?
Ne nutně. php -v ukazuje verzi varianty pro příkazovou řádku. Web může běžet přes jinou verzi PHP-FPM nebo modul Apache. Pro web je rozhodující stav webového SAPI, který zjistíte přes službu nebo krátce nahraný kontrolní soubor.
Proč skripty CLI běží neomezeně dlouho?
Podle příručky PHP nastavuje CLI max_execution_time pevně na 0, tedy neomezeně, protože skripty v příkazové řádce často vykonávají dlouhé úlohy. Dobu běhu lze omezit samotným skriptem nebo nástroji jako timeout.
Smím vestavěný webový server php -S používat v produkci?
Ne. Příručka jej popisuje jako pomůcku pro vývoj, nikoli jako plnohodnotný webový server, a odrazuje od jeho použití ve veřejných sítích a v produkci. Pro ostré systémy patří před PHP-FPM Apache, Nginx nebo LiteSpeed.
Je OPcache v příkazové řádce aktivní?
Standardně ne. opcache.enable_cli je podle příručky nastaveno na 0. U krátkých skriptů cache stejně mnoho nepřináší, protože každé volání je nový proces.