3

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.]

Elliptical view
  • 3,338
  • 1
  • 31
  • 28
  • 1
    Did you mean PRG (Post, Redirect, Get) instead? – Ja͢ck Feb 17 '14 at 01:36
  • 2
    Did you mean RPG(Rocket Propelled Grenade)... you could write to a file, log, email etc. Take a look @ http://www.php.net/manual/en/function.error-log.php – Ronni Skansing Feb 17 '14 at 01:37
  • @RonniSkansing you hit that bro :D – Vainglory07 Feb 17 '14 at 01:42
  • @Jack, thank you. Yes I meant PRG. – Elliptical view Feb 17 '14 at 01:45
  • How about just make sure that the most common stuff that raise warnings is checked. Your own answer to this question makes little sense. If you want to stop it, why not isset($x) or die; For exceptions if(isset($x)===false){ throw new AnykindOfException } ? Is it for typo handling? – Ronni Skansing Feb 17 '14 at 04:04
  • @Ronni, I know it was a terrible solution. Jack just nailed it. Someday I need to learn more about the difference between errors and exceptions and how to use each, but that's a Q for another day. Thanks you. – Elliptical view Feb 17 '14 at 04:15
  • @Elipticalview Well Jack is great, it is also a great solution for the logging errors/whatever when your ajax hits the backend. – Ronni Skansing Feb 17 '14 at 04:17

2 Answers2

2

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;
}
Community
  • 1
  • 1
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • +1 for link to related question, gives good detail on limitations of error_log – Ronni Skansing Feb 17 '14 at 01:52
  • Unfortunately, in your first solution while literal 'BAD CODE' caused the parser to stop (and was a poor simplification on my part), the actual test case: $var = $x; does not stop the parser. So this idea does not fix the problem. Your second idea is good I think, but it means I now have to check a 2nd place for error, but I can do that. Am thinking about an email so I know I'll get it. – Elliptical view Feb 17 '14 at 01:59
  • I will let you know if the third idea pans out. Looked at it already once. Will look again. Thank you. – Elliptical view Feb 17 '14 at 02:01
  • @Elipticalview I didn't take "Bad code" literally, because a parse error is obviously not your problem. A logger can also send you an email btw. – Ja͢ck Feb 17 '14 at 02:04
  • So I tried the logging idea, with a simple test writing to a file, but it doesn't work. I've updated my question to show what I've tried. Thank you again for looking at this. – Elliptical view Feb 17 '14 at 02:40
  • @Elipticalview You forgot to register the error handler; without it, there will be no exceptions to catch. – Ja͢ck Feb 17 '14 at 02:46
  • @Jack, ok, not sure how to do that, but I'll look it up. Thanks. – Elliptical view Feb 17 '14 at 02:49
  • @Jack, so I put in both an exception handler and an error handler, but neither of them catch anything. But I did find this in the php manual, "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." – Elliptical view Feb 17 '14 at 02:59
  • 1
    @Elipticalview I've updated my answer, I think you just put the code in a wrong place. – Ja͢ck Feb 17 '14 at 03:57
  • So from the looks of what you did, was to see that what was being generated by the missing $x was an 'error'. Then you convert this error into an exception (which can be thrown and caught). And that exception calls another exception which is uncaught and displays the message. The this falls thru and hits the exit. I think I understand. Very tricky. Nice work. Thank you again. – Elliptical view Feb 17 '14 at 04:54
0

Try echo your input;

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