Normally php script continues to run after E_NOTICE, is there a way to elevate this to fatal error in context of a function, that is I need only to exit on notice only in my functions but not on core php functions, that is globally.
You could create a custom error handler to catch E_NOTICEs.
This is untested but should go into the right direction:
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if ($errno == E_USER_NOTICE)
die ("Fatal notice");
else
return false; // Leave everything else to PHP's error handling
}
then, set it as the new custom error handler using set_error_handler() when entering your function, and restore PHP's error handler when leaving it:
function some_function()
{
// Set your error handler
$old_error_handler = set_error_handler("myErrorHandler");
... do your stuff ....
// Restore old error handler
set_error_handler($old_error_handler);
}
You use a custom error handler using set_error_handler()
<?php
function myErrorHandler($errno, $errstr, $errfile, $errline) {
if ($errno == E_USER_NOTICE) {
die("Died on user notice!! Error: {$errstr} on {$errfile}:{$errline}");
}
return false; //Will trigger PHP's default handler if reaches this point.
}
set_error_handler('myErrorHandler');
trigger_error('This is a E_USER_NOTICE level error.');
echo "This will never be executed.";
?>
Working Example
Related
I defined handler function in functions.php:
function errorHandler($errno, $errstr, $errfile, $errline) {
echo "An error: $errstr";
return true; // Preventing standard handler
}
Then I used it in set_error_handler:
require_once('functions.php');
set_error_handler("errorHandler");
But when I trigger notice, I get standard PHP message: Notice: Undefined variable: thisVariableDoesntExist in..., set_error_handler doesn't handle E_ERROR, but here I have notice, so I can't get it why this doesn't work.
I'm writing a custom error handler for Slim/3.3.0 and I'm trying to figure out if it's worth reusing the same code to handle both errors and exceptions. To do so I've defined a custom error handler to convert errors into ErrorException instances:
require __DIR__ . '/../vendor/autoload.php';
set_error_handler (function ($errno, $errstr, $errfile, $errline) {
if (!(error_reporting() & $errno)) {
return true; // Do not run built-in handler
}
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});
$app = new \Slim\App(['settings' => ['displayErrorDetails' => false]]);
$container = $app->getContainer();
// [...]
$container['errorHandler'] = function (Slim\Container $c) {
return new App\Handlers\Error($c->logger, $c['settings']['displayErrorDetails']);
};
I can then log uncaught exceptions and/or display my generic "There was an error" page to my liking (so far so good).
But now I want to handle minor issues (E_WARNING, E_NOTICE, etc.) differently: instead of aborting everything and showing the generic error page template, I want to be able to continue execution and/or display the error message inline (just like PHP does by default) and here's where I'm lost. The display inline part is easy but my scripts aborts right there:
namespace App\Handlers;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
final class Error extends \Slim\Handlers\Error
{
public function __invoke(Request $request, Response $response, \Exception $e)
{
if ($this->displayErrorDetails) {
$response->write($e);
} else {
$this->saveToLog($e);
$response->write('[ERROR]');
}
if ($this->isFatal($e)) {
// Aborts scripts and displays error page (OK)
return parent::__invoke($request, $response, $e);
} else {
// Seems to abort script (nothing else is shown from this poing)
return $response;
}
}
}
... testing it this way:
$app->get('/warning-test', function (Request $request, Response $response) {
$this->logger->info("Loading {$_SERVER['REQUEST_URI']}");
$response->write('<h1>Warning test page</h1>');
$response->write('<p>About to generate a warning:</p>');
$this->logger->info("Generating warning...");
1/0;
$this->logger->info("Warning generated");
$response->write('<p>This should display as well.</p>');
// ... but it doesn't. Probably because Response is immutable and my copy
// was superseded by a clone
return $response;
});
What are my options?
The set_error_handler() function takes as second parameter the error type therefore you can specify that only E_ERROR should use your custom error handler:
$errorTypes = E_ERROR;
set_error_handler (function ($errno, $errstr, $errfile, $errline) {
if (!(error_reporting() & $errno)) {
return true; // Do not run built-in handler
}
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}, $errorTypes);
When you want handle notices and warnings by yourself, you cannot throw an Exception as it basically cancels the normal route and only take the error response. You can do this without throwing an Exception like so:
$errorTypes = E_WARNING | E_NOTICE;
set_error_handler (function ($errno, $errstr, $errfile, $errline) {
if (!(error_reporting() & $errno)) {
return true; // Do not run built-in handler
}
\App\Handlers\Error::setNoticeOrWarning($errno, $errstr, $errfile, $errline);
}, $errorTypes);
Then you can check this later in middleware and display this.
How may arrange that script execution stops upon notice/warning, without changing other behaviour, inc, the notice/warning messages, i.e. e.g. not throwing an exception.
Stop script execution upon notice/warning is a different question.
You can create a custom error handling function, like so:
<?php
// error handler function
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting
return;
}
switch ($errno) {
case E_USER_ERROR: exit('Im a user error.');
case E_USER_WARNING: exit('Im a user warning');
case E_USER_NOTICE:
printNotice($errno, $errstr, $errfile, $errline);
break;
default: exit('Unknown Error');
}
// don't execute PHP internal error handler
return true;
}
function printNotice($errno, $errstr, $errfile, $errline)
{
// use the following vars to output the original error
var_dump($errno, $errstr, $errfile, $errline);
exit;
}
Important are the constants: E_USER_NOTICE and E_USER_WARNING.
The function printNotice() shows how you can print the original error,
so that it appears unmodified and then stops script execution with exit.
All the original error data (message, line number, etc.) is in the variables
$errno, $errstr, $errfile, $errline. PHP makes the error data automatically available at the registered errorhandler (here myErrorHandler).
In this example i'm forwarding all the parameters a second time, to printNotice() function, which could format the error differently or do what you like upon it.
And then register it with set_error_handler(), like so:
<?php
// register your error handler
set_error_handler('myErrorHandler');
In order to test the error handling you might use the function trigger_error():
trigger_error("This is a User Error", E_USER_ERROR);
trigger_error("This is a User Warning", E_USER_WARNING);
trigger_error("This is a User Warning", E_USER_NOTICE);
Straight forward answer to your question is NO you can't.
You have to create a custom error handler that stops execution.
As there is no way to do this outside.
I am trying to create a custom error function (following a tutorial). I have:
<?php
error_reporting(E_ERROR);
function handleError ($errno, $errstr,$error_file,$error_line){
echo "<b>Error:</b> [$errno] $errstr - $error_file:$error_line";
echo "<br />";
echo "Terminating PHP Script";
die();
}
//set the error handler here, override the default
set_error_handler("handleError");
//cause a crash
myfunction();
?>
However my script isn't calling the function. It just prints the default error message. Could someone give me a pointer to what I might be doing wrong here please? Is my error_reporting value wrong?
There is nothing wrong with your code. However, the capabilities of set_error_handler are limited.
From the PHP documentation:
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.
If you indeed need to catch compilation errors as in your example, there is one workaround mentioned in the comments of the documentation above - the use of a shutdown function:
<?php
error_reporting(E_ERROR);
function handleError($errno, $errstr, $error_file, $error_line) {
echo "<b>Error:</b> [$errno] $errstr - $error_file:$error_line";
echo "<br />";
echo "Terminating PHP Script";
die();
}
function checkForError() {
$error = error_get_last();
if ($error["type"] == E_ERROR) {
handleError($error["type"], $error["message"], $error["file"], $error["line"]);
}
}
register_shutdown_function("checkForError");
// cause a crash
myfunction();
?>
Note that the default error handler will still be called, so this prints out:
Fatal error: Call to undefined function myfunction() in path\to\file.php on line 24
Error: [1] Call to undefined function myfunction() - path\to\file.php:24
Terminating PHP Script
You can get rid of the default message by disabling error reporting with error_reporting(0);.
If you want to handle errors from within your method execution (i.e. you have defined myfunction somewhere), your original example might already work, depending on your concrete case. Proof, e.g.:
<?php
error_reporting(E_ERROR);
function handleError($errno, $errstr, $error_file, $error_line) {
echo "<b>Error:</b> [$errno] $errstr - $error_file:$error_line";
echo "<br />";
echo "Terminating PHP Script";
die();
}
function myfunction() {
fopen("nonexistingfile", "r");
}
// set the error handler here, override the default
set_error_handler("handleError");
// cause a crash
myfunction();
?>
This uses the custom error handler as expected and prints out:
Error: [2] fopen(nonexistingfile): failed to open stream: No such file or directory - path\to\file.php:12
Terminating PHP Script
I got this code from w3schools, I think you might have a need to trigger it
<?php
// A user-defined error handler function
function myErrorHandler($errno, $errstr, $errfile, $errline) {
echo "<b>Custom error:</b> [$errno] $errstr<br>";
echo " Error on line $errline in $errfile<br>";
}
// Set user-defined error handler function
set_error_handler("myErrorHandler");
$test=2;
// Trigger error
if ($test>1) {
trigger_error("A custom error has been triggered");
}
?>
Normally php script continues to run after E_NOTICE, is there a way to elevate this to fatal error in context of a function, that is I need only to exit on notice only in my functions but not on core php functions, that is globally.
You could create a custom error handler to catch E_NOTICEs.
This is untested but should go into the right direction:
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if ($errno == E_USER_NOTICE)
die ("Fatal notice");
else
return false; // Leave everything else to PHP's error handling
}
then, set it as the new custom error handler using set_error_handler() when entering your function, and restore PHP's error handler when leaving it:
function some_function()
{
// Set your error handler
$old_error_handler = set_error_handler("myErrorHandler");
... do your stuff ....
// Restore old error handler
set_error_handler($old_error_handler);
}
You use a custom error handler using set_error_handler()
<?php
function myErrorHandler($errno, $errstr, $errfile, $errline) {
if ($errno == E_USER_NOTICE) {
die("Died on user notice!! Error: {$errstr} on {$errfile}:{$errline}");
}
return false; //Will trigger PHP's default handler if reaches this point.
}
set_error_handler('myErrorHandler');
trigger_error('This is a E_USER_NOTICE level error.');
echo "This will never be executed.";
?>
Working Example