Īsi: PHP ziņo par problēmām divējādi: kā klasiskas kļūdas, piemēram, brīdinājumus un piezīmes, ko vada ar error_reporting, un kā izņēmumus, ko var noķert ar try un catch. Kopš PHP 7 daudzas iekšējās kļūdas met klases Error objektu; kopā ar Exception tas ievieš interfeisu Throwable. Produkcijā spēkā: kļūdas reģistrēt žurnālā, nekad nerādīt pārlūkprogrammā. PHP 8.5 gadījumā PHP2Shell dēļ pie pagaidu pasākumiem pieder arī fatal_error_backtraces=0.
Divas pasaules: klasiskās kļūdas un izņēmumi
PHP nāk no laikiem, kad kļūdas galvenokārt tika izvadītas kā ziņojums: piezīmes (E_NOTICE), brīdinājumi (E_WARNING), novecojušas funkcijas (E_DEPRECATED) un fatālas kļūdas (E_ERROR). Daudzi no šiem ziņojumiem ļauj skriptam turpināt darbu, bieži ar nepareiziem vai tukšiem datiem.
Izņēmumi darbojas citādi. Tie pārtrauc ierasto norisi un pāriet uz nākamo piemērotu catch bloku. Ja tāda nav, skripts beidzas. Lēmumu pieņēmējiem atšķirība ir svarīga: kluss brīdinājums var novest pie tā, ka pasūtījums tiek saglabāts nepilnīgi, un neviens to nepamana. Izņēmums problēmu padara redzamu un apstrādājamu.
Par maz novērtēts klasisko ziņojumu ieguvums ir E_DEPRECATED tipa norādes. Tās paziņo, ka valodas līdzeklis nākamajā PHP versijā tiks atcelts. Kas tās vāc žurnālā un regulāri izvērtē, pirms jauninājuma zina, kuras vietas jāpielāgo, un steidzamas drošības ievainojamības gadījumā nav ilgi jātestē.
Throwable hierarhija
Viss, ko var mest ar throw un noķert ar catch, ievieš Throwable. Zem tā ir divi zari:
| Klase | Nolūks | Apakšklašu piemēri |
|---|---|---|
Exception |
lietojumprogrammas un paplašinājumu gaidāmas kļūdas | ErrorException, PDOException, paša definētas klases |
Error |
PHP iekšējās kļūdas | TypeError, ValueError, ArgumentCountError, ArithmeticError, DivisionByZeroError, UnhandledMatchError |
Paša kļūdu klases mantojamas no Exception, nevis no Error. Kopš PHP 8.0 lielākā daļa iekšējo funkciju nederīgu parametru gadījumā met TypeError vai ValueError, nevis tikai izvada brīdinājumu. Viens šāds gadījums ir strlen([]).
try, catch un finally praksē
<?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) {
// kopš PHP 8.0 mainīgais catch ir neobligāts
$log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
return false;
} finally {
$dienst->verbindungSchliessen();
}
}
Vairākas klases var apvienot vienā catch ar |. finally bloks darbojas vienmēr, neatkarīgi no tā, vai kļūda radusies. Kopš PHP 8.0 throw ir arī izteiksme, un to var likt, piemēram, aiz ??: $id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');.
Globālie handler: set_error_handler un set_exception_handler
Divas funkcijas noķer to, kas citādi izslīdētu. set_exception_handler() reģistrē funkciju nenoķertiem Throwable. Saskaņā ar rokasgrāmatu skripts pēc tās izsaukšanas beidzas; tāpēc tā der reģistrēšanai žurnālā un neitrālai kļūdas lapai, nevis darba turpināšanai.
Izrādījies noderīgs handler, kas pilnu kļūdu ar laiku un nejaušu identifikatoru ieraksta žurnālā, bet apmeklētājam rāda tikai neitrālu lapu ar šo identifikatoru. Atbalsts tad var atrast gadījumu žurnālā, un iekšējās detaļas netiek atklātas ārpusei.
set_error_handler() noķer klasiskās kļūdas. Rokasgrāmata rāda, kā tās pārveidot par ErrorException, lai brīdinājumus apstrādātu kā izņēmumus:
<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
if (!(error_reporting() & $nr)) {
return false; // izslēgts ar error_reporting
}
if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
return false; // norādes par novecojušo neeskalēt
}
throw new ErrorException($text, 0, $nr, $datei, $zeile);
});
Fatālas kļūdas, piemēram, atmiņas pārpildi, šādi noķert nevar. Kas pārpildes gadījumā notiek iekšienē, izskaidro lapa memory_limit un Out-of-Memory.
Kļūdu izvades un reģistrēšanas konfigurēšana
Svarīgākie iestatījumi ar noklusējuma vērtībām saskaņā ar rokasgrāmatu:
| Iestatījums | Noklusējums | Ieteikums produkcijai |
|---|---|---|
error_reporting |
E_ALL kopš PHP 8.0.0 |
E_ALL |
display_errors |
1 |
Off |
display_startup_errors |
1 kopš PHP 8.0.0 |
Off |
log_errors |
0 |
On |
error_log |
tukšs (tīmekļa servera vai SAPI žurnāls) | atsevišķs fails ārpus webroot |
fatal_error_backtraces |
1, jauns PHP 8.5.0 |
īslaicīgi 0 (PHP2Shell) |
Kopš PHP 8.2.0 error_log_mode nosaka žurnāla faila tiesības, pēc noklusējuma 0644. Ja žurnālos ir personas dati vai ceļi, saprātīga ir stingrāka vērtība, lai citi servera lietotāji tos nevarētu lasīt. Ar ignore_repeated_errors var apvienot identiskus ziņojumus no tā paša faila un rindas, lai kļūdu cilpa nepārpildītu žurnālu.
Komplektā iekļautais php.ini-production display_errors jau iestata uz Off. Saskaņā ar rokasgrāmatu ini_set('display_errors', ...) izpildes laikā uz fatālām kļūdām neiedarbojas, un sintakses kļūdas rodas, pirms ini_set() vispār darbojas. Šīs vērtības tāpēc jāliek servera konfigurācijā. Fona informācija ir rakstā Kļūdu izvades izslēgšana produkcijā; par to, kā žurnālus vest bez datu noplūdes, rakstā Droša reģistrēšana.
Kļūdu apstrāde un PHP2Shell
PHP 8.5 gadījumā php.net kā vienu no pagaidu pasākumiem pret PHP2Shell min fatal_error_backtraces=0 iestatīšanu un PHP pārstartēšanu pēc tam. Pārējie pasākumi attiecas uz memory_limit, post_max_size un session.upload_progress.enabled. Neviens no tiem neaizstāj atjauninājumu uz PHP 8.5.12, 8.4.27, 8.3.36 vai 8.2.35.
; tikai PHP 8.5, php.ini vai FPM pūlā, pēc tam pārstartēt visus darbprocesus
fatal_error_backtraces = 0
Kļūdu žurnāli pēc PHP2Shell ir arī svarīgs pierādījums. Ja kopš 20.10.2026 uzkrājas atmiņas kļūdas vai pārtraukti darbprocesi, tas var norādīt uz uzbrukuma mēģinājumiem, bet var būt arī nekaitīgi iemesli. Saglabājiet žurnālus un izvērtējiet tos kopā ar piekļuves žurnāliem, kā aprakstīts ceļvedī Tīmekļa servera žurnālu izvērtēšana pēc uzbrukuma.
Kā PHP SOS palīdz konkrēti?
- Mēs pārbaudām spēkā esošos kļūdu izvades un reģistrēšanas iestatījumus katrai vietnei un iestatām tos produkcijai piemērotus.
- Mēs ieviešam PHP2Shell pagaidu pasākumus atbilstoši PHP versijai un pārstartējam visus darbprocesus.
- Mēs nodrošinām kļūdu un piekļuves žurnālus no 20.10.2026 un izvērtējam tos uz neparastām pazīmēm.
- Drošības monitoringa ietvaros mēs ziņojam par neparastu kļūdu uzkrāšanos, nevis ļaujam tai pazust žurnālā.
Biežāk uzdotie jautājumi
Kāda ir atšķirība starp Error un Exception?
Abi ievieš interfeisu Throwable. Exception paredzēts kļūdām, ko lietojumprogramma gaida un apstrādā, piemēram, neizdevies datubāzes savienojums. Error apzīmē PHP iekšējās kļūdas, piemēram, TypeError vai dalīšanu ar nulli.
Vai display_errors produkcijā jāieslēdz?
Nē. Kļūdu ziņojumi pārlūkprogrammā atklāj ceļus, vaicājumus un dažkārt pieejas datus. Produkcijā display_errors jābūt Off un log_errors On, lai kļūdas nonāktu žurnālā, nevis pie apmeklētāja.
Vai atmiņas pārpildi var noķert ar try/catch?
Nē. Ja skripts pārsniedz memory_limit, PHP to beidz ar fatālu kļūdu, ko nevar noķert kā izņēmumu. Tā parādās tikai kļūdu žurnālā, ja log_errors ir aktīvs.
Kas ir fatal_error_backtraces?
Iestatījums, kas pastāv kopš PHP 8.5.0 un fatālām kļūdām pievieno backtrace. Pēc noklusējuma tas ir aktīvs. Kā pagaidu pasākumu pret PHP2Shell php.net PHP 8.5 min iestatīt to uz 0 un pēc tam PHP pārstartēt.