Lühidalt: PHP teatab probleemidest kahel viisil: klassikaliste vigadena, nagu hoiatused ja märkused, mida juhib error_reporting, ning erandite (Exceptions) kujul, mida saab püüda kinni try ja catch abil. Alates PHP 7-st viskavad ka paljud sisemised vead klassi Error objekti; koos klassiga Exception realiseerib see liidese Throwable. Tootmises kehtib: vead logida, mitte kunagi brauseris näidata. PHP 8.5 puhul kuulub PHP2Shelli tõttu ajutiste meetmete hulka ka fatal_error_backtraces=0.
Kaks maailma: klassikalised vead ja erandid
PHP pärineb ajast, mil vigu väljastati peamiselt teadetena: märkused (E_NOTICE), hoiatused (E_WARNING), iganenud funktsioonid (E_DEPRECATED) ja fataalsed vead (E_ERROR). Paljud neist teadetest lasevad skriptil edasi töötada, sageli vigaste või tühjade andmetega.
Erandid töötavad teisiti. Need katkestavad tavapärase kulgemise ja hüppavad järgmisse sobivasse catch-plokki. Kui sellist ei leita, skript lõpeb. Otsustajale on vahe oluline: vaikne hoiatus võib viia selleni, et tellimus salvestatakse poolikuna, ilma et keegi seda märkaks. Erand teeb probleemi nähtavaks ja käsitletavaks.
Klassikaliste teadete alahinnatud kasu on tüüpi E_DEPRECATED märkused. Need teatavad, et mõni keelevahend langeb tulevases PHP versioonis ära. Kes neid logisse kogub ja korrapäraselt hindab, teab enne uuendust, millised kohad vajavad kohandamist, ega pea kiireloomulise turvaaugu korral kaua testima.
Throwable-hierarhia
Kõik, mida saab throw-ga visata ja catch-iga kinni püüda, realiseerib Throwable. Selle all on kaks haru:
| Klass | Otstarve | Näiteid alamklassidest |
|---|---|---|
Exception |
rakenduse ja laienduste oodatavad vead | ErrorException, PDOException, oma klassid |
Error |
PHP sisemised vead | TypeError, ValueError, ArgumentCountError, ArithmeticError, DivisionByZeroError, UnhandledMatchError |
Oma veaklassid tuletatakse klassist Exception, mitte Error-ist. Alates PHP 8.0-st viskavad enamik sisemisi funktsioone kehtetute parameetrite korral vea TypeError või ValueError, selle asemel et ainult hoiatust väljastada. strlen([]) on üks selline juhtum.
try, catch ja finally praktikas
<?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) {
// alates PHP 8.0-st on muutuja catch'is valikuline
$log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
return false;
} finally {
$dienst->verbindungSchliessen();
}
}
Mitu klassi saab ühes catch-is kokku võtta märgiga |. Plokk finally käivitub alati, olenemata sellest, kas viga tekkis või mitte. Alates PHP 8.0-st on throw lisaks avaldis ja võib seista näiteks ?? järel: $id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');.
Globaalsed käsitlejad: set_error_handler ja set_exception_handler
Kaks funktsiooni püüavad kinni selle, mis muidu läbi lipsaks. set_exception_handler() registreerib funktsiooni kinnipüüdmata Throwable'ite jaoks. Käsiraamatu järgi lõpeb skript pärast selle väljakutsumist; see sobib seega logimiseks ja neutraalseks vealeheks, mitte edasitöötamiseks.
Heaks on osutunud käsitleja, mis kirjutab logisse kogu vea koos ajahetke ja juhusliku tunnusega ning näitab külastajale ainult neutraalset lehte selle tunnusega. Tugi leiab juhtumi siis logist üles, ilma et sisemised üksikasjad välja satuksid.
set_error_handler() püüab kinni klassikalised vead. Käsiraamat näitab, kuidas need muuta ErrorException'iks, et hoiatusi käsitletaks nagu erandeid:
<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
if (!(error_reporting() & $nr)) {
return false; // error_reporting on välja jätnud
}
if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
return false; // iganenu märkusi mitte eskaleerida
}
throw new ErrorException($text, 0, $nr, $datei, $zeile);
});
Fataalseid vigu, nagu mälu ülekäitumine, sel viisil kinni püüda ei saa. Mis ülekäitumisel sees toimub, selgitab leht memory_limit ja Out-of-Memory.
Veateadete ja logimise seadistamine
Olulisimad sätted vaikeväärtustega käsiraamatu järgi:
| Säte | Vaikeväärtus | Soovitus tootmiseks |
|---|---|---|
error_reporting |
E_ALL alates PHP 8.0.0-st |
E_ALL |
display_errors |
1 |
Off |
display_startup_errors |
1 alates PHP 8.0.0-st |
Off |
log_errors |
0 |
On |
error_log |
tühi (veebiserveri või SAPI logi) | oma fail väljaspool veebijuurt |
fatal_error_backtraces |
1, uus PHP 8.5.0-s |
ajutiselt 0 (PHP2Shell) |
Alates PHP 8.2.0-st määrab error_log_mode logifaili õigused, vaikimisi 0644. Kui logid sisaldavad isikuandmeid või teekondi, on mõistlik rangem väärtus, et teised serveri kasutajad neid lugeda ei saaks. Sättega ignore_repeated_errors saab samast failist ja reast pärinevaid identseid teateid kokku võtta, et veatsükkel logi ei ujutaks üle.
Kaasasolev php.ini-production seab display_errors juba väärtusele Off. Käsiraamatu järgi ei mõjuta ini_set('display_errors', ...) täitmisajal fataalseid vigu ning süntaksivead tekivad enne, kui mingi ini_set() üldse käivitub. Need väärtused kuuluvad seetõttu serveri seadistusse. Taustu leiate artiklist Veateadete väljalülitamine tootmises; kuidas logisid ilma andmelekketa pidada, artiklist Turvaline logimine.
Veakäsitlus ja PHP2Shell
PHP 8.5 jaoks nimetab php.net üheks PHP2Shelli vastaseks ajutiseks meetmeks seada fatal_error_backtraces=0 ja käivitada PHP seejärel uuesti. Ülejäänud meetmed puudutavad sätteid memory_limit, post_max_size ja session.upload_progress.enabled. Ükski neist ei asenda uuendust versioonile PHP 8.5.12, 8.4.27, 8.3.36 või 8.2.35.
; ainult PHP 8.5, php.ini-s või FPM-poolis, seejärel kõik workerid uuesti käivitada
fatal_error_backtraces = 0
Vealogid on pärast PHP2Shelli ka oluline tõendusmaterjal. Kui alates 20.10.2026 tekib rohkem mäluvigu või katkenud workereid, võib see viidata ründekatsetele, kuid põhjused võivad olla ka kahjutud. Säilitage logid ja hinnake neid koos ligipääsulogidega, nagu on kirjeldatud juhendis Veebiserveri logide hindamine pärast rünnakut.
Kuidas PHP SOS konkreetselt aitab?
- Kontrollime veateadete ja logimise toimivaid sätteid iga veebisaidi kohta ning seame need tootmiseks sobivaks.
- Seame PHP2Shelli ajutised meetmed PHP versioonile vastavalt ja käivitame kõik workerid uuesti.
- Kindlustame vea- ja ligipääsulogid alates 20.10.2026 ning hindame neid kõrvalekallete suhtes.
- Turvaseire raames teatame ebatavalisest vigade kuhjumisest, selle asemel et lasta sel logis hääbuda.
Korduma kippuvad küsimused
Mis vahe on Error'il ja Exception'il?
Mõlemad realiseerivad liidese Throwable. Exception on mõeldud vigade jaoks, mida rakendus ootab ja käsitleb, näiteks ebaõnnestunud andmebaasiühendus. Error tähistab PHP sisemisi vigu, näiteks TypeError või nulliga jagamine.
Kas display_errors peaks tootmises olema sees?
Ei. Veateated brauseris reedavad teekondi, päringuid ja vahel ligipääsuandmeid. Tootmises peab display_errors olema Off ja log_errors On, et vead jõuaksid logisse, mitte külastajani.
Kas mälu ülekäitumist saab try/catch'iga kinni püüda?
Ei. Kui skript ületab memory_limit'i, lõpetab PHP selle fataalse veaga, mida ei saa erandina kinni püüda. See ilmub ainult vealogisse, kui log_errors on aktiivne.
Mis on fatal_error_backtraces?
See on säte, mis on olemas alates PHP 8.5.0-st ja lisab fataalsetele vigadele backtrace'i. Vaikimisi on see aktiivne. Ajutise meetmena PHP2Shelli vastu nimetab php.net PHP 8.5 jaoks selle seadmist väärtusele 0 ja PHP seejärel uuesti käivitamist.