Situazione attuale: PHP2Shell. Due vulnerabilità critiche di PHP (CVSS 9,2) consentono codice dannoso senza autenticazione. Patch dal 21/10/2026.Che cosa fare ora →

Errori ed eccezioni in PHP

PHP conosce i messaggi di errore classici e le eccezioni. Questa pagina spiega la gerarchia di Throwable, la gestione pulita degli errori, le impostazioni sicure per la produzione e la misura PHP2Shell su fatal_error_backtraces.

Stato 6 min di letturaConoscere PHP

In breve: PHP segnala i problemi in due modi: come errori classici, ad esempio avvisi e notifiche, controllati tramite error_reporting, e come eccezioni, che si possono intercettare con try e catch. Da PHP 7 anche molti errori interni generano un oggetto della classe Error; insieme a Exception implementa l'interfaccia Throwable. In produzione vale la regola: registrare gli errori nel log, non mostrarli mai nel browser. Su PHP 8.5, a causa di PHP2Shell, tra le misure transitorie c'è inoltre fatal_error_backtraces=0.

Due mondi: errori classici ed eccezioni

PHP nasce in un'epoca in cui gli errori venivano emessi soprattutto come messaggi: notifiche (E_NOTICE), avvisi (E_WARNING), funzioni obsolete (E_DEPRECATED) ed errori fatali (E_ERROR). Molti di questi messaggi lasciano proseguire lo script, spesso con dati errati o vuoti.

Le eccezioni funzionano diversamente. Interrompono il flusso normale e saltano al successivo blocco catch adatto. Se non ne viene trovato nessuno, lo script termina. Per chi decide la differenza è importante: un avviso silenzioso può far sì che un ordine venga salvato in modo incompleto senza che nessuno se ne accorga. Un'eccezione rende il problema visibile e gestibile.

Un vantaggio sottovalutato dei messaggi classici sono le notifiche di tipo E_DEPRECATED. Annunciano che uno strumento del linguaggio verrà eliminato in una futura versione di PHP. Chi le raccoglie nel log e le analizza con regolarità sa, prima di un upgrade, quali punti vanno adeguati, e in caso di vulnerabilità urgente non deve prima testare a lungo.

La gerarchia di Throwable

Tutto ciò che si può lanciare con throw e intercettare con catch implementa Throwable. Al di sotto ci sono due rami:

Classe Scopo Esempi di sottoclassi
Exception errori prevedibili dell'applicazione e delle estensioni ErrorException, PDOException, classi proprie
Error errori interni di PHP TypeError, ValueError, ArgumentCountError, ArithmeticError, DivisionByZeroError, UnhandledMatchError

Le classi di errore proprie derivano da Exception, non da Error. Da PHP 8.0 la maggior parte delle funzioni interne, con parametri non validi, lancia un TypeError o un ValueError invece di emettere soltanto un avviso. strlen([]) ne è un esempio.

try, catch e finally nella pratica

<?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) {
        // da PHP 8.0 la variabile nel catch è facoltativa
        $log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
        return false;
    } finally {
        $dienst->verbindungSchliessen();
    }
}

Più classi si possono riunire in un unico catch con |. Il blocco finally viene eseguito sempre, che si sia verificato un errore o no. Da PHP 8.0 throw è inoltre un'espressione e può comparire, ad esempio, dopo ??: $id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');.

Handler globali: set_error_handler e set_exception_handler

Due funzioni intercettano ciò che altrimenti sfuggirebbe. set_exception_handler() registra una funzione per i Throwable non intercettati. Secondo il manuale, dopo la sua chiamata lo script termina; è quindi adatta per la registrazione nel log e per una pagina di errore neutra, non per proseguire il lavoro.

Si è rivelato valido un handler che scrive nel log l'errore completo con data e ora e un identificativo casuale, mostrando al visitatore solo una pagina neutra con tale identificativo. Il supporto può così ritrovare il caso nel log, senza che dettagli interni trapelino all'esterno.

set_error_handler() intercetta gli errori classici. Il manuale mostra come trasformarli in una ErrorException, in modo che gli avvisi vengano trattati come eccezioni:

<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
    if (!(error_reporting() & $nr)) {
        return false; // esclusa da error_reporting
    }
    if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
        return false; // non trasformare in eccezioni le segnalazioni di funzioni obsolete
    }
    throw new ErrorException($text, 0, $nr, $datei, $zeile);
});

Gli errori fatali, come un superamento della memoria, non si possono intercettare in questo modo. Che cosa accade internamente in caso di superamento lo spiega la pagina memory_limit e Out-of-Memory.

