Jump to content

Error reporting


kurt.santo

Recommended Posts

Getting advice from you chaps I now finally delved into error handling techniques. I put together the following (with help from a book, he, he):

<?php$live=TRUE;$email='kurt@jalp.co.uk';function my_error_handler ($e_number, $e_message, $e_file, $e_line, $e_vars) {global $live, $email;$message="An error occured in script '$e_file' on line $e_line: $e_message\n";$message.=print_r($e_vars,1);if($live){error_log($message, 1, $email);echo '<div class="error">A system error occured. We apologise for the inconvenience.</div><br/>';} else {echo '<div class="error">'.$message.'</div><br/>';}}set_error_handler('my_error_handler');?>

but get twice the error message "Warning: error_log() [function.error-log]: "sendmail_from" not set in php.ini or custom "From:" header missing in C:\Programme\Apache Software Foundation\Apache2.2\htdocs\private\handle.php on line 9A system error occured. We apologise for the inconvenience."I purposely put two mistakes in my page to check if the script works and as I put "$live=TRUE" would have expected to see only the bit with "A system error occured. We apologise for the inconvenience." I went already in my php.ini file and changed the two lines, which read now as:log_errors = On (was off before)sendmail_from = kurt@jalp.co.ukWhat else would I need to change? When I tried the whole thing without logging of errors it worked. But even there I would have two questions: As I put two mistakes in my file it showed the live error message twice. I do not think this is a good idea and would rather have only one error message. Also I would like to have my error message in main content area of page, but when I incude with main content as

  <?php  include('../private/handle2.php');  require_once $content;  ?>

this surely is too late if there are any mistakes beforehand. If you were to place the include line in the first line of the script how can you make sure the message is printed in content area?I hope I make sense...Kurt

Link to comment
Share on other sites

The error message about the email is because you are telling the error_log function to email you the error message, but the sendmail_from option isn't set in php.ini. If you think you are setting it in php.ini make sure that the line is not commented, that you restart the web server after you make the change, and that you are editing the correct file. You can use phpinfo to tell you the location of php.ini that it is using.About printing error messages in the content area, you can't really control that. If the error occurs before the content area is written out then the error message will be outputted at that point, regardless of whatever else is going on with the page. It's not going to get an error, then output the rest of the page, then output the error message.If you want only 1 error to be outputted you can either use the exit function in the error handler to stop execution or you can use a global variable to keep track of whether or not errors have already been printed.

Link to comment
Share on other sites

The error message about the email is because you are telling the error_log function to email you the error message, but the sendmail_from option isn't set in php.ini. If you think you are setting it in php.ini make sure that the line is not commented, that you restart the web server after you make the change, and that you are editing the correct file. You can use phpinfo to tell you the location of php.ini that it is using.About printing error messages in the content area, you can't really control that. If the error occurs before the content area is written out then the error message will be outputted at that point, regardless of whatever else is going on with the page. It's not going to get an error, then output the rest of the page, then output the error message.If you want only 1 error to be outputted you can either use the exit function in the error handler to stop execution or you can use a global variable to keep track of whether or not errors have already been printed.
The problem with the email occured, because I did not restart the web server. This solved that issue, but I have a different problem now: It complains that "Warning: error_log() [function.error-log]: Failed to connect to mailserver at "localhost" port 25, verify your "SMTP" and "smtp_port" setting in php.ini or use ini_set() in C:\Programme\Apache Software Foundation\Apache2.2\htdocs\private\handle.php on line 9A system error occured. We apologise for the inconvenience." What is incorrect with that setting? Also it strikes me as being odd as $live is set to TRUE, so I would not have expected anything else apart from "A system error occured etc" (by the way thank you for your advice with the exit function). Why is that?My PHP.ini was configured as [mail function]; For Win32 only.SMTP = localhostsmtp_port = 25, which seems ok to me?Regarding the issue with printing error messages in a certain area I wondered if should dump the error handler when the site is live, but use sth as "require_once $content or die('could not open file); if that is possible (?). Is that what you mean by "It's not going to get an error, then output the rest of the page, then output the error message."?Cheers,Kurt
Link to comment
Share on other sites

