PHP errors laten e-mailen

Onlangs kwam ik het probleem tegen dat een script een foutmelding veroorzaakte welke ik niet kon achterhalen. Deze werd door een extern proces aangeroepen, maar dat leek om een of andere reden niet te werken. Wanneer ik het script handmatig aanriep werkt dit wel naar behoren. Om te kijken of er fouten werden veroorzaakt besloot ik om fouten naar mijn e-mail adres te laten e-mailen.

Error afhandeling

In PHP is de mogelijkheid aanwezig om errors op je eigen manier te laten afhandelen. Hierdoor kun je bijvoorbeeld errors laten loggen, óf bijvoorbeeld laten e-mailen. En dat hebben we nou net nodig!

Als eerste hebben we de PHP functie set_error_handler nodig. Hierbij kan een functie worden opgegeven die moet worden aangeroepen wanneer een foutmelding wordt veroorzaakt. In dit geval gaan we werken met een functie die heel afgezaagd error_handler heet. De eerste regel code ziet er dan ook zo uit:

  1. set_error_handler('error_handler');

Nu moeten we uiteraard wel de functie aanmaken die de errors ook daadwerkelijk naar ons e-mail adres gaat versturen. Deze functie kan een aantal argumenten accepteren waarvan de eerste 2 verplicht geaccepteerd moeten worden:

  • errno
    Het niveau van de fout. Dit loopt van het gebruik van een variabele die niet bestaat tot fouten waardoor het script niet uitgevoerd kan worden.
  • errstr
    De leesbare variant van de foutmelding. Hier staat vrij duidelijk in wat er mis is.
  • errfile
    Het bestand waar de foutmelding is opgetreden. Dit is vooral handig wanneer dit script op meerdere pagina's wordt gebruikt.
  • errline
    De regel waarop de foutmelding zich heeft voorgedaan.
  • errcontext
    Een array met daarin de beschikbare variabelen van het moment dat de foutmelding zich voordeed.

Met deze kennis komt de functie er als volgt uit te zien:

  1. function error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
  2.         switch($errno) {
  3.                 case E_ERROR:               $errno_type = "Error";                  break;
  4.                 case E_WARNING:             $errno_type = "Warning";                break;
  5.                 case E_PARSE:               $errno_type = "Parse Error";            break;
  6.                 case E_NOTICE:              $errno_type = "Notice";                 break;
  7.                 case E_CORE_ERROR:          $errno_type = "Core Error";             break;
  8.                 case E_CORE_WARNING:        $errno_type = "Core Warning";           break;
  9.                 case E_COMPILE_ERROR:       $errno_type = "Compile Error";          break;
  10.                 case E_COMPILE_WARNING:     $errno_type = "Compile Warning";        break;
  11.                 case E_USER_ERROR:          $errno_type = "User Error";             break;
  12.                 case E_USER_WARNING:        $errno_type = "User Warning";           break;
  13.                 case E_USER_NOTICE:         $errno_type = "User Notice";            break;
  14.                 case E_STRICT:              $errno_type = "Strict Notice";          break;
  15.                 case E_RECOVERABLE_ERROR:   $errno_type = "Recoverable Error";      break;
  16.                 default:                    $errno_type = "Unknown error ($errno)"; break;
  17.         }
  18.        
  19.         $bericht = '<p>Er heeft zojuist een error plaatsgevonden.</p>';
  20.         $bericht .= '<p>Dit was een <strong>' . $errorno_type . '</strong> en vond plaats op regel <strong>' . $errline . '</strong> in het bestand <strong>' . $errfile . '</strong></p>';
  21.         $bericht .= '<p>De exacte foutmelding was:</p>';
  22.         $bericht .= '<p><strong>' . $errstr . '</strong></p>';
  23.         $bericht .= '<p>Deze variabelen waren beschikbaar:</p>';
  24.         $bericht .= '<pre>' . print_r($errcontext, true) . '</pre>';
  25.        
  26.         $headers  = 'MIME-Version: 1.0' . "\r\n";
  27.         $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
  28.         mail('jouw@e-mailadres.nl', 'Er is een foutmelding veroorzaakt', $bericht, $headers);
  29. }

Alles bij elkaar, inclusief fout, komt er dan zo uit te zien:

  1. <?php
  2. function error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
  3.         switch($errno) {
  4.                 case E_ERROR:               $errno_type = "Error";                  break;
  5.                 case E_WARNING:             $errno_type = "Warning";                break;
  6.                 case E_PARSE:               $errno_type = "Parse Error";            break;
  7.                 case E_NOTICE:              $errno_type = "Notice";                 break;
  8.                 case E_CORE_ERROR:          $errno_type = "Core Error";             break;
  9.                 case E_CORE_WARNING:        $errno_type = "Core Warning";           break;
  10.                 case E_COMPILE_ERROR:       $errno_type = "Compile Error";          break;
  11.                 case E_COMPILE_WARNING:     $errno_type = "Compile Warning";        break;
  12.                 case E_USER_ERROR:          $errno_type = "User Error";             break;
  13.                 case E_USER_WARNING:        $errno_type = "User Warning";           break;
  14.                 case E_USER_NOTICE:         $errno_type = "User Notice";            break;
  15.                 case E_STRICT:              $errno_type = "Strict Notice";          break;
  16.                 case E_RECOVERABLE_ERROR:   $errno_type = "Recoverable Error";      break;
  17.                 default:                    $errno_type = "Unknown error ($errno)"; break;
  18.         }
  19.        
  20.         $bericht = '<p>Er heeft zojuist een error plaatsgevonden.</p>';
  21.         $bericht .= '<p>Dit was een <strong>' . $errorno_type . '</strong> en vond plaats op regel <strong>' . $errline . '</strong> in het bestand:<br /><strong>' . $errfile . '</strong></p>';
  22.         $bericht .= '<p>De exacte foutmelding was:</p>';
  23.         $bericht .= '<p><strong>' . $errstr . '</strong></p>';
  24.         $bericht .= '<p>Deze variabelen waren beschikbaar:</p>';
  25.         $bericht .= '<pre>' . print_r($errcontext, true) . '</pre>';
  26.        
  27.         $headers  = 'MIME-Version: 1.0' . "\r\n";
  28.         $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
  29.         mail('jouw@e-mailadres.nl', 'Er is een foutmelding veroorzaakt', $bericht, $headers);
  30. }
  31.  
  32. set_error_handler('error_handler');
  33.  
  34. echo $dezeVariabeleBestaatNiet . 'test';
  35. ?>

Dit script zeurt al over het minste en geringste, in het voorbeeld hier boven omdat de variabele $dezeVariabeleBestaatNiet niet bestaat. Op zich handig om te weten maar ik kan mij voorstellen dat je enkel de echt boeiende foutmeldingen wilt weergeven. Dat kun je doen door alleen bij een bepaalde $errno de functie verder te laten uitvoeren.

Het originele probleem

En het probleem met mijn script? Dat bleek uiteindelijk veroorzaakt te worden doordat de website enkel bereikbaar was van een aantal selectieve ip-adressen. Soms ligt het antwoord is te veel voor de hand :-)