Debugging PRG in php - how to get errors to show? - php

How does one get php to stop on a non-fatal error inside a PRG (POST-Redirect-GET) segment, so you can see the error message, without the subsequent header() used for the redirect wiping out the error message?
Example Caller.htm
<form method="post" action="Callee.php">
<input type="text" name="PostData" />
<input type="submit" value="Go" />
</form>
Example Callee.php:
<?php
// POST section:
if($_POST) {
$var = $x; // non-fatal error: $x is missing.
header("Location: ". $_SERVER['REQUEST_URI']. 'Query'); die; // Redirect & GET
}
// GET section
// ...
What happens is that when testing, php reports the error for the missing $x, but then keeps moving, hits the header() and discards the error output, so you never see the error message on your screen.
You can temporarily put a die; (or exit;) just before the header, or comment out the header to test the code. Then when the code is working take out the die; or put the header back in. But this doesn't work very well in development as I've found a number of times an error crept in that I didn't even know was there.
Sometimes you can move the header up above where the errors are likely to occur. However, in the more general case one needs to be able to pass a query string to the GET section, so the header must be at the bottom of the POST section.
I think this might be what php calls an E_WARNING, "Run-time warnings (non-fatal errors). Execution of the script is not halted.", but I'm not sure.
I'm running 5.4.23:
error_reporting = E_ALL | E_STRICT
display_errors = "On"
log_errors = "On"
ignore_repeated_errors = "Off"
[All that I tried deleted. Jack has the answer below.]

First of all, you should assume things go right, so the redirect should take place inside the try scope:
if($_POST) {
try{
$var = $x; //BAD CODE, $x is missing.
header("Location: ". $_SERVER['REQUEST_URI']); // Redirect & GET
} catch (Exception $e) {
echo $e->getMessage();
}
exit;
}
Now, if you want your code to throw exceptions on warnings and notices, have a look at ErrorException and define a custom error handler that turns them into exceptions:
function exception_error_handler($errno, $errstr, $errfile, $errline )
{
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
Above code is taken from the documentation.
Preferably, you will want to use an error logger (related question):
// ...
} catch (Exception $e) {
$logger->fatal($e); // or $this->fatal($e);
}
Putting it together
function exception_error_handler($errno, $errstr, $errfile, $errline )
{
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
if($_POST) {
try{
$var = $x; //BAD CODE, $x is missing.
header("Location: ". $_SERVER['REQUEST_URI']); // Redirect & GET
} catch (Exception $e) {
echo $e->getMessage(); // or log the exception
}
exit;
}

Try echo your input;
echo $_SERVER['REQUEST_URI'];
You can see if your input is empty: before being redirected by header();

Related

Unable to catch Exception when using Eval function

I'm writing code that randomly generates expressions for a genetic algorithm for code optimisation purposes. The generated expressions are eval'ed for fitness. Some expressions will generate errors and I need to be able to catch these and act appropriately.
I have the following code (simplified from the original):
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
$expression = '$y=~!7;';
try {
eval($expression);
} catch (Exception $e){
echo 'Expression failed';
} catch (ParseError $e){
echo 'Expression failed';
}
This throws the following error:
PHP Fatal error: Unsupported operand types in ..... : eval()'d code on line ....
But this error is not caught in either catch block.
I've set my own error handler so that all errors are promoted to exceptions.
How do I catch this error?
Note: I am very aware that using eval is dangerous, but there is strictly no user input in my code.
At least in PHP 7.1+, eval() terminates the script if the evaluated code generate a fatal error. For example:
#eval('$content = (100 - );');
(Even if it is in the man, I'm note sure it acted like this in 5.6, but whatever)
To catch it, I had to do:
try {
eval('$content = (100 - );');
} catch (ParseError $e) {
$content = null;
}
This is the only way I found to catch the error and hide the fact there was one.

Exit execution on calling disabled function [duplicate]

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

PHP Error Logs + Add a Session Value to the log entry

This is most likely a silly question so I have no issues with it being closed etc.
I'm debugging PHP error logs and it would be of great advantage if I could see the user that created the specific error.
The userid is keep in the session.
Is it possible to customize PHP error logs to include a session value for debugging?
thx
Of course it is possible, I don't see why not:
try {
//some code
} catch (Exception $e) {
session_start();
$log = 'Caught exception: '. $e->getMessage(). "\n";
$log .= 'By user = '.$_SESSION['user_id']. "\n";
error_log($log);
}
To change error messages into Exception use this code:
<?php
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();
?>
ErrorException

Get error messages when I have a syntax error?

I have a class and the commented line is failing (clearly because I don't need the $ before displayname), however I ended up having to put a bunch of echo statements in to figure that out because an error isn't being thrown.
I'm hoping there is a way.
class RegisterModel {
var $displayname;
...
function RegisterModel() {
try {
if (empty($_POST) === false) {
// THIS LINE IS FAILING ... BUT I'M NOT GETTING AN ERROR
// I KNOW WHY IT'S FAILING ... BUT I WANT AN ERROR TO THROW
$this->$displayname = $_POST['displayname'];
...
}
}
catch (Exception $e) {
echo $e->getMessage();
}
}
}
Should the error be getting thrown into the catch and I'm just not using it right? Is there some global setting I need to set so that the errors are thrown?
set_error_handler(function($errno ,$errstr,$errfile,$errline,$errcontext){
if($errno & error_reporting()) throw new Exception($errstr,$errno);
});
Keep in mind you want to set error_reporting to your desired level.
You can try adding:
error_reporting(E_ALL);
ini_set('display_errors', 1);
If this displays the error, you have a potential run-time configuration error. You could adjust your configuration accordingly if it's impossible. You can look at the various error-related variables defined here.

how to make php exit on E_NOTICE?

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

Categories