The mail function will only work if you have a mail server installed and configured where you say it is in php.ini. If you haven't installed and configured a mail server, chances are you don't have one. I haven't bothered with setting one up on my development machine.

Also it strikes me as being odd as $live is set to TRUE, so I would not have expected anything else apart from "A system error occured etc". Why is that?
If an error happens in the error handling function it's not going to call the error handling function again to handle the new error. It would be easy to generate an error with the error handling function and then have it get in an infinite loop calling the error handler, which generates a new error. Instead if there is an error in the error handling function it probably just defaults to printing the error to the screen or to the default error log like it's doing.
Regarding the issue with printing error messages in a certain area I wondered if should dump the error handler when the site is live, but use sth as "require_once $content or die('could not open file); if that is possible (?).
Of course it's possible, but that doesn't do what you're trying to do. When errors happen the error handler function just echos out the error message, whenever it happened. That means that the only errors that will show up in the content part are errors that happen when you are printing the content. But if you run into an error when you're setting up the page it's not going to wait until you output the beginning of the page, then set up the content area, then write the error message, then finish the page. It's just going to write the error message. You could have the error handler save all of the error messages into a buffer and display the buffer in some place in the content.
Link to comment
Share on other sites

You could have the error handler save all of the error messages into a buffer and display the buffer in some place in the content.
I am very interested in your last paragraph. Is this the way you would do that? And how would I do that?Also, I put my two files on my hosting space. Then when I opened the file it just showed the message, which is intended for the viewer of the page (which is great). But the email did not arrive. I would think that I am not able to mess around with the php.ini of my provider. So, I cannot use that functionality to send an email with any error message?In addition, to confirm I got this right. When I said "Also it strikes me as being odd as $live is set to TRUE, so I would not have expected anything else apart from "A system error occured etc". Why is that?" and you explained what it means: The "additonal" error message was printed as there was a error in the error handling function? Is this what you are saying?I appreciate your input:-)KurtEmail actually just arrived... There seems to be a delay with my emails...
Link to comment
Share on other sites

I am very interested in your last paragraph. Is this the way you would do that? And how would I do that?
The idea is to have a string containing all of the error messages, and display that string when you want to. Instead of something like this that just prints the message immediately:echo '<div class="error">A system error occured. We apologise for the inconvenience.</div><br/>';You would do this:$buffer .= '<div class="error">A system error occured. We apologise for the inconvenience.</div><br/>';So you need a global variable that you can keep adding messages to. Then, when you get to your content, you can check that global variable to see if it's not empty, and if so then print the contents of it and clear it. You would have to check again at the end of execution because another error might have happened between the time you print the buffer and when the execution ends.I noticed this on the reference page for set_error_handler:
The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.
So the message you saw I believe is E_CORE_WARNING, which isn't handled by your function. Comparing that list with the list of error constants, it looks like the only types that your error handler will handle are E_WARNING, E_NOTICE, E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, and E_RECOVERABLE_ERROR. The USER types are all triggered by using the trigger_error function. So, you're pretty much just handling warnings here, which aren't fatal anyway. Any fatal error that will stop execution won't go through your function, it will use the error_reporting settings in php.ini still.
Link to comment
Share on other sites

I noticed this on the reference page for set_error_handler:So the message you saw I believe is E_CORE_WARNING, which isn't handled by your function. Comparing that list with the list of error constants, it looks like the only types that your error handler will handle are E_WARNING, E_NOTICE, E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, and E_RECOVERABLE_ERROR. The USER types are all triggered by using the trigger_error function. So, you're pretty much just handling warnings here, which aren't fatal anyway. Any fatal error that will stop execution won't go through your function, it will use the error_reporting settings in php.ini still.
I had a check in the php.ini file and it says error reporting is "6135". I do not have the slightest clue what this means, but created an include file as follows:
<?php # config.phperror_reporting(E_ALL);?>

