PHP FAQs and Stickies
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me

The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.

Go Back   Dev Shed ForumsProgramming LanguagesPHP DevelopmentPHP FAQs and Stickies

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old March 20th, 2013, 07:31 PM
Jacques1's Avatar
Jacques1 Jacques1 is offline
pollyanna
Click here for more information.
 
Join Date: Jul 2012
Location: Germany
Posts: 1,870 Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level) 
Time spent in forums: 1 Month 2 Weeks 2 Days 22 m 32 sec
Reputation Power: 813
PHP-General - The mystery of errors and exceptions

Hi,

since many people seem to struggle a lot with error reporting and exception handling, and since the same nonsense „solutions“ still get copied and pasted around, this is an attempt of clearing things up a bit.



Premises


What error reporting is supposed to do:
  • distinguish between end-users and developers
  • provide developers with detailed error reports
  • provide end-users with a short, generic error message and a 5xx status code

What error reporting is not supposed to do
  • leak critical information (file paths, queries, your database credentials, ...)
  • irritate users with technical bug reports
  • stay silent



Common mistakes


Displaying internal errors generated by PHP

This is probably the most common mistake. Outputting PHP errors makes sense during development, but on the actual website, it’s very dangerous for you and irritating for your users. The PHP error messages are meant for developers, not application users. If they pop up on your website, they help attackers with detailed information while scaring legitimate users.

Since this often happens due to a misconfiguration, make sure to properly configure PHP as explained below.


Displaying internal errors from subsystems

Another common mistake is taking the error messages from, for example, MySQL and dumping them on the screen with a die() or an echo. Check this pattern, which is an all-time favorite of many bullsh*t „tutorials“ and gets copied and pasted around since PHP was invented:

don’t use
PHP Code:
 mysql_query(...) or die(mysql_error()); 

There’s also an object-oriented variant:

