views:

525

answers:

6

I have a PHP app "index.php" that, for various reasons, needs to run other PHP scripts by using include_once on that other script. That other script isn't very stable, so is there some way to do a safe include_once that won't halt the caller?

i.e.:

<?php

safely_include_once('badfile.php'); // MAY throw syntax error, parse error, other badness
echo "I can continue execution after error";

?>

(I know what a bad idea this can be, etc., rest assured this isn't production-environment stuff.)

+6  A: 

You can just

@include "fileWithBadSyntax.php";

Which, from my quick tests, works for both parse errors or errors thrown with trigger_error().

timdev
Does the job, would it be possible to capture the error details with this approach?
Wally Lawless
This approach will silence all errors. See KyleFarris' answer for a method that will catch errors and can optionally keep them quiet (IE, custom error handling).
The Wicked Flea
Indeed, Kyle's answer is more powerful
timdev
+1  A: 

Would it be possible to change your architecture and turn "badfile.php" into a web service? Instead of including it directly into your codebase, you would call it over the network and parse or include its output. This will get you around parse errors, you could also avoid potentially malicious code if you have badfile.php's environment limited appropriately (using safe_mode, or running a separate web server process with limited privileges).

pix0r
@pix0r: This would certainly work but depending on the scope of his project it might just be a bit overkill and inelegant.
KyleFarris
+5  A: 

You could do a try/catch block

<?php
try {
    include("someFile.php");
} catch (Exception $e) {
    // Should probably write it to a log file, but... for brevity's sake:
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}
?>

Now, it will only include the file if there is no error. If there is an error, it will just skip this stuff and write the exception (like, in the comments, preferably to a log file or something).

For more info: http://us2.php.net/manual/en/language.exceptions.php

KyleFarris
A parse error will stop PHP in the middle of the included file and it won't return to the `catch` block.
erjiang
A: 

In badfile.php you could make it return a value:

<?php
//inestable instructions.


return true; ?>

then on main file you could do:

 <?php

 if (require($badFile)) {
     //if it was true continue with normal execution
 } else {
     echo "Error: ". error_get_last();
 }
elviejo
+2  A: 

None of these answers will work. The top-voted one, which says to @include(), will still terminate the first script if there is a parse error in the included file.

You can't eval() it, you can't try/catch it, and every way of calling include or require will terminate all execution in the script.

This question remains OPEN and UNSOLVED.

http://bugs.php.net/bug.php?id=41810

This is a bug in PHP, and this functionality's been missing since at least 2006. They classified the bug as "bogus" because, they claim, includes() and requires() happen at compile-time.

This goes out the window if you are generating the string arguments to include() and/or require() at RUNTIME, or doing an eval() over a string containing code that runs an include().

sneak
A: 

Here's the only real solution I've been able to find:

function safe_include($fn) {
        $fc = file_get_contents($fn);
        if(!eval($fc)) {
                return 0;
        }
        return 1;
}

Note that the above code means you have to take out the opening statements from your to-be-included files, or do the following:

eval("?>" . $fc)

The problem is that you can't call require() or include() or their _once() variants at any point and expect them not to terminate everything, including any error handlers. PHP will completely stop processing everything when it encounters a parse error.

The only exception to this is the string inside of an eval(). The problem is, though, that you can't really do this:

eval('require($fn);'); 

...because the require() inside the eval'd string will still stop. You have to read in the contents, pray that the file in question doesn't include() or require() further, and eval() it.

The real solution? Skip PHP. :/

sneak