How to avoid TCPDF error suppressing system? - php

TCPDF uses a lot the PHP # operator to suppress error.
As my application use a custom error handler, it still get these "suppressed" errors.
How can I make it ignore #-suppressed errors?
I thought of finding out if the error comes from TCPDF using the backtrace but the error may come from a line not using # operator.
Such a line looks like (l. 6882) for instance:
if (($imsize = #getimagesize($file)) === FALSE) {
I've asked Nicola Asuni (TCPDF creator) about this specific error and he said: "The code is working fine and the error has been suppressed on purpose".
I use PHP function set_error_handler to handle errors.
And the following: error_reporting(E_ALL); on PHP 5.4

Check for error_reporting() inside the error handler (you should read the PHP Documentation, it explains your concrete case there)
See the example (adapted from PHP DOCS):
function myErrorHandler($errno, $errstr, $errfile, $errline ) {
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting or was called with #
return;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler('myErrorHandler');
#strpos();

Related

Pass php error to default php error handler in my custom error handler

I can't manage the following: I have an error handler which catches all E_WARNINGS but I only want to handle some of the warnings all the other I want to ignore and pass them to the default PHP error handler (which also takes all the other error types except the E_WARNINGS).
Is this even possible? Look at my simple error handler:
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
if($errfile != 'somefile_for_example.php') {
// I don't care about this error throw it somewhere else!
}
echo 'error in this file handles my custom error handler';
return true;
}, E_WARNING);
PHP documentation says at: http://php.net/manual/en/function.set-error-handler.php
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.
Maybe then this should work:
$old_error_handler = set_error_handler(
function($errno, $errstr, $errfile, $errline, $errcontext) {
if($errfile != 'somefile_for_example.php') {
return false;
}
echo 'error in this file handles my custom error handler';
return true;
}, E_WARNING);
-
[Edit] Another user (Philipp) commented that set_error_handler returns old handler, but only for another custom one, not for the default handler.
-
In any case, when programming error handlers, one must always be extra careful with programming errors, as they cannot be handled (maybe test the functions by themselves first).
There isn't an easy solution to do this, if you really want the error handler of php.
If you call set_error_handler, you get the current error handler as return value, but only, if set_error_handler was called already. An possible solution to avoid this is to restore the error handler(restore_error_handler) trigger your own error(trigger_error) and set your own error handler again. Caveat from this is, you lost the information about error line, file and context. In addition, you can only trigger user errors, which means, you have to map each error type to an user error type.
I would suggest, to handle all errors in your custom handler - there's no real benefit in such workarounds.

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

Send PHP errors to default error log plus user-defined error log

I may just be having trouble with the error-handling documentation, but what I have in mind is a few different scenarios:
When PHP throws a typical error, I want to keep the default error logging i place but also have separate error logs based on the error type / severity (a log for only fatal errors so I don't have to scan past millions of minor errors, but still have those minor errors logged in the general pile).
For a webapp / platform (like Wordpress or MediaWiki, etc), have PHP errors (all, not just those thrown by webapp) stored in the web app error log. (This will almost certainly be severity based. The idea is to go to the webapp error log and being able to see PHP fatal errors mixed in to avoid hunting down that domain's error log, etc)
Also having errors of certain types thrown by the webapp go to the general error log and it's own custom log (I know I've seen one or the other, but not both).
So the root question is: How can I have a custom error log without losing/overriding the default error log?
Also, is it pretty safe to assume that in most cases errors and exceptions at this level are interchangeable, or will I need to take other steps for similar exception handling goals?
You can set your own error handler and still let php handle the triggered error as usual
http://se.php.net/manual/en/function.set-error-handler.php
set_error_handler(function($errno, $errstr, $errfile, $errline) {
// do what you want
return false; // returning false makes PHP execute its own error handler as well
});
You can use custom error handler and log message into different files like that,
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno)) {
return false;
}
$logFile = "";
switch ($errno) {
case E_USER_ERROR:
$logFile = "logs/php-errors-".date("yyyy-mm-dd",time());
exit(1);
break;
case E_USER_WARNING:
$logFile = "logs/php-warnings-".date("yyyy-mm-dd",time());
break;
case E_USER_NOTICE:
$logFile = "logs/php-notices-".date("yyyy-mm-dd",time());
break;
default:
$logFile = "logs/php-unkown-".date("yyyy-mm-dd",time());
break;
}
error_log($errstr,3,$logFile);
return true;
}
and you should set this error handler function using
set_error_handler("myErrorHandler");

# error suppression operator and set_error_handler

I am following good programming practices and I am logging the PHP errors to file instead of displaying it to user. I use set_error_handler() for that.
Now the problem. For example, I have somewhere:
#file_exists('/some/file/that/is/outside/openbasedir.txt');
But despite the error suppression operator, the error message logs. I don't want that. I want suppressed errors not to pass to my error handler.
This answer applies at PHP 7:
The # operator temporarily sets error_reporting to 0, so you can test the value of error_reporting in your error handler:
if (error_reporting() == 0)
return;
Or even better, log only error types that are in error_reporting:
$error_reporting = error_reporting();
if ( !($error_reporting & $errno) )
return;
Also take a look at the log_errors and error_log options, for automatically logging errors to a file or to syslog.
Solution that also works for PHP 7
According to the PHP docs:
If you have set a custom error handler function with set_error_handler() then it will still get called, but this custom error handler can (and should) call error_reporting() which will return 0 when the call that triggered the error was preceded by an #.
Source: http://php.net/manual/en/language.operators.errorcontrol.php
So you can use the following code in your error handler:
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
if (error_reporting() == 0) {
/// # sign temporary disabled error reporting
return;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
From manual:
Warning Prior to PHP 8.0.0, the error_reporting() called inside the
custom error handler always returned 0 if the error was suppressed by
the # operator. As of PHP 8.0.0, it returns the value E_ERROR |
E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR |
E_PARSE.
This means that solutions from other answers will not work :(
The #-operator became completely unusable imho.
To disable errors you will have to do the following:
error_reporting(0); // disable
try {
$res = 10/0;
} catch (Throwable){
$res = false;
}
error_reporting(-1); // enable
PHP8 behavior has changed and checking error_reporting() == 0 in the error handler no longer works. The way to check for errors suppressed with # in PHP8 is as follows:
function errorHandler($err_severity, $err_msg, $err_file, $err_line)
{
// Skip errors suppressed by #
if (!(error_reporting() & $err_severity)) {
return true;
}
// Error handling here
return false;
}
You should actually avoid usage of # operator. First of all, it is slow, and I would as far as to call it harmful.
What you should have instead is in php.ini file have two line:
error_repoting = E_ALL | E_STRICT
display_errors = Off
... or , if you do not have access to the php.ini file , then at the top of index.php (or any other bootstrap file) you should add :
error_reporting( E_ALL | E_STRICT );
ini_set('display_errors', 0);
PHP8 code 4437 for #
function myErrorHandler(int $errno, string $errstr, ?string $errfile, ?int $errline) : void {
if (error_reporting() !== 4437)
{
......
}
}
set_error_handler("myErrorHandler", E_ALL);

How to catch all PHP errors?

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.

Categories