Stručne: PHP hlási problémy dvoma spôsobmi: ako klasické chyby, napríklad varovania a upozornenia, ktoré sa riadia cez error_reporting, a ako výnimky, ktoré sa dajú zachytiť pomocou try a catch. Od PHP 7 vyhadzuje objekt triedy Error aj mnoho interných chýb; spolu s Exception implementuje rozhranie Throwable. V produkcii platí: chyby zapisovať do logu, nikdy ich nezobrazovať v prehliadači. Na PHP 8.5 patrí kvôli PHP2Shell k prechodným opatreniam aj fatal_error_backtraces=0.
Dva svety: klasické chyby a výnimky
PHP pochádza z čias, keď sa chyby vypisovali predovšetkým ako hlásenie: upozornenia (E_NOTICE), varovania (E_WARNING), zastarané funkcie (E_DEPRECATED) a fatálne chyby (E_ERROR). Mnohé z týchto hlásení nechajú skript bežať ďalej, často s nesprávnymi alebo prázdnymi údajmi.
Výnimky fungujú inak. Prerušia normálny priebeh a preskočia na najbližší vhodný blok catch. Ak sa žiadny nenájde, skript skončí. Pre rozhodovateľov je rozdiel dôležitý: tiché varovanie môže viesť k tomu, že sa objednávka uloží neúplne, bez toho, aby si to niekto všimol. Výnimka robí problém viditeľným a ošetriteľným.
Nedocenený prínos klasických hlásení sú upozornenia typu E_DEPRECATED. Oznamujú, že jazykový prostriedok v budúcej verzii PHP zanikne. Kto ich zbiera v logu a pravidelne vyhodnocuje, vie pred upgradom, ktoré miesta treba upraviť, a pri naliehavej bezpečnostnej zraniteľnosti nemusí najprv dlho testovať.
Hierarchia Throwable
Všetko, čo sa dá vyhodiť pomocou throw a zachytiť pomocou catch, implementuje Throwable. Pod ním sú dve vetvy:
| Trieda | Účel | Príklady podtried |
|---|---|---|
Exception |
očakávateľné chyby aplikácie a rozšírení | ErrorException, PDOException, vlastné triedy |
Error |
interné chyby PHP | TypeError, ValueError, ArgumentCountError, ArithmeticError, DivisionByZeroError, UnhandledMatchError |
Vlastné triedy chýb sa odvodzujú od Exception, nie od Error. Od PHP 8.0 vyhadzuje väčšina interných funkcií pri neplatných parametroch TypeError alebo ValueError namiesto toho, aby vypísala len varovanie. Takým prípadom 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 premenná v catch voliteľná
$log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
return false;
} finally {
$dienst->verbindungSchliessen();
}
}
Viaceré triedy možno v jednom catch zlúčiť pomocou |. Blok finally sa vykoná vždy, či už nastala chyba, alebo nie. Od PHP 8.0 je throw navyše výraz a môže stáť napríklad za ??: $id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');.
Globálne handlery: set_error_handler a set_exception_handler
Dve funkcie zachytia to, čo by inak prešlo. set_exception_handler() zaregistruje funkciu pre nezachytené Throwable. Podľa príručky skript po jej zavolaní skončí; hodí sa teda na zapisovanie do logu a neutrálnu chybovú stránku, nie na pokračovanie v práci.
Osvedčil sa handler, ktorý do logu zapíše celú chybu s časom a náhodným identifikátorom a návštevníkovi ukáže iba neutrálnu stránku s týmto identifikátorom. Podpora potom prípad v logu nájde bez toho, aby unikli interné podrobnosti.
set_error_handler() zachytáva klasické chyby. Príručka ukazuje, ako ich premeniť na ErrorException, aby sa varovania ošetrovali ako výnimky:
<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
if (!(error_reporting() & $nr)) {
return false; // vylúčené cez error_reporting
}
if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
return false; // upozornenia na zastarané veci neeskalovať
}
throw new ErrorException($text, 0, $nr, $datei, $zeile);
});
Fatálne chyby, ako pretečenie pamäte, sa týmto spôsobom zachytiť nedajú. Čo sa pri pretečení deje vo vnútri, vysvetľuje stránka memory_limit a Out-of-Memory.
Konfigurácia výpisu chýb a zapisovania do logu
Najdôležitejšie nastavenia s ich štandardnými hodnotami podľa príručky:
| Nastavenie | Štandard | Odporúčanie pre produkciu |
|---|---|---|
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ázdne (log webového servera, resp. SAPI) | vlastný súbor mimo webrootu |
fatal_error_backtraces |
1, novinka v PHP 8.5.0 |
dočasne 0 (PHP2Shell) |
Od PHP 8.2.0 určuje error_log_mode prístupové práva súboru logu, štandardne 0644. Ak logy obsahujú osobné údaje alebo cesty, je vhodná prísnejšia hodnota, aby ich ostatní používatelia na serveri nemohli čítať. Pomocou ignore_repeated_errors sa dajú zlúčiť rovnaké hlásenia z toho istého súboru a riadku, aby slučka chýb nezaplavila log.
Dodávaný php.ini-production už nastavuje display_errors na Off. Podľa príručky ini_set('display_errors', ...) za behu nepôsobí na fatálne chyby a syntaktické chyby nastanú skôr, než sa vôbec vykoná nejaké ini_set(). Tieto hodnoty preto patria do konfigurácie servera. Súvislosti sú v článku Vypnutie výpisu chýb v produkcii; ako viesť logy bez úniku údajov, v článku Bezpečné zapisovanie do logov.
Ošetrenie chýb a PHP2Shell
Pre PHP 8.5 uvádza php.net ako jedno z prechodných opatrení proti PHP2Shell nastaviť fatal_error_backtraces=0 a potom PHP reštartovať. Ostatné opatrenia sa týkajú memory_limit, post_max_size a session.upload_progress.enabled. Žiadne z nich nenahrádza aktualizáciu na PHP 8.5.12, 8.4.27, 8.3.36 alebo 8.2.35.
; iba PHP 8.5, v php.ini alebo v poole FPM, potom reštartovať všetky workery
fatal_error_backtraces = 0
Logy chýb sú po PHP2Shell navyše dôležitým dôkazným materiálom. Ak sa od 20. 10. 2026 množia chyby pamäte alebo prerušené workery, môže to naznačovať pokusy o útok, ale môže to mať aj neškodné príčiny. Logy uchovajte a vyhodnoťte spolu s prístupovými logmi, ako opisuje sprievodca Vyhodnotenie logov webového servera po útoku.
Ako PHP SOS konkrétne pomáha?
- Kontrolujeme účinné nastavenia výpisu chýb a zapisovania do logu pre každý web a nastavujeme ich vhodne pre produkciu.
- Prechodné opatrenia PHP2Shell nastavujeme podľa verzie PHP a reštartujeme všetky workery.
- Zálohujeme logy chýb a prístupov od 20. 10. 2026 a vyhodnocujeme ich na nezrovnalosti.
- V rámci monitoringu bezpečnosti hlásime nezvyčajné nahromadenie chýb, namiesto toho, aby sa stratilo v logu.
Časté otázky
Aký je rozdiel medzi Error a Exception?
Obe implementujú rozhranie Throwable. Exception je určená pre chyby, ktoré aplikácia očakáva a ošetruje, napríklad neúspešné pripojenie k databáze. Error predstavuje interné chyby PHP, ako TypeError alebo delenie nulou.
Má byť display_errors v produkcii zapnuté?
Nie. Chybové hlásenia v prehliadači prezrádzajú cesty, dotazy a niekedy aj prístupové údaje. V produkcii patrí display_errors na Off a log_errors na On, aby chyby skončili v logu, a nie u návštevníka.
Dá sa pretečenie pamäte zachytiť pomocou try/catch?
Nie. Ak skript prekročí memory_limit, PHP ho ukončí fatálnou chybou, ktorú nemožno zachytiť ako výnimku. Objaví sa iba v logu chýb, pokiaľ je log_errors aktívne.
Čo je fatal_error_backtraces?
Nastavenie, ktoré existuje od PHP 8.5.0 a k fatálnym chybám pridáva backtrace. Je štandardne aktívne. Ako prechodné opatrenie proti PHP2Shell php.net pre PHP 8.5 uvádza nastaviť ho na 0 a potom PHP reštartovať.