Configurare la visualizzazione e la registrazione degli errori

Le impostazioni più importanti con i loro valori predefiniti secondo il manuale:

Impostazione Predefinito Raccomandazione per la produzione
error_reporting E_ALL da PHP 8.0.0 E_ALL
display_errors 1 Off
display_startup_errors 1 da PHP 8.0.0 Off
log_errors 0 On
error_log vuoto (log del server web o della SAPI) file proprio fuori dal webroot
fatal_error_backtraces 1, nuova in PHP 8.5.0 temporaneamente 0 (PHP2Shell)

Da PHP 8.2.0 error_log_mode stabilisce i permessi del file di log, per impostazione predefinita 0644. Se i log contengono dati personali o percorsi, è sensato un valore più restrittivo, perché gli altri utenti sul server non possano leggerli. Con ignore_repeated_errors si possono riunire i messaggi identici provenienti dallo stesso file e dalla stessa riga, perché un ciclo di errori non sommerga il log.

Il php.ini-production fornito con PHP imposta già display_errors su Off. Secondo il manuale ini_set('display_errors', ...) in fase di esecuzione non ha effetto sugli errori fatali, e gli errori di sintassi si verificano prima ancora che un ini_set() venga eseguito. Questi valori appartengono quindi alla configurazione del server. Gli approfondimenti si trovano nell'articolo Disattivare la visualizzazione degli errori in produzione; come tenere i log senza fughe di dati, nell'articolo Registrare i log in modo sicuro.

Gestione degli errori e PHP2Shell

Per PHP 8.5 php.net indica, tra le misure transitorie contro PHP2Shell, di impostare fatal_error_backtraces=0 e di riavviare poi PHP. Le altre misure riguardano memory_limit, post_max_size e session.upload_progress.enabled. Nessuna di esse sostituisce l'aggiornamento a PHP 8.5.12, 8.4.27, 8.3.36 o 8.2.35.

; solo PHP 8.5, in php.ini o nel pool FPM, poi riavviare tutti i worker
fatal_error_backtraces = 0

Dopo PHP2Shell i log degli errori sono inoltre un'importante prova. Se dal 20/10/2026 si accumulano errori di memoria o worker interrotti, ciò può indicare tentativi di attacco, ma può avere anche cause innocue. Conservi i log e li analizzi insieme ai log degli accessi, come descritto nella guida Analizzare i log del server web dopo un attacco.

Come aiuta concretamente PHP SOS?

  • Verifichiamo le impostazioni effettive per la visualizzazione degli errori e la registrazione per ogni sito web e le configuriamo in modo adatto alla produzione.
  • Applichiamo le misure transitorie PHP2Shell in base alla versione di PHP e riavviamo tutti i worker.
  • Mettiamo al sicuro i log degli errori e degli accessi dal 20/10/2026 e li analizziamo alla ricerca di anomalie.
  • Nell'ambito del monitoraggio della sicurezza segnaliamo concentrazioni insolite di errori, invece di lasciarle disperdere nel log.

Domande frequenti

Qual è la differenza tra Error ed Exception?

Entrambe implementano l'interfaccia Throwable. Exception è pensata per gli errori che un'applicazione si aspetta e gestisce, ad esempio una connessione al database non riuscita. Error indica errori interni di PHP come un TypeError o una divisione per zero.

display_errors dovrebbe essere attivo in produzione?

No. I messaggi di errore nel browser rivelano percorsi, query e talvolta credenziali. In produzione display_errors va impostato su Off e log_errors su On, così gli errori finiscono nel log e non davanti al visitatore.

Si può intercettare un superamento della memoria con try/catch?

No. Se uno script supera memory_limit, PHP lo termina con un errore fatale che non può essere intercettato come eccezione. Compare solo nel log degli errori, se log_errors è attivo.

Che cos'è fatal_error_backtraces?

Un'impostazione disponibile da PHP 8.5.0 che aggiunge un backtrace agli errori fatali. È attiva per impostazione predefinita. Come misura transitoria contro PHP2Shell, per PHP 8.5 php.net indica di impostarla su 0 e di riavviare poi PHP.

Fonti

Contatto immediato

Ogni ora conta. Ci scriva adesso.

Descriva brevemente sistema, versione di PHP e quanto osservato. Ci faremo sentire, chiariremo la situazione e lavoreremo da remoto fino alla chiusura e alla documentazione dell'incidente.

Aiuto immediato