When PHP emits a PHP Notice to the log, it contains the file name and the line number where the problem occurred. In the case of a large application, this often isn't enough to reproduce the problem. What would really help is some additional information, most obviously the URL that was being called at the time this notice occurred.
Is there a way to customize the PHP Notice message in PHP >= 7?
Create your own error handler and catch the notices then log the message with whatever information you need. The code below produces the following the PHP error log file.
[27-Feb-2019 13:55:09 America/New_York] 8 Undefined variable: hello
from URI /customnotice.php
function myErrorHandler($errno,$errstr, $errfile, $errline) {
if ($errno == 8) { // this is a notice
error_log($errno . ' ' . $errstr . ' from URI ' . $_SERVER['REQUEST_URI']);
}
}
$old_error_handler = set_error_handler("myErrorHandler");
echo $hello; // will throw a notice for testing
Related
What happens with set_error_handler() on PHP7 now that all errors are exceptions? makes me think that recoverable errors can be caught but that does not appear to be the case, as demonstrated here:
<?php
$_SERVER['TEST'] = new stdClass;
try {
phpinfo();
} catch (\Throwable $e) {}
If you run that code you'll get this as the output:
$_SERVER['argc'] => 1
$_SERVER['TEST'] =>
Recoverable fatal error: Object of class stdClass could not be converted to string in /Users/username/zzz.php on line 6
So clearly an error is being "issued" but one is not being thrown, unless I'm misunderstanding something?
Not all errors were converted to Throwable errors in PHP 7.
Actually, the docs say:
most errors are now reported by throwing Error exceptions.
(Emphasis mine). Most !== All.
Some errors are still not catchable.
Funnily enough, the error message used you get used to say "Catchable Fatal Error" instead of "Recoverable Fatal Error" before PHP 7.1 was released.
This was reported as a bug, but the solution implemented by the devs was change the error string from Catchable to Recoverable to dispel misconceptions.
In the specific case you are testing, it seems that phpinfo() raises a recoverable error instead of throwing an Error, so it makes sense you can't catch it this way.
Still, not all hope is lost.
What you could do is convert all errors to exceptions by implementing your own error handler. An example of this is described on the ErrorException documentation:
function exception_error_handler($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting
return;
}
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler("exception_error_handler");
The neat thing of this example is that it takes into account your error reporting settings, so only errors that would have been reported under your settings are actually thrown as exceptions. Otherwise, nothing happens.
Testing your code:
<?php
function exception_error_handler($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting
return;
}
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler("exception_error_handler");
$_SERVER['TEST'] = new stdClass;
try {
phpinfo(INFO_VARIABLES);
} catch (\Throwable $e) {echo 'CAUGHT!!!!!!';}
prints the following output:
$_SERVER['TERM_SESSION_ID'] => w0t1p0:xxx-cxx-xxxxxxx-xxxxx
$_SERVER['SSH_AUTH_SOCK'] => /private/tmp/com.apple.launchd.xxxxxxxx/Listeners
$_SERVER['LC_TERMINAL_VERSION'] => 3.3.2
....
$_SERVER['argc'] => 1
$_SERVER['TEST'] =>
CAUGHT!!!!!!%
Is it possible to capture/gather all the errors on page and concatenate them to a string by using:
$allErrors = "";
$allErrors .= error_get_last(); // Each time an error shows up
I like to log errors in my database and would prefer to log all these PHP errors since I already have SQL-related PHP Fatal Errors logged.
error_get_last(), like the name is suggesting, only gives you the last error. And the fact that most errors will stop your script from running will get you only the last one and none of the previous ones. But you can set an own handler to catch every thrown error and exception. Here is an example
//function for exception handling
function handle_exception (Exception $exception) {
//here you can save the exception to your database
}
//function for error handling
function handle_error ($number, $message, $file, $line, $context = null) {
//pass/throw error to handle_exception
throw new ErrorException ($message, 0, $number, $file, $line);
}
//set error-handler but only for E_USER_ERROR and E_RECOVERABLE_ERROR
set_error_handler ('handle_error', E_USER_ERROR|E_RECOVERABLE_ERROR);
//exception-handler
set_exception_handler ('handle_exception');
I want to log all error's that are generated whit error_reporting(E_ALL); in a logfile.
Thus the error's you normaly see when there is an error in the PHP script.
I tried many thing but the closest that i come was whit
asdasc(); // generate error
$i=error_get_last();
if($i['message']!==''){
error_log(date('Y-m-d-h:m:s') . " | type = " .$i ['type']." message = " .$i ['message']." file = " .$i ['file']." line = " .$i ['line'] , 3, "my-errors.log");}
This way i see that there was an error at a date,but what i want to see is what error i should see if it was on mine screen. something like :
SQLSTATE[HY000] [1045] Access denied for user 'root'#'localhost' (using password: NO) OR
Fatal error: Call to undefined function blabla() in C:\xampp\htdocs...\index.php on line 125
Is there a way to do this?
thnx in advanced.
Use error_get_last():
error_log(date('Y-m-d-h:m:s') . " | error = " . print_r(error_get_last(), true), 3, "my-errors.log");
You can as well set up your own error handling class in your application:
class MyErrorHandlerClass
{
public function MyErrorHandlerMethod($errno, $errmsg, $filename, $linenum, $vars)
{
// log you error
}
}
Then you can define your own error handler:
$ErrorHandler = new MyErrorHandlerClass();
set_error_handler(array($ErrorHandler, 'MyErrorHandlerMethod'));
error_reporting() btw. does not generate errors, it only controls the level of displaying errors. When an error occurs, its stack trace is always generated.
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");
}
?>
If I include a file in to php. If there is any fatal error in that php then is there any way to skip that .
<?php
include "somefile.php";
echo "OK"; // Is there any way to print this OK If there is any fatal error on somefile.php
?>
I need to include this somefile.php file. It may return fatal error
for some host. I want to skip this file for those host.
Please Advice me.
With this, you can define your own continuation function that will take over in case of a fatal error. This uses register_shutdown_function() to intercept the fatal error.
Usage:
function my_continuation_func($filename, $arg2) {
// On fatal error during include, continue script execution from here.
// When this function ends, or if another fatal error occurs,
// the execution will stop.
}
include_try('my_continuation_func', array($filename, $arg2));
$data = include($filename);
$error = include_catch();
If a fatal error occurs (like a parse error), script execution will continue from my_continuation_func(). Otherwise, include_catch() returns true if there was an error during parsing.
Any output (like echo 'something';) from the include() is treated as an error. Unless you enabled output by passing true as the third argument to include_try().
This code automatically takes care of possible working directory changes in the shutdown function.
You can use this for any number of includes, but the second fatal error that occurs cannot be intercepted: the execution will stop.
Functions to be included:
function include_try($cont_func, $cont_param_arr, $output = false) {
// Setup shutdown function:
static $run = 0;
if($run++ === 0) register_shutdown_function('include_shutdown_handler');
// If output is not allowed, capture it:
if(!$output) ob_start();
// Reset error_get_last():
#user_error('error_get_last mark');
// Enable shutdown handler and store parameters:
$params = array($cont_func, $cont_param_arr, $output, getcwd())
$GLOBALS['_include_shutdown_handler'] = $params;
}
function include_catch() {
$error_get_last = error_get_last();
$output = $GLOBALS['_include_shutdown_handler'][2];
// Disable shutdown handler:
$GLOBALS['_include_shutdown_handler'] = NULL;
// Check unauthorized outputs or if an error occured:
return ($output ? false : ob_get_clean() !== '')
|| $error_get_last['message'] !== 'error_get_last mark';
}
function include_shutdown_handler() {
$func = $GLOBALS['_include_shutdown_handler'];
if($func !== NULL) {
// Cleanup:
include_catch();
// Fix potentially wrong working directory:
chdir($func[3]);
// Call continuation function:
call_user_func_array($func[0], $func[1]);
}
}
Fatal means fatal ...
There is no way to recover from a fatal error.
You can use register_shutdown_function.
<?php
function echoOk()
{
echo "OK";
}
register_shutdown_function(function ()
{
$error = error_get_last();
// to make sure that there is any fatal error
if (isset($error) &&
($error['type'] == E_ERROR
|| $error['type'] == E_PARSE
|| $error['type'] == E_COMPILE_ERROR
|| $error['type'] == E_CORE_ERROR))
{
echoOk();
}
});
include "somefile.php";
echoOk();
But you can do it only once. Any further fatal error will stop execution.
PHP won't tolerate with Fatal Errors. Best to check the included file and solve it.
Actually, you can try looking at register-shutdown-function, but it's not recommended to run away from your problems.
Yes, there is. It can be done through a simple if statement
You Have:
<?php
include "somefile.php";
echo "OK"; // Is there any way to print this OK If there is any fatal error on
?>
Try This:
<?php
if(include "somefile.php"){
// echo do something if success
}else{
echo "OK";
}
edit: I missed the word fatal. As stated, you can't recover from a fatal error. If it is just an exception the hastly writen response below will work.
Including another php module is the same as that code being inserted inline, so a simple try-catch statement should work:
<?php
try {
include "somefile.php";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
echo "OK";
?>
Try to set a set_error_handler() function that doesn't die on fatal errors, but instead Apache crashed. In other words, PHP needs to die so that the system doesn't.
See this LINK
Fatal Error means there is something seriously wrong with the including code. As #Orangepill said there is no way to stop this fatal error message popping up. Please go through your coding and find the error.