Aktuální situace: PHP2Shell. Dvě kritické zranitelnosti PHP (CVSS 9.2) umožňují spustit škodlivý kód bez přihlášení. Záplaty od 21. 10. 2026.Co nyní udělat →

Chyby a výjimky v PHP

PHP zná klasická chybová hlášení i výjimky. Tato stránka vysvětluje hierarchii Throwable, čisté ošetření chyb, bezpečná nastavení pro produkci a opatření PHP2Shell k fatal_error_backtraces.

Stav 5 min čteníZnalosti o PHP

Stručně: PHP hlásí problémy dvěma způsoby: jako klasické chyby, například varování a upozornění, které se řídí pomocí error_reporting, a jako výjimky, které lze zachytit pomocí try a catch. Od PHP 7 vyhazuje mnoho interních chyb také objekt třídy Error; spolu s Exception implementuje rozhraní Throwable. V produkci platí: chyby protokolovat, nikdy je nezobrazovat v prohlížeči. V PHP 8.5 patří kvůli PHP2Shell k přechodným opatřením navíc fatal_error_backtraces=0.

Dva světy: klasické chyby a výjimky

PHP pochází z doby, kdy se chyby vypisovaly hlavně jako hlášení: upozornění (E_NOTICE), varování (E_WARNING), zastaralé funkce (E_DEPRECATED) a fatální chyby (E_ERROR). Mnohá z těchto hlášení nechají skript běžet dál, často s chybnými nebo prázdnými daty.

Výjimky fungují jinak. Přeruší normální průběh a skočí na nejbližší vhodný blok catch. Pokud žádný není, skript skončí. Pro rozhodovatele je rozdíl důležitý: tiché varování může způsobit, že se objednávka uloží neúplně, aniž si toho někdo všimne. Výjimka problém zviditelní a umožní ho ošetřit.

Podceňovaným přínosem klasických hlášení jsou upozornění typu E_DEPRECATED. Oznamují, že jazykový prvek v budoucí verzi PHP zanikne. Kdo je sbírá v logu a pravidelně vyhodnocuje, ví před upgradem, která místa je nutné upravit, a při naléhavé bezpečnostní zranitelnosti nemusí dlouho testovat.

Hierarchie Throwable

Vše, co lze vyhodit pomocí throw a zachytit pomocí catch, implementuje Throwable. Pod ním jsou dvě větve:

Třída Účel Příklady podtříd
Exception očekávatelné chyby aplikace a rozšíření ErrorException, PDOException, vlastní třídy
Error interní chyby PHP TypeError, ValueError, ArgumentCountError, ArithmeticError, DivisionByZeroError, UnhandledMatchError

Vlastní třídy chyb dědí z Exception, ne z Error. Od PHP 8.0 vyhazuje většina interních funkcí při neplatných parametrech TypeError nebo ValueError, místo aby jen vypsala varování. Příkladem je strlen([]).

try, catch a finally v praxi

<?php
declare(strict_types=1);

final class ZahlungFehlgeschlagen extends RuntimeException {}

function bezahlen(Bestellung $b, Zahlungsdienst $dienst, LoggerInterface $log): bool
{
    try {
        $dienst->belasten($b->betrag(), $b->referenz());
        return true;
    } catch (ZahlungFehlgeschlagen $e) {
        $log->warning('Zahlung abgelehnt', ['bestellung' => $b->id(), 'exception' => $e]);
        return false;
    } catch (TimeoutException | VerbindungsFehler) {
        // od PHP 8.0 je proměnná v catch volitelná
        $log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
        return false;
    } finally {
        $dienst->verbindungSchliessen();
    }
}

Několik tříd lze v jednom catch spojit pomocí |. Blok finally proběhne vždy, ať k chybě došlo, nebo ne. Od PHP 8.0 je navíc throw výraz a může stát například za ??: $id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');.

Globální handlery: set_error_handler a set_exception_handler

Dvě funkce zachytí to, co by jinak proklouzlo. set_exception_handler() zaregistruje funkci pro nezachycené objekty Throwable. Podle příručky skript po jejím zavolání skončí; hodí se tedy k protokolování a neutrální chybové stránce, ne k pokračování v práci.

Osvědčil se handler, který zapíše úplnou chybu s časem a náhodným identifikátorem do logu a návštěvníkovi ukáže jen neutrální stránku s tímto identifikátorem. Podpora pak může případ v logu dohledat, aniž by interní podrobnosti pronikly ven.

set_error_handler() zachytává klasické chyby. Příručka ukazuje, jak je převést na ErrorException, aby se varování ošetřovala jako výjimky:

