I was wondering if anybody knows of a way to alter the default way an error message gets logged in PHP. Hopefully this can be applied to ALL messages, fatal errors, warnings, etc. as well as any time my script calls upon the error_log.
Currently the default error messages show up in the log as
[19-Feb-2017 15:38:42 America/Vancouver] Could not post employee data - no rows submitted
[20-Feb-2017 11:12:34 America/Toronto] PHP Warning: array_splice() expects parameter ...
But what would be greatly beneficial to me is if I could have it also include some variables that i have stored in $_SESSION for each user, such as the user's login and company. So for example the error could be output like the following
[19-Feb-2017 15:38:42 America/Vancouver] [CompanyXYZ/bob_smith] Could not post employee data - no rows submitted
[20-Feb-2017 11:12:34 America/Toronto] [OtherCompany/jimbo_redneck] PHP Warning: array_splice() expects parameter ...
Does anything like this exist in the world of PHP?
You can create your own error handling routine. You should be able to add whatever data you want to the error message. Something like this should get your started:
<?php
function my_handler($errno , $errstr, $errfile, $errline, $errcontext)
{
$msg = "Hey I got an error of type $errno ($errstr) from $errfile line $errline!";
$msg .= "Here's some more info: $_SESSION[foo]";
error_log($msg);
return true;
}
set_error_handler("my_handler");
Fatal errors are only caused by code problems such as syntax errors. They will not happen to users, so you don't need to worry about catching them.
Note that things change considerably in PHP 7.
Related
I am working for a while now with the SOAP API (self teached during work projects). But one thing always bothers me, is that I can't figure out how to handle an empty response.
For instance: I call the service to get some articles from an ERP system. The input parameter is the article number or the GTIN.
Here is some sample code: https://codeshare.io/5e3EYr
If for instance no GTIN is set (just for understanding) the response is not an array anymore (single or multidimensional). The return would be a soap error like "Fatal error: Cannot use string offset as an array" Because the return is the error message.
I hope you understand my problem. I already tried to check if it is_array and even tried to catch the string. But I always get the "Fatal error: Cannot use string offset..." message.
Something like ( as an example for my comment )
function handleShutdown(){
$lasterror = error_get_last();
if (is_null($lasterror)) {
//normal shutdown
return false;
}
//return error to client as XML, JSON etc.
// $lasterror['message']
// $lasterror['type']
// $lasterror['file']
// $lasterror['line']
}
register_shutdown_function('handleShutdown');
I will leave it up to you on how you want to format the error message. The shutdown handler can even catch out of memory errors ... :)
Obviously, you cant catch anything before it's registered so do it early in execution.
php.net/manual/en/function.register-shutdown-function.php
You may also want to look at
set_error_handler
set_exception_handler
Then you can have the trifecta of error handling.
You could use set_error_handler to catch these but you would want to filter out errors of certain verities (in the error handler), an example would be Deprecated or Notice level errors. You can do this with checking the Severity against the error_reporting level you have (bitwise) like this
if($severity & error_reporting())
//report on these errors.
Notice the single & is a bitwise comparison and differs from the normal AND (&&)
Now if you want to prevent the error altogether, I would need to see the code (including the line - marked somehow) where it is produced. Otherwise it's just wild guessing.
In any case when building some kind of service that lacks the normal GUI, it never hurts to have shutdown recovery to send feedback to the client, just make sure to sanitize any output information you share with clients. That way you don't "leak" information that may give away any information that could be used to compromise your application.
cheers.
Finally I figured out, which part to check for an array. If it is not an array, nothing happens. And if, everything is fine.
if(is_array(['getSomeArticleResult']['SqlRowSet']['diffgram']['SqlRowSet1'])){
$aSuppl = $aSuppl['getSomeArticleResult']['SqlRowSet']['diffgram']['SqlRowSet1']['row'];
return $aSuppl;
}
What is the best way to handle errors on front end websites? Similar to twitter, reddit, etc that have a nice 'something went wrong' page. I want to:
detect errors and be notified, even if its just to a log file
show a custom error page such as the fail whale or similar, so its
obvious something has gone wrong instead of showing nothing, or a horrible looking error.
Ideally anything that prevents a user from seeing the site, like fatal errors, custom exceptions, mysql being down, random 500 errors etc, should show the custom error page.
Fatal Errors
PHP : Custom error handler - handling parse & fatal errors - works ok, but if this happens at the end of a script, and it has already output something, this wont work
Non Fatal Errors
http://davidwalsh.name/custom-error-handling-php
MySQL Errors
Ideally need to cover everything from a simple query error, to the server not being there. Imagine its as simple as detecting the error in my database class and calling redirecting to / calling the error method
Server Errors
Is this something I should be doing in PHP OR Apache OR both?
Code at the moment
Currently I have the following from a mix of various other SO's, but fatal errors will just be reported after the rest of the page has loaded.
Anyone have any ideas for something that will work with all of the above?
<?
function xhandler($number,$string,$file,$line,$context)
{
//log to text file?
//log to xml file?
//store in database?
//whatever you want to do!
echo "<h1>here be dragons!</h1>";
echo "$number,$string,$file,$line,$context";
exit();
}
function fatal_handler() {
$errfile = "unknown file";
$errstr = "shutdown";
$errno = E_CORE_ERROR;
$errline = 0;
$error = error_get_last();
if( $error !== NULL) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];
}
echo "<h1>here be dragons!</h1>";
print_r($error);
exit();
}
register_shutdown_function( "fatal_handler" );
set_error_handler('xhandler',E_ALL);
include('show_the_content');
function_that_doesnt_exist();
echo $unterminated_line_of_code
?>
You can't catch fatal errors. They are fatal, script execution stops immediately when they're encountered. These errors should never appear on production sites.
Notices and warnings should be suppressed from showing in HTML on production environment (live sites).
What these sites usually do is handle HTTP errors with PHP. You need to redirect these errors to a PHP script which will handle them. For example, in Apache you do it with the ErrorDocument directive. You can put these directives (one for each HTTP error code) in the server configuration or in the .htaccess file in the web site's document root.
In the PHP script, you can filter different HTTP errors with $_SERVER['REDIRECT_STATUS'], if you need to. When you receive a request with the desired HTTP error, you can handle it any way you wish.
I have had a few nerve racking days trying to get a good error handling system in place within my site.
My error handling system is only focusing on unexpected errors e.g. mysqli errors
My site runs many mysqli queries meaning there is potential for errors to occur.
There is 3 parts to my system, and every one I am unsure on its place in best practices as well as efficiency.
Step 1 : catching the error
$query = "
SELECT * FROM `users_account_activations` WHERE `user_ip` =?
";
$statement = $databaseHandler->mysqli->prepare($query);
$statement->bind_param('s', $userIp);
$statement->execute();
$statement->store_result();
//record error, if any
$databaseHandler->mysqli->error ? error = true : error = false;
Is this a good way of catching the presents of an error somewhere in a prepared statement?
Will looking for errors at the end of the query not catch a error say in the prepare stage? or when the prepare stage fails all other fails (like falling dominoes)
Step 2 : recording the error
error_log("Could not process query...", 3, 'log/default.log');
Is this a suitible way of recording a error? as aposed to the systems that opens a file steam?
Step 3 : handling the after math
Now that there is a error I need to decide on how to move forward, my system intails exiting the script and going to a standard error page saying "opps! something went wrong".
header('location: errorpage.php'); exit();
is changing the header a good way of doing this? I am aware of the limitation of header regarding when you can use it.
Is there a better way for handing errors, this system is intended for unexpected errors. Expected errors are took care of and displayed to the users a different way.
Yes, you are right with your doubts - all the three steps are wrong.
First, for some very strange reason you are not recording the error message itself. How it is supposed to fix the error without error message? What's the use of logging something like "Could not process query..."?
Next, you have to check the result of every operation - so, prepare have to be checked too.
Next, it will be hard to spot the error without knowing where it happened. Some debug backtrace have to be included in the error message.
Next, there shouldn't be a Location header but just Status:500. So, instead of redirecting to error page, just include it.
Finally, all the aforementioned tasks have to be performed in a single place, namely - in the function registered as a custom error handler
So, the scenario have to be like this
in your bootstrap file create a code like this
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;
}
then, make your mysqli code like this
$stmt = $mysqli->prepare("qwefq") or trigger_error($mysqli->error);
and have all your errors logged
EDIT: about the linked answer above, it's similar but different, since my goal is to debug the error in the error page.
Sometimes an unexpected error is hard to debug, since the error report is printed inside strange HTML elements, like an hidden div or a option element.
Is there not a way to automatically store error objects in a global variable and redirect the script to an error page, if any uncaught error is fired? And is there a way to do this for all errors, included the ones that normally doesn't quit the script, like warnings and notices?
You do this with a custom error handler. Turning errors into exceptions is a good way and allows you very fine grained control over error handling:
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
});
You may decide for which errors to throw exceptions and which to ignore; for example you may want to ignore or just log E_NOTICEs. With a global try..catch block or a custom exception handler you can now very easily decide what to do in case of errors.
Indeed there are ways to both redirect errors to pages, log them, track them, and what not. PHP is quite flexible. The good news is you don't have to homecook such methods, frameworks are available for that, but you can also survive without these as built in error handling facilities of PHP are sufficiently usable. If configured properly, PHP will abort on errors (or warnings, you decide), log them, and even return HTTP 500 Server Error code if plugged into a web server.
You may need to configure PHP properly. It is perfectly capable of a better error handling workflow. First of all, disable error printing, this is not how well behaved applications should report errors, and at worst, helps malicious users to break their way into your systems, using printed error output. You are not the only one viewing your webpages, you know, and not all users get confused seeing these, some wait for these. This is one of the directives you can use, editing the "php.ini" file, which configures PHP; it disables mixing error output with whatever else PHP outputs as part of content generation:
display_errors = "0"
You can also set it to "stderr", which is a good thing to do when debugging scripts using command line PHP invocation, as the output will be sent to another file channel, the so called standard error.
Take now heed of the following "php.ini" directive:
log_errors = "1"
The above will have PHP log errors either to a file or using web servers error logging facilities, depending on how PHP is invoked. On UNiX systems, the log file, listing the error and its details, will reside in "/var/log/www/", for instance.
Take a good read through the PHP documentation on error handling and reporting, starting perhaps at the following page:
http://www.php.net/manual/en/book.errorfunc.php
Don't forget to read on installation configuration. And I repeat again, NEVER have PHP display errors for a public PHP script! (and yes, I am aware that you are debugging, but I can't stress this point enough these days).
Thanks to #MladenB. and deceze, I solved my problem. This is how I coded the solution:
in a config.php file, to be included in your scripts (it's better to move the functions to a personal library file):
<?php
function my_error_handler($errno, $errstr, $errfile, $errline)
{
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
function my_exception_handler($e)
{
/**
* Exception handler that pass the error object to an error page.
* This is to avoid bad displaying or hiding of error reports.
*
* #param $e Exception The exception to manage
*/
if (session_status() !== PHP_SESSION_ACTIVE)
{
session_start();
}
session_register_shutdown();
$_SESSION['error'] = $e;
header('Location: error.php');
exit();
}
set_error_handler('my_error_handler');
set_exception_handler('my_exception_handler');
in error.php:
<?php
session_start();
session_register_shutdown();
$e = $_SESSION['error'];
echo '<h2>Stack trace</h2>';
echo var_dump($e->getTrace());
throw $e;
I know better than to ignore errors, I promise. A run of the XML-Sitemaps generator hits URLs without valid session information to please CodeIgniter. The result is one E_NOTICE for every page crawled and a log (and email notifications) that make me bonkers. Nothing breaks and no people or robots are harmed – only my sanity is affected.
Several folks have engineered fixes for the CodeIgniter unserialize() fail:
Encryption Problem: http://codeigniter.com/forums/viewthread/91456/#758252
Recursive Serialization Problem: Weird session behaviour in codeigniter
I've run with each premise and still get hundreds of the following notices:
NOTICE: unserialize() [<a href='function.unserialize'>function.unserialize</a>]: Error at offset 98 of 128 bytes
This brings me back to square one with a very simple question. Here's the problematic line 724 of CI's Session.php:
$data = #unserialize(strip_slashes($data));
I didn't add the suppressive '#' – it was already there. Doesn't that mean that it will specifically suppress E_NOTICE messages if thrown? If not, how could that line possibly generate all these notices that make me want to rip all my hair out?
Setting a custom error handler bypasses PHP's error handling — and apparently PHP's error suppression:
It is important to remember that the standard PHP error handler is completely bypassed for the error types specified by error_types unless the callback function returns FALSE. error_reporting() settings will have no effect and your error handler will be called regardless - however you are still able to read the current value of error_reporting and act appropriately. Of particular note is that this value will be 0 if the statement that caused the error was prepended by the # error-control operator.
<?php
set_error_handler(function ($errno, $errstr) {
echo $errstr;
}, E_ALL);
#unserialize("foo"); // Still shows $errstr!
This will take over for PHP, and probably ignore your error suppression settings. Chances are that CodeIgniter is using its own error handler (which I believe it has) and spitting out errors regardless of the error suppression level.
However, PHP seems to imply that checking the error reporting level and seeing if it's equal to zero will tell you whether or not the error was supposed to be suppressed. So, in theory, you could edit the CodeIgniter error handler and add an if (error_reporting()) { /* show error */ }.