don’t use
PHP Code:
try {
    
$db->query(...);
} catch (
PDOException $e) {
    echo 
'Query failed: ' $e->getMessage();


What’s wrong with this is that it again displays an internal error message not meant for end-users. The message will contain critical information like the exact query or even your database credentials. But it’s actually even worse than a misconfiguration, because this mistake cannot be fixed globally. A die() is a die(), you cannot turn it off. You have to actually go through your whole code and delete those parts manually.

So never use echo or die() to display error messages from databases or other systems.



Proper error reporting


Configuring PHP

Start off by opening the php.ini. Note that you cannot do the error configuration within the script, because PHP might fail before the script is even executed.

The four most important directives are:
  • error_reporting: which errors should be displayed or logged
  • display_errors: whether or not internal error messages should be displayed on the website
  • display_startup_errors: whether or not errors within the PHP system itself should be displayed
  • log_errors: whether or not errors should be written to a log; the log can be specified with error_log
During development, you’ll probably want to see all error messages in the browser and not log them. Do this by setting error_reporting to -1, display_errors and display_startup_errors to On and log_errors to Off. You can also exclude specific errors using the error constants. Avoid using E_ALL. Despite its name, it doesn’t cover E_STRICT errors prior to PHP 5.4.

Use during development
Code:
error_reporting = -1

display_errors = On

display_startup_errors = On

log_errors = Off

On the actual website, PHP must not output any internal error messages, so set display_errors and display_startup_errors to Off. If you want to log the errors, set error_reporting to the appropriate level, turn log_errors on and set the error_log if needed.

Use for production
Code:
error_reporting = -1    ; if your code is sloppy, this will quickly fill the error log, so use an appropriate level

display_errors = Off

display_startup_errors = Off

log_errors = On


Setting up a custom error page

If you’re using nginx with a current PHP version (at least 5.2.4) over FastCGI, this is easy: enable fastcgi_intercept_errors and define an error_page for 500 errors.

PHP >= 5.2.4 will automatically generate a 500 code under the following conditions: a fatal error has occured, display_errors is set to Off and no output has been sent yet. All you have to do is catch the 500 code and have nginx handle it.

Use with nginx + PHP >= 5.2.4
Code:
fastcgi_intercept_errors  on;

error_page  500  /error_pages/5xx.html;

location /error_pages {
    internal;    # the error pages should not be publicly accessible
}

If you’re using Apache, you need to do some handiwork. Since Apache doesn’t intercept 500 errors issued by PHP, you’ll get a blank page by default. Any custom error page must be sent by PHP itself. However, you cannot do this in the actual script, because several errors like E_PARSE prevent the script from ever being executed (as already mentioned above).

The workaround for this is to create a separate script with a shutdown handler and prepend it to every script using auto_prepend_file in the php.ini:
Code:
auto_prepend_file = 'path/to/fatal_error_handler.php'


A shutdown handler is executed after the actual script has been run or aborted, so it can be used to catch even severe errors like erroneous syntax. Prepending the helper script makes sure that the shutdown handler is registered before the actual script might crash everything.

Use with Apache + PHP >= 5.4
PHP Code:
<?php

register_shutdown_function
('handle_fatal_errors');

function 
handle_fatal_errors() {
    
// display error message if the response code is 500 (either due to a fatal error or a custom header() call) and display_errors is turned off and nothing has been sent yet
    
if ( http_response_code() == 500 && !ini_get('display_errors') && !headers_sent() ) {
        
// flush any buffered content (assuming this is garbage generated before the error occured)
        
ob_clean();
        
// send a 500 status code and an error message
        
echo 'Sorry, an error has occured. The webmaster has been notified and will fix the issue as soon as possible. Please try again later.';
    }
}

Use with Apache + PHP < 5.4
PHP Code:
<?php

register_shutdown_function
('handle_fatal_errors');

function 
handle_fatal_errors() {
    
$fatal_errors =
        
E_ERROR E_PARSE E_CORE_ERROR E_COMPILE_ERROR E_USER_ERROR E_RECOVERABLE_ERROR;
    
$last_error error_get_last();
    
// display error message if there was a fatal error and display_errors is turned off and nothing has been sent yet
    
if ( $last_error && ($last_error['type'] & $fatal_errors) && !ini_get('display_errors') && !headers_sent() ) {
        
// flush any buffered content (assuming this is garbage generated before the error occured)
        
ob_clean();
        
// send a 500 status code and an error message (see http://stackoverflow.com/questions/3258634/php-how-to-send-http-response-code)
        
header('X-PHP-Response-Code: 500'true500);
        echo 
'Sorry, an error has occured. The webmaster has been notified and will fix the issue as soon as possible. Please try again later.';
    }
}


Using custom errors or exceptions

In case you want to generate a custom error within the script (like when a query fails), always use the trigger_error() function or an exception (see below). This will adhere to the error procedure and not just dump the message on the screen no matter what.

PHP Code:
 $query mysql_query(...);
if (!
$query)
    
trigger_error('Query failed: ' mysql_error(), E_USER_ERROR); 

Note that the old MySQL extension is hopelessly outdated and has already been replaced 10 years ago. If possible, switch to one of the new extensions. They no longer require you to manually check the status of each query.



Exceptions


If you’re dealing with modern, object-oriented PHP code, you have to consider yet another error mechanism: exceptions. An exception is a special object indicating a certain kind of error.

Since exceptions are pretty „new“ in the PHP world, they don’t seem to be very well understood. A common misconception is that somehow every piece of code that might throw an exception must be wrapped in a try-catch block. This is not the case.

Check this piece of code from the PHP manual, which is yet another example of bad ideas being mindlessly copied and pasted through the whole internet:

don’t use
PHP Code:
try {
    
$db = new PDO($dsn$user$password);
} catch (
PDOException $e) {
    echo 
'Connection failed: ' $e->getMessage();


This is dangerous, error-prone and completely useless for many reasons:
  • It will simply dump the error message on the screen, completely ignoring the PHP configuration. The error will leak critical information about your database and your queries (see „Common mistakes“).
  • It does what an uncaught exception would do, anyway – except that it cuts off important information like the file name, line, stack trace etc. and turns a smart exception into a dumb die().
  • The code can hardly be reused in a bigger system, because it could stop the whole application at any time. There’s no chance to catch the exception on a higher level. Wasn’t reusability the whole point of object-oriented programming?
  • Doing this procedure for every query clutters up the whole application with useless, repetitious code
So this is obviously a bad idea. It’s probably just meant to demonstrate how exceptions can be fetched, but many people actually copy and paste the literal code.

Exceptions are designed to be smart. They do not have to be fetched right away like a return value. Instead, they can „bubble up“ and be caught later – or not at all. An uncaught exception will generate a fatal error and trigger the standard error procedure, which should work fine for most of your exceptions.

This allows for very sophisticated error handling – but only if used properly:
  • Only catch an exception if you actually want to handle it in a specific way. In case of a database failure, for example, you might want to retry the connection, switch to an alternative connection etc. Otherwise, just let the exception bubble up and catch it later or not at all.
  • Don't repeat yourself. When you have multiple exceptions that should all be handled in the same way, catch them on a higher level.
  • Catch specific exceptions, not the generic Exception class. This class includes all exceptions, so you might unintentionally „swallow“ other important errors.

Reply With Quote
  #2  
Old March 21st, 2013, 04:18 PM
MrFujin's Avatar
MrFujin MrFujin is offline
Lord of the Dance
Dev Shed Loyal (3000 - 3499 posts)
 
Join Date: Oct 2003
Posts: 3,129 MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level) 
Time spent in forums: 2 Months 2 Weeks 23 h 6 m 34 sec
Reputation Power: 1736
Great post.

We can only hope that people start to take care and get/use the necessary time to make things properly.

PS: where did my reputation comment go? hidden?

Reply With Quote
  #3  
Old March 22nd, 2013, 06:08 AM
Jacques1's Avatar
Jacques1 Jacques1 is offline
pollyanna
Click here for more information.
 
Join Date: Jul 2012
Location: Germany
Posts: 1,870 Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level)Jacques1 User rank is Lieutenant General (80000 - 90000 Reputation Level) 
Time spent in forums: 1 Month 2 Weeks 2 Days 22 m 32 sec
Reputation Power: 813
Quote:
Originally Posted by MrFujin
We can only hope that people start to take care and get/use the necessary time to make things properly.