<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
    if (!(error_reporting() & $nr)) {
        return false; // vyloučeno pomocí error_reporting
    }
    if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
        return false; // upozornění na zastaralé neeskalovat
    }
    throw new ErrorException($text, 0, $nr, $datei, $zeile);
});

Fatální chyby, například přetečení paměti, se tímto způsobem zachytit nedají. Co se při přetečení uvnitř děje, vysvětluje stránka memory_limit a Out-of-Memory.

Konfigurace výpisu chyb a protokolování

Nejdůležitější nastavení s výchozími hodnotami podle příručky:

Nastavení Výchozí Doporučení pro produkci
error_reporting E_ALL od PHP 8.0.0 E_ALL
display_errors 1 Off
display_startup_errors 1 od PHP 8.0.0 Off
log_errors 0 On
error_log prázdné (log webového serveru, resp. SAPI) vlastní soubor mimo webroot
fatal_error_backtraces 1, nové v PHP 8.5.0 dočasně 0 (PHP2Shell)

Od PHP 8.2.0 určuje error_log_mode oprávnění k souboru logu, standardně 0644. Pokud logy obsahují osobní údaje nebo cesty, je vhodná přísnější hodnota, aby je ostatní uživatelé na serveru nemohli číst. Pomocí ignore_repeated_errors lze shrnout shodná hlášení ze stejného souboru a řádku, aby smyčka chyb log nezahltila.

Dodávaný php.ini-production už nastavuje display_errors na Off. Podle příručky ini_set('display_errors', ...) za běhu na fatální chyby nepůsobí a syntaktické chyby nastanou dříve, než se vůbec spustí nějaké ini_set(). Tyto hodnoty proto patří do konfigurace serveru. Souvislosti najdete v článku Vypnutí výpisu chyb v produkci; jak vést logy bez úniku dat, popisuje článek Bezpečné logování.

Zpracování chyb a PHP2Shell

Pro PHP 8.5 uvádí php.net jako jedno z přechodných opatření proti PHP2Shell nastavit fatal_error_backtraces=0 a poté PHP restartovat. Ostatní opatření se týkají memory_limit, post_max_size a session.upload_progress.enabled. Žádné z nich nenahrazuje aktualizaci na PHP 8.5.12, 8.4.27, 8.3.36 nebo 8.2.35.

; jen PHP 8.5, v php.ini nebo poolu FPM, poté restartovat všechny workery
fatal_error_backtraces = 0

Chybové logy jsou po PHP2Shell navíc důležitým důkazním prostředkem. Pokud se od 20. 10. 2026 množí chyby paměti nebo ukončení workerů, může to ukazovat na pokusy o útok, ale může jít i o neškodné příčiny. Logy uchovejte a vyhodnoťte je spolu s přístupovými logy, jak popisuje průvodce Vyhodnocení logů webového serveru po útoku.

Jak konkrétně pomáhá PHP SOS?

  • Zkontrolujeme účinná nastavení výpisu chyb a protokolování pro každý web a nastavíme je pro produkci.
  • Nastavíme přechodná opatření PHP2Shell podle verze PHP a restartujeme všechny workery.
  • Zajistíme chybové a přístupové logy od 20. 10. 2026 a vyhodnotíme je z hlediska nápadností.
  • V rámci bezpečnostního monitoringu hlásíme neobvyklé nahromadění chyb, místo aby zapadly v logu.

Časté dotazy

Jaký je rozdíl mezi Error a Exception?

Obě implementují rozhraní Throwable. Exception je určena pro chyby, které aplikace očekává a ošetřuje, například neúspěšné připojení k databázi. Error představuje interní chyby PHP, jako je TypeError nebo dělení nulou.

Má být display_errors v produkci zapnuto?

Ne. Chybová hlášení v prohlížeči prozrazují cesty, dotazy a někdy i přístupové údaje. V produkci patří display_errors na Off a log_errors na On, aby chyby skončily v protokolu, a ne u návštěvníka.

Lze přetečení paměti zachytit pomocí try/catch?

Ne. Pokud skript překročí memory_limit, PHP jej ukončí fatální chybou, kterou nelze zachytit jako výjimku. Objeví se jen v chybovém logu, pokud je aktivní log_errors.

Co je fatal_error_backtraces?

Nastavení, které existuje od PHP 8.5.0 a přidává k fatálním chybám backtrace. Je standardně aktivní. Jako přechodné opatření proti PHP2Shell php.net pro PHP 8.5 uvádí nastavit je na 0 a poté PHP restartovat.

Zdroje

Okamžitý kontakt

Každá hodina se počítá. Napište nám hned.

Stručně popište systém, verzi PHP a pozorování. Ozveme se, vyjasníme situaci a budeme pracovat na dálku, dokud nebude incident uzavřen a zdokumentován.

Okamžitá pomoc