Gestione degli errori in PDO

Ci sono alcuni chiarimenti a proposito del costrutto try...catch di cui dobbiamo discutere. In rete si trova sempre qualcosa del genere:

try {
$pdo->prepare('SELECT * FROM users WHERE username = :username AND group = :group')->execute(['username' => $username, 'group' => $group]);
} catch (PDOException $e) {
   die($e->getMessage());
}

Niente di più sbagliato. Non ha nessuno scopo pratico, se non quello puramente didattico.

PHP ha un sistema di error reporting abbastanza buono, non c’è bisogno di questi espedienti. Quindi anche senza try…catch PHP si occuperà di segnalare l’eccezione traducendola in un fatal error, come di solito fa. Se volete sapere con precisione quale tipo di errore si è presentato, e in quale parte del codice, e SOLO in fase di sviluppo, potete impostare correttamente la funzione display_errors.

Esempio pratico:

Solitamente, gli errori di PDO si presentano in questo modo:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘foo’ at line 1

Non è esattamente il più chiaro dei messaggi, no? Appare incondizionatamente, rivelando all’esterno alcune indicazioni che non dovrebbero però essere rivelate. E potrebbero comunque spaventare gli utenti, inducendoli ad abbandonare l’applicazione. Non è neppure di alcun aiuto al programmatore, non rivelando le informazioni che potrebbero essere utili.

Nel manuale di PHP viene scritto questo:

WarningIf your application does not catch the exception thrown from the PDO constructor, the default action taken by the zend engine is to terminate the script and display a back trace. This back trace will likely reveal the full database connection details, including the username and password.

In realtà non c’è nessuna traccia di back trace! Quello che lo zend engine fa, è convertire una eccezione non gestita in un fatal error (lo fa se la direttiva nel file php.ini è impostata correttamente) e mostrare il messaggio indicato prima, terminando irrimediabilmente la connessione al DB, ma senza mostrare dati sensibili. Non sono utili proprio a nessuno. Quindi è utile settare correttamente i file nel server, e tutto fila liscio.

Impostando display_errors=on ci assicuriamo che PHP segnali in maniera chiara come e dove è avvenuta l’eccezione, trasformandosi in:

Fatal error: Uncaught exception ‘PDOException’ with message ‘SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘foo’ at line 1′ in /srv/hosting/html/another_file.php:5
Stack trace:
#0 /srv/hosting/html/another_file.php(5): PDO->query(‘foo’)
#1 /srv/hosting/html/pdo.php(23): demo()
#2 {main}

Quello che ci interessa è in /srv/hosting/html/another_file.php:5: indica il punto esatto in cui è avvenuto l’errore. Ma ancora più importante è lo stack trace, in quanto offre una panoramica della catena degli eventi che hanno portato a questo errore in particolare.

Quindi per fare in modo che PDO segnali correttamente gli errori bisogna:

  1. Impostare PDO in exception mode;
  2. $options = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ];
    
    // oppure
    
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
  3. Non usare try...catch;
  4. Configurare il file php.ini in maniera corretta per comunicare gli errori:
    • In fase di sviluppo impostare display_errors=on in modo che l’errore venga segnalato subito;
    • Impostare in produzione display_errors=off e log_errors=on;

In ogni caso, impostare E_ALL in error_reporting, impostando queste due righe a inizio pagina:

error_reporting(E_ALL);
ini_set('display_errors', '1');

Quindi con due semplici righe di codice, potete ottenere l’error reporting che desiderate.

Cosa fare sui sistemi in produzione?

Per gestire gli errori in produzione, abbiamo bisogno di:

  • Un log degli errori per il programmatore (log_errors=on);
  • Mostrare una pagina generica di errore per l’utente;
  • Inviare al motore di ricerca un HTTP response code appropriato.

E se proprio vogliamo un sistema di gestione degli errori:

set_exception_handler('myExceptionHandler');
function myExceptionHandler($e)
{
    header('HTTP/1.1 500 Internal Server Error', TRUE, 500);
    error_log($e);
    readfile ('500.html');
    exit;
}

Oppure, per qualcosa di più verbose:

set_error_handler("myErrorHandler");
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
    error_log("$errstr in $errfile:$errline");
    header('HTTP/1.1 500 Internal Server Error', TRUE, 500);
    readfile("500.html");
    exit;
}

Un pensiero su “Gestione degli errori in PDO

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.