Hopefully. Unfortunately, it's very easy to just copy and paste the bad stuff that's available everywhere, but it's pretty hard to do things right.

Other languages have one way of indicating errors, PHP has three of them (return values, errors and exceptions). Other languages let you do global error handling by simply wrapping the main script in a try-catch statement, PHP makes you jump through hoops to actually get all errors. Yeah, there's set_error_handler(), but many error will just slip through that error handler -- and you have to reimplement the whole error system.

I have no idea why people keep saying that PHP is simple.



Quote:
Originally Posted by MrFujin
PS: where did my reputation comment go? hidden?


I can see it in my profile. Thanks.

Reply With Quote
  #4  
Old March 22nd, 2013, 06:25 AM
MrFujin's Avatar
MrFujin MrFujin is offline
Lord of the Dance
Dev Shed Loyal (3000 - 3499 posts)
 
Join Date: Oct 2003
Posts: 3,129 MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level)MrFujin User rank is General 11st Grade (Above 100000 Reputation Level) 
Time spent in forums: 2 Months 2 Weeks 23 h 6 m 34 sec
Reputation Power: 1736
Quote:
Originally Posted by Jacques1
I have no idea why people keep saying that PHP is simple.


You more or less just answered this yourself.
Those people live in the perfect (/flawless) world. Then PHP is simple I guess.

Reply With Quote
  #5  
Old April 19th, 2013, 03:13 AM
Northie's Avatar
Northie Northie is offline
Square Peg in a Round Hole
Click here for more information.
 
Join Date: Oct 2007
Location: North Yorkshire, UK
Posts: 3,420 Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level)Northie User rank is General 44th Grade (Above 100000 Reputation Level) 
Time spent in forums: 3 Weeks 5 Days 10 h 50 m 26 sec
Reputation Power: 3896
Quote:
Originally Posted by Jacques1
I have no idea why people keep saying that PHP is simple.


because those 'people' are the ones copying and pasting or a writing code which 'works' (code which behaves as expected only when used as intended) first time and have no idea about the concepts of Exceptions or what to do (or just don't) if the query did fail on their 1-visitor a day 4 page website on a cheap host
__________________
PHP OOPS! <?php DB::Execute(SQL::makeFrom($_GET))->fetchArray()->FormatWith(Template::getInstance('default'))->printHtml(); ?>

PDO vs mysql_* functions: Find a Migration Guide Here

[ Xeneco - T'interweb Development ] - [ Are you a Help Vampire? ] - [ Read The manual! ] - [ W3 methods - GET, POST, etc ] - [ Web Design Hell ]

Reply With Quote
Reply

Viewing: Dev Shed ForumsProgramming LanguagesPHP DevelopmentPHP FAQs and Stickies > PHP-General - The mystery of errors and exceptions

Developer Shed Advertisers and Affiliates



Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 


Powered by: vBulletin Version 3.0.5
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.

© 2003-2013 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap