How to catch all PHP errors? - php

I need a solution to catch all PHP fatal errors, exceptions, warnings, etc. and have a callback.
I want to display a friendly version of the error to the user and log that error.
I'm thinking about using a text file per day for logging error.
Any suggestion or PHP class (library)?

php method: set_error_handler might be what you are looking for.
More at: http://www.php.net/manual/en/function.set-error-handler.php
and at: http://php.net/manual/en/book.errorfunc.php

This makes almost all errors become catchable instance of ErrorException:
set_error_handler(function($errno, $errstr, $errfile, $errline ){
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
});
use it before of the code that can give errors, for instances at the very top of your php file or in a common header included
Limits: Severest errors (PHP engine, server, syntax) 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 compromise it.
But, if syntax is correct and server don't broke, these errors should not appear.
If needed, you could workaround it with the register_shutdown_function() and error_get_last()

As of PHP 8 the best way to catch any and all Exceptions is to catch the Throwable interface which "is the base interface for any object that can be thrown via a throw statement". So your code would look something like this.
try {
# code...
} catch (\Throwable $th) {
# code...
}

Try launch this web page, you should see "Message: Division by Zero".
// Set Error Handler
set_error_handler (
function($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
);
// Trigger an exception in a try block
try {
$a = 3/0;
echo $a;
}
catch(Exception $e) {
echo 'Message: ' .$e->getMessage();
}

I quite like the error handling from the kohana framework. You'd have to do a bit of work to pull it out though.
http://kohanaframework.org/
It will allow you to do error logging to a file and email a recipient. It also enables you to redirect to your friendly error page.

Related

PHP get warning and error messages?

I want to get warning and error messages into php $variables so I save them to my database.
For example when there is any kind of error, warning or similar:
Parse error: syntax error, unexpected T_VARIABLE in /example.php(136) on line 9
Warning: [...]
I want to get them to variable $error_code
How is this done?
For the simple case of just logging them:
set_error_handler(function($errno, $errstr, $errfile, $errline) use ($db) {
// log in database using $db->query()
});
Instead of just logging them into your database (with the likelihood you will not look at them after a while), you can also let those warnings, notices, etc. generate an Exception:
function exception_error_handler($errno, $errstr, $errfile, $errline)
{
if (error_reporting()) { // skip errors that were muffled
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
}
set_error_handler("exception_error_handler");
Source: ErrorException
An exception will have more serious side effects, so you should have an exception handler in place to prevent the uncaught exception to cause a white page of death.
Look into set_error_handler()
Sets a user function (error_handler) to handle errors in a script.
This function can be used for defining your own way of handling errors
during runtime, for example in applications in which you need to do
cleanup of data/files when a critical error happens, or when you need
to trigger an error under certain conditions (using trigger_error()).
I'm using error_get_last(); until I find a better solution
$lastError = error_get_last();
echo $lastError ? "Error: ".$lastError["message"]." on line ".$lastError["line"] : "";
// Save to db
There is a variable called $php_errormsg which gets the previous error message. Check here for more info - http://php.net/manual/en/reserved.variables.phperrormsg.php

PHP try catch exceptions

Hello I have a code like that :
try
{
// Here I call my external function
do_some_work()
}
catch(Exception $e){}
The question is: If the do_some_work() has a problem and produce an Error this try catch will hide the error?
There are two types of error in PHP. There are exceptions, and there are errors.
try..catch will handle exceptions, but it will not handle errors.
In order to catch PHP errors, you need to use the set_error_handler() function.
One way to simplify things mught be to get set_error_handler() to throw an exception when you encounter an error. You'd need to tread carefully if you do this, as it has the potential to cause all kinds of trouble, but it would be a way to get try..catch to work with all PHP's errors.
If do_some_work() throws an exception, it will be catched and ignored.
The try/catch construct has no effect on standard PHP errors, only on exceptions.
produce a Fatal Error
No, catch can not catch Fatal Errors. You can not even with an error handler.
If you want to catch all other errors, have a look for ErrorException and it's dedicated use with set_error_handler:
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
/* Trigger exception */
strpos();

Ensure PHP shutdown function is called

I'm trying to catch as many errors as possible in PHP and properly handle them in a non-default way. My question is best illustrated in this example:
<?php
function errorHandler($errno, $errstr, $errfile, $errline){
echo "Error handler here <br>\n";
//throw new Exception($errstr);
}
function shutdownFunction() {
echo "Hi I'm in here <br>\n";
}
set_error_handler("errorHandler");
register_shutdown_function("shutdownFunction");
try {
$undefined->ok(); // causes some error
} catch(Exception $e) {
echo "Caught the exception <br>\n";
}
The result of running this code as a PHP program will indicate that errorHandler() is run, a PHP error is printed (if "display_errors" is set to "On"), and then shutdownFunction() is run.
The problem I'm having arises if I uncomment out that exception throw; I want to throw exceptions on PHP errors as often as possible. If I uncomment the throw statement out, then the error handler is called, which throws an exception thus causing a further error which results in shutdownFunction() not to be called.
It is my understanding that I can't make this error into a catchable exception; however, I would at least like to ensure that the shutdown function is called without restricting my ability to catch at least some php errors as exceptions (meaning I don't want to remove that throw statement in errorHandler()).
Is there some check in the errorHandler that I can do to check whether or not throwing it will cause shutdownFunction() to be bypassed?
Throw an exception from the error handler, then use set_exception_handler to handle uncaught exceptions.
So the way I'm solving this is to check if the $errstr parameter starts with "Undefined variable" - and if it does, then I'm not throwing the exception. I suppose if there are any other errors that have a similar issue, i'll do the same thing with those. I can't find a comprehensive list of php errors and what their affects are though, so it'll have to be ad hoc

What are some differences between error and exception in PHP?

I'm a beginner in PHP. So far, from the source I'm learning from, the only mechanism to trigger an exception is by writing a line that throws it.
throw new Exception('message')
Furthermore, on the code below, any exception won't be thrown, but an error will be raised.
try
{
$file = fopen('no such file.txt', 'r');
}
catch(Exception $e)
{
echo 'Exception: ' . $e->getMessage();
}
Please give me some explanations.
It seems this try..catch block is not so useful in PHP, unlike in Java or .NET.
By convention, the functions in the PHP core do not throw exceptions (the only exception is that constructors may throw exceptions, because there's no other way for them to properly signal error conditions).
Some differences:
Exceptions have types, and you can catch them according to their type. Errors only have an associated level (E_WARNING, E_STRICT, E_NOTICE, ...).
Exceptions can be caught at any point in the call stack, otherwise they go to a default exception handler. Errors can only be handled in the defined error handler.
"errors" are remains from the pre-oop era of php and are indeed hardly useful in the modern code. Fortunately, you can (actually, must) automatically convert most "errors" to exceptions. The magic is like this
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
Once you've got this, your "fopen" snippet will work as expected. See http://php.net/manual/en/class.errorexception.php for more details/discussion.
It is not useful in this specific case, because fopen() doesn't throw an exception when it encounters an error. I think none of the core functions do.
If you are used to working with exceptions and want to work consistently with them, I think there is nothing speaking against using the ErrorException class to turn all errors into exceptions.
However, fopen() throws only a E_WARNING when it fails to open a file, so in your example, it would be easiest to test whether $file is false to see whether the operation failed.
I personally also like to do a file_exists() before fopen(), and react accordingly if the file is missing.

How to catch an "undefined index" E_NOTICE error in simpleTest?

I would like to write a test using simpleTest that would fail if the method I'm testing results in a PHP E_NOTICE "undefined index : foo".
I tried expectError() and expectException() without success. The simpleTest webpage indicate that simpleTest isn't able to catch compile time PHP errors, but E_NOTICE seems to be a run time error.
Is there a way to catch such an error and makes my test fail if so ?
That wasn't really easy but I finally managed to catch the E_NOTICE error I wanted. I needed to override the current error_handler to throw an exception that I will catch in a try{} statement.
function testGotUndefinedIndex() {
// Overriding the error handler
function errorHandlerCatchUndefinedIndex($errno, $errstr, $errfile, $errline ) {
// We are only interested in one kind of error
if ($errstr=='Undefined index: bar') {
//We throw an exception that will be catched in the test
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
return false;
}
set_error_handler("errorHandlerCatchUndefinedIndex");
try {
// triggering the error
$foo = array();
echo $foo['bar'];
} catch (ErrorException $e) {
// Very important : restoring the previous error handler
restore_error_handler();
// Manually asserting that the test fails
$this->fail();
return;
}
// Very important : restoring the previous error handler
restore_error_handler();
// Manually asserting that the test succeed
$this->pass();
}
This seems a little overly complicated having to redeclare the error handler to throw an exception just to catch it. The other hard part was correctly restoring the error_handler both when an exception was catched and no error occured, otherwise it just messes with SimpleTest error handling.
There really isn't a need to catch the notice error. One could also test the outcome of 'array_key_exists' and then proceed from there.
http://www.php.net/manual/en/function.array-key-exists.php
Test for false and have it fail.
You'll never catch it within the try-catch block, luckily we have set_error_handler():
<?php
function my_handle(){}
set_error_handler("my_handle");
echo $foo["bar"];
?>
You can do anything you want inside my_handle() function, or just leave it empty to silence the notice, although, it's not recommended. A normal handler should be like this:
function myErrorHandler($errno, $errstr, $errfile, $errline)
Many solutions to handling at sign E_NOTICE errors ignore all E_NOTICE errors. To ignore just errors due to use of at signs, do this in your set_error_handler callback function:
if (error_reporting()==0 && $errno==E_NOTICE)
return; // Ignore notices for at sign
An example of an important E_NOTICE that should not be ignored is this:
$a=$b;
because $b is undefined.

Categories