This should hopefully display all errors? When I set the error reporting to (0) I would have expected that no error whatsoever was displayed, but is still showed the "We are sorry blah, blah bit". Why is that? Do not worry, I won't turn the error reporting off, this is all just good practise for me...You advice sounds great, though am not sure if I manage. Will dedicate the next few hours and come hopefully up with something useful. Otherwise, I hope you can look with me through my code again (would post in that case)...Cheers,Kurt

Link to comment
Share on other sites

I had a check in the php.ini file and it says error reporting is "6135".
Values like those are referred to as a bitmask. This will take a little explanation. You can get a list of the error types and their numeric values here:http://www.php.net/manual/en/function.error-reporting.phpNotice that, with the exception of E_ALL, each of the values is a power of 2. This corresponds to a single number, maybe a 16-bit number. So the 16-bit number is represented like this (for a value of 0):[00000000 00000000]Since E_ERROR has a value of 1, if E_ERROR is the only thing that is set then the number looks like this:[00000000 00000001]E_WARNING is 2, so that number is this:[00000000 00000010]E_PARSE, being 4, is this:[00000000 00000100]etc. So each of the powers of 2 corresponds to a single bit in the number. So if you want both E_ERROR (1) and E_PARSE (4), it would look like this:[00000000 00000101]That makes a value of 5, so if you set error_reporting to 5 you are saying you want E_ERROR and E_PARSE. So the way you take a value like 6135 and figure out which errors that corresponds to is to keep subtracting the largest number you can. So the largest number that fits into 6135 in that list is 4096, which is for E_RECOVERABLE_ERROR. So subtracting 4096 from 6135 leaves 2039. The largest value that fits that is 1024, which is for E_USER_NOTICE. Subtracting that leaves 1015. Next is 512, or E_USER_WARNING, which leaves 503. Next is 256, or E_USER_ERROR, which leaves 247. Next is 128, for E_COMPILE_WARNING, which leaves 119. Next is 64, for E_COMPILE_ERROR, which leaves 55. Next is 32, for E_CORE_WARNING, which leaves 23. Next is 16, for E_CORE_ERROR, which leaves 7. Next is 4, for E_PARSE, which leaves 3. That can only be 2 and 1, for E_WARNING and E_ERROR. So a value of 6135 for error_reporting corresponds to these errors:E_ERRORE_WARNINGE_PARSEE_CORE_ERRORE_CORE_WARNINGE_COMPILE_ERRORE_COMPILE_WARNINGE_USER_ERRORE_USER_WARNINGE_USER_NOTICEE_RECOVERABLE_ERRORThose 11 types make a bit string like this:[00010111 11110111]The first zero from the right, which corresponds to a value of 8, is for E_NOTICE, which is disabled (because it's a zero). The other zero is for E_STRICT, so 6135 shows everything except E_NOTICE and E_STRICT. The three zeros on the far left correspond to the values 8192, 16384, and 32768, which aren't being used as error codes now. They may be added in a future version of PHP.
When I set the error reporting to (0) I would have expected that no error whatsoever was displayed, but is still showed the "We are sorry blah, blah bit". Why is that?
Because PHP doesn't pay attention to the error_reporting level when it sends an error to your error handler. It is up to your handler to check the value of error_reporting, the type of the error that was sent, and determine if it should display a message.
Link to comment
Share on other sites

Values like those are referred to as a bitmask. This will take a little explanation. You can get a list of the error types and their numeric values here:http://www.php.net/manual/en/function.error-reporting.phpNotice that, with the exception of E_ALL, each of the values is a power of 2. This corresponds to a single number, maybe a 16-bit number. So the 16-bit number is represented like this (for a value of 0):[00000000 00000000]Since E_ERROR has a value of 1, if E_ERROR is the only thing that is set then the number looks like this:[00000000 00000001]E_WARNING is 2, so that number is this:[00000000 00000010]E_PARSE, being 4, is this:[00000000 00000100]etc. So each of the powers of 2 corresponds to a single bit in the number. So if you want both E_ERROR (1) and E_PARSE (4), it would look like this:[00000000 00000101]That makes a value of 5, so if you set error_reporting to 5 you are saying you want E_ERROR and E_PARSE. So the way you take a value like 6135 and figure out which errors that corresponds to is to keep subtracting the largest number you can. So the largest number that fits into 6135 in that list is 4096, which is for E_RECOVERABLE_ERROR. So subtracting 4096 from 6135 leaves 2039. The largest value that fits that is 1024, which is for E_USER_NOTICE. Subtracting that leaves 1015. Next is 512, or E_USER_WARNING, which leaves 503. Next is 256, or E_USER_ERROR, which leaves 247. Next is 128, for E_COMPILE_WARNING, which leaves 119. Next is 64, for E_COMPILE_ERROR, which leaves 55. Next is 32, for E_CORE_WARNING, which leaves 23. Next is 16, for E_CORE_ERROR, which leaves 7. Next is 4, for E_PARSE, which leaves 3. That can only be 2 and 1, for E_WARNING and E_ERROR. So a value of 6135 for error_reporting corresponds to these errors:E_ERRORE_WARNINGE_PARSEE_CORE_ERRORE_CORE_WARNINGE_COMPILE_ERRORE_COMPILE_WARNINGE_USER_ERRORE_USER_WARNINGE_USER_NOTICEE_RECOVERABLE_ERRORThose 11 types make a bit string like this:[00010111 11110111]The first zero from the right, which corresponds to a value of 8, is for E_NOTICE, which is disabled (because it's a zero). The other zero is for E_STRICT, so 6135 shows everything except E_NOTICE and E_STRICT. The three zeros on the far left correspond to the values 8192, 16384, and 32768, which aren't being used as error codes now. They may be added in a future version of PHP.Because PHP doesn't pay attention to the error_reporting level when it sends an error to your error handler. It is up to your handler to check the value of error_reporting, the type of the error that was sent, and determine if it should display a message.
Great explanation! I think I understood what you meant. I also had a read through the web page you referenced and came up with many more questions (still did not come up with a suitable error_handler;-()... It would be great if you could explain the following:Error_reporting has no effect if you use your own error_handler. Is this right? Then would it make sense to set your error handler to E_ALL or even E_STRICT (what would you prefer?) for testing and to E_ERROR only when live (and display user-friendly message as such)? Also, I am not quite sure what parse errors are. Furthermore, what are user-generated error messages as E_USER_ERROR? I also saw that people use the "@" for suppressing errors. This surely is not good, is it? I mean when a site is live and page content cannot be displayed as an include file cannot be found: this would mean there is an empty page, but the user does not have a clue what is going on? Also, someone said that it might be a security risk sending error logs via email. Is it better to log them in a file?Edit:justsomeguy,trying to come closer to what you suggested with output buffering etc I try to work my way from basic solution to the final one (otherwise I am completely lost and do not understand a thing). I put a script together, but it does not what it should (I put in parenthesis my assumptions of what my code is doing):
/*-- start output buffering--*/ob_start();/*-- live site --*/$live=TRUE;/*-- error handling function giving back error number, the actual message, the error file, the error line and the variables (what are variable in this context?) --*/function my_error_handler ($e_number, $e_message, $e_file, $e_line, $e_vars) {/*-- make $live global --*/global $live;/*-- set error message for testing together --*/$message="An error occured in script '$e_file' on line $e_line: $e_message\n";$message.=print_r($e_vars,1);/*-- error message for live site should not give any detail about problem, just an apology --*/if($live){/*-- if there are error messages print the standard user message --*/if ($message==1){echo $message;}else{/*-- otherwise say 'hi there' --*/echo ('hi there');}/*-- do it only once as user should not see the apology more than once --*/exit();} else {/*-- if site is in testing print the acual error messages --*/echo '<div class="error">'.$message.'</div><br/>';}}ob_end_flush();/*-- as everything is defined now, set the error handler, so it's ready to be used --*/set_error_handler('my_error_handler');

I would have thought that this prints out the error message if sth is wrong or says "hi there" if everything is ok. Having two mistakes in my file I am surprised it says "hi there". Why is that?EDIT: I just found that when I set "$message==0" it actully prints out the error message. THis is confusing. I thought when I compare it to 1 it checks if there is a value and when I compare it to 0 it checks if there is no value. So, why does it print then an error message when I should not? I am lost (and spinning in my head after spending so many hours now on php.net...).Kurt

Link to comment
Share on other sites

Then would it make sense to set your error handler to E_ALL or even E_STRICT (what would you prefer?) for testing and to E_ERROR only when live (and display user-friendly message as such)?
I use E_ALL on my machine at home while I'm developing, seeing all of the notices helps to write more efficient and clear code. PHP recommends that for production servers it is better to set display_errors to false and instead save all errors to a log file, so that people don't see any error messages at all. Then it would be up to the application to detect if an error happened and show the right content.
Also, I am not quite sure what parse errors are.
A parse error is a syntax error, it means that the PHP interpreter could not parse the code. Parse errors are things like a missing quote, semicolon, or paren or a misspelled function name where the interpreter couldn't figure out what the code is trying to do. If your code has a parse error it won't even execute.
Furthermore, what are user-generated error messages as E_USER_ERROR?
If you use the trigger_error function to trigger your own error it will be E_USER_ERROR, E_USER_WARNING, or E_USER_NOTICE, whichever you want it to be.
I mean when a site is live and page content cannot be displayed as an include file cannot be found: this would mean there is an empty page, but the user does not have a clue what is going on?
It would be better if they saw some message telling them that there is a problem, but you often don't want people seeing error messages. An error from an include file would include the path of the script that is running and the path of the include file, you might not want people to know the paths. A database error would expose some information about the database that you might not want people to see.
I just found that when I set "$message==0" it actully prints out the error message. THis is confusing. I thought when I compare it to 1 it checks if there is a value and when I compare it to 0 it checks if there is no value.
No, you're just comparing 2 values. When you compare a string to a number using == it will check if the string contains the number, so checking if $message == 1 would only be true if $message contains the number 1 or the string "1". If you want to check if the string is empty just do that.if ($message == "")
Link to comment
Share on other sites

PHP recommends that for production servers it is better to set display_errors to false and instead save all errors to a log file, so that people don't see any error messages at all. Then it would be up to the application to detect if an error happened and show the right content.
Production servers are the ones for live sites? When you say "it would be up to the application to detect if an error happened and show the right content", does this mean it could display a user-friendly error message in the content area for example? Kurt
Link to comment
Share on other sites

When I say errors I mean errors that you can check for, not fatal PHP errors. A fatal error is trying to write to a file that you haven't opened yet, so it would be up to your application to try and open the file, check for failure, and show a message saying that before trying to write to the file. That's just an example though. Most things you'll do in PHP you can determine whether or not they succeeded, so I'm not talking about trapping the PHP errors, I'm talking about making sure that PHP errors don't happen and trapping the situations where your application can't continue (even though there wasn't a PHP error). That's why people use the error suppression operator, like with mysql_connect. Instead of showing a PHP/MySQL error message, the application would be responsible for checking if the connection failed and, if so, it would display its own error message.

Link to comment
Share on other sites

When I say errors I mean errors that you can check for, not fatal PHP errors. A fatal error is trying to write to a file that you haven't opened yet, so it would be up to your application to try and open the file, check for failure, and show a message saying that before trying to write to the file. That's just an example though. Most things you'll do in PHP you can determine whether or not they succeeded, so I'm not talking about trapping the PHP errors, I'm talking about making sure that PHP errors don't happen and trapping the situations where your application can't continue (even though there wasn't a PHP error). That's why people use the error suppression operator, like with mysql_connect. Instead of showing a PHP/MySQL error message, the application would be responsible for checking if the connection failed and, if so, it would display its own error message.
Ok, I got this (or at least I hope so). But what would you suggest as the best solution to care for non-fatal errors once your site is live? Would you think an error message in content is preferable to a redirect to another file? Obviously, I would still log errors...Kurt
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...