Is there a way in PHP to try to include a file, but if the file contains errors that stop it from compiling to just skip that file from inclusion?
You can call php -l on the file in question. This will shell out and slow though.
it doesn't handle runtime errors like die() though.
test.php:
<?php
function check_code_file($filename)
{
$filename = escapeshellcmd($filename);
system("php -l $filename 2>/dev/null 1>/dev/null", $status);
if ($status) return false;
return true;
}
if (check_code_file('test-good.php'))
{
include('test-good.php');
}
if (check_code_file('test-bad.php'))
{
include('test-bad.php');
}
print "finished\n";
test-good.php:
<?php
print "here\n";
test-bad.php:
<?php
die(
$ php test.php
here
finished
A less than ideal solution I thought I'd mention here for posterity. The original idea is here.
You can capture the E_PARSE error you would receive on a bad 'require' and hand it off to a shutdown function. The idea is to suppress the parsing error...
register_shutdown_function('post_plugin_include');
#require 'bad_include.php';
Then do your primary execution after the fact.
function post_plugin_include() {
if(is_null($e = error_get_last()) === false) {
// do something else
}
}
Like I said, less than ideal but interesting nonetheless.
Depending on the PHP version you could use php_check_syntax() (practically the same as php -l).
But its a moo point really..
Either you need the stuff your trying to include or you dont include it.
Related
Well, I have run into a bit of a pickle here. I am needing to check some PHP for syntax errors. I noticed this bit that needs to run from the commandline:
php -l somefile.php
However, is there a way to run this from within a PHP file itself? I've been looking and have think that I can use parse_str function somehow to accomplish this by entering it into a $_GET, but can't quite understand how this works.
Someone else told me to use token_get_all() php function to determine this.
But I can't figure out how to do this with any approach? Can anyone here give me some sample code to get started perhaps?? I don't think using eval() is the way to go, although I had an eval($code) working, but don't think I should run the script if there are PHP syntax errors.
Any help on this is greatly appreciated, as always!
You could simply do shell_exec() like this:
$output = shell_exec('php -l /path/to/filename.php');
This gives you the output of the command line operation in the string $output.
It is safer to check the return status of php -l
$fileName = '/path/to/file.php';
exec("php -l {$fileName}", $output, $return);
if ($return === 0) {
// Correct syntax
} else {
// Syntax errors
}
See this fiddle to see it in action
I use token_get_all for this. I have some PHP code in the db. Before saving, I do
function is_valid_php_code_or_throw( $code ) {
$old = ini_set('display_errors', 1);
try {
token_get_all("<?php\n$code", TOKEN_PARSE);
}
catch ( Throwable $ex ) {
$error = $ex->getMessage();
$line = $ex->getLine() - 1;
throw new InvalidInputException("PARSE ERROR on line $line:\n\n$error");
}
finally {
ini_set('display_errors', $old);
}
}
Works like a charm. Syntax only. No missing variables, type incompayibility etc.
InvalidInputException is my own. You can make it anything, or return a bool, or handle the exception yourself.
I'm not sure if display_errors is necessary. It was at some point.
I would do it like this:
$php_file = 'The path to your file';
if(substr(`php -l $php_file`, 0, 16) == 'No syntax errors') {
// Correct syntax
} else {
// Error
}
php_check_syntax should do the trick. If you're running PHP >= 5.05, see the first comment in the comments section for the implementation.
You can use exec to check for syntax errors.
$tempFile = path/of/file
$syntaxParseError = strpos(exec('php -l '.$tempFile), 'No syntax errors detected') === false;`
Unfortunately, this will not give you the line number or tell you anything about the error. For that you will either need to install static analyzer on your server Is there a static code analyzer [like Lint] for PHP files? or write your own parser.
NB. token_get_all() will not determine anything on its own, but it useful function for making a parser.
Why use the shell at all?
function syntax_is_valid($code)
{
try
{
#eval($code);
}
catch (ParseError $e)
{
return false;
}
return true;
}
Alternatively use $e->getMessage() for more info.
I read that file_get_content is synchronous, but when I tried the code below I dont' think so :
$url = "http://foo.com";
$a = array("file11.php", "file2.php", "file3.php");
foreach ($a as $file)
{
$final = $url . "/" . $file;
print "Calling $final ...";
$res = file_get_contents($final);
if ($res)
print "OK";
else
print "ERR!";
print "<br>";
}
Each file executes some complex tasks, so I know the minimal excution time of any script, but this code runs very fastly and seems not to wait each request ! How can I wait for each file request?
Thanks :)
The above code is definitely synchronous. So if you say that the code exits after a few seconds, while it should be a lot longer, then you probably have a problem with the code.
Try to wrap this code in a try {} catch. And print the error. See what it says.
Try { code here } catch (Exception $e) { }
Also, most default settings in the php.ini for MAX_EXECUTION for a script is 30 seconds. After that it will exit on a fatal timeout error too. Check the setting in your php.ini and adjust it to your needs.
Edit:
Gathering your comments, I now assume you are trying to execute the php files you are referring to. This makes your question very confusing and the tags just wrong.
The code you use in your example only reads the contents of the file, so it's not executing anything. Which explains why it returns so fast, while you expect it to take a while.
If you want to execute the referred php files, approach it like this:
Include_once( $final );
Instead of opening the contents.
From inside my index.php file, say, I'd like to check if another PHP file executes without error (and include it, if so), and if it does in fact fail and returns a fatal error, I'd obviously like to not include it. Any suggestions? Thanks...
You may use -l parameter of php CLI:
php -l filename.php
and parse the output.
$o = `php -l filename.php`;
if (strpos($o, 'No syntax errors detected') !== false) {
echo 'No errors';
} else {
echo 'There are errors';
}
You probably don't want to run the second file separately. That said, you can do one of two things...
1.) if you really want to use it as an include that executes separately you could call it with something such as CURL and have it output either the expected result or a failure message that would then be read and acted on accordingly.
2.) Include your function/class/etc execution in a try/catch statement to properly handle any errors encountered. http://php.net/manual/en/language.exceptions.php might help you a little more with this method.
This runs the script as a separate process, with no shared variables/functions/state/scope etc...
$cmd = 'php file.php';
exec($cmd, $ar, $exit_status);
$wasFatal = $exit_status == 255;
There's a real good chance it gets run with a php.ini that's different than whatever your webserver php.ini is, so expect differences in config and maybe even php version.
Well, I have run into a bit of a pickle here. I am needing to check some PHP for syntax errors. I noticed this bit that needs to run from the commandline:
php -l somefile.php
However, is there a way to run this from within a PHP file itself? I've been looking and have think that I can use parse_str function somehow to accomplish this by entering it into a $_GET, but can't quite understand how this works.
Someone else told me to use token_get_all() php function to determine this.
But I can't figure out how to do this with any approach? Can anyone here give me some sample code to get started perhaps?? I don't think using eval() is the way to go, although I had an eval($code) working, but don't think I should run the script if there are PHP syntax errors.
Any help on this is greatly appreciated, as always!
You could simply do shell_exec() like this:
$output = shell_exec('php -l /path/to/filename.php');
This gives you the output of the command line operation in the string $output.
It is safer to check the return status of php -l
$fileName = '/path/to/file.php';
exec("php -l {$fileName}", $output, $return);
if ($return === 0) {
// Correct syntax
} else {
// Syntax errors
}
See this fiddle to see it in action
I use token_get_all for this. I have some PHP code in the db. Before saving, I do
function is_valid_php_code_or_throw( $code ) {
$old = ini_set('display_errors', 1);
try {
token_get_all("<?php\n$code", TOKEN_PARSE);
}
catch ( Throwable $ex ) {
$error = $ex->getMessage();
$line = $ex->getLine() - 1;
throw new InvalidInputException("PARSE ERROR on line $line:\n\n$error");
}
finally {
ini_set('display_errors', $old);
}
}
Works like a charm. Syntax only. No missing variables, type incompayibility etc.
InvalidInputException is my own. You can make it anything, or return a bool, or handle the exception yourself.
I'm not sure if display_errors is necessary. It was at some point.
I would do it like this:
$php_file = 'The path to your file';
if(substr(`php -l $php_file`, 0, 16) == 'No syntax errors') {
// Correct syntax
} else {
// Error
}
php_check_syntax should do the trick. If you're running PHP >= 5.05, see the first comment in the comments section for the implementation.
You can use exec to check for syntax errors.
$tempFile = path/of/file
$syntaxParseError = strpos(exec('php -l '.$tempFile), 'No syntax errors detected') === false;`
Unfortunately, this will not give you the line number or tell you anything about the error. For that you will either need to install static analyzer on your server Is there a static code analyzer [like Lint] for PHP files? or write your own parser.
NB. token_get_all() will not determine anything on its own, but it useful function for making a parser.
Why use the shell at all?
function syntax_is_valid($code)
{
try
{
#eval($code);
}
catch (ParseError $e)
{
return false;
}
return true;
}
Alternatively use $e->getMessage() for more info.
file1.php and file2.php with die(); function.
include.php:
<? include 'file1.php';
include 'file2.php' ?>
file1.php
<? echo 'included'; die(); ?>
file2.php
<? echo 'not included'; die(); ?>
How can I include both files with die(); function?
Non-English Speakers:
You can provide your question in your native language as well, and somebody here may be able to translate it for you. Just make your best effort to ask in English, and add your native tongue below.
If you would like to test whether the includes happened successfully, you can test the return value of the include function itself:
// http://us3.php.net/manual/en/function.include.php Example #4
if ((include 'file1.php') != 'OK') {
die();
}
You may also consider require() instead of include() depending on your needs:
require() is identical to include() except upon failure it will also produce a fatal E_ERROR level error. In other words, it will halt the script whereas include() only emits a warning (E_WARNING) which allows the script to continue.
If I understand correctly what you are trying to do then unfortunately it isn't possible.
die(); will stop the script from executing at the point from where it is called.
Here is how to include a file, or die with a message if the include fails code sample.
(include('file.php')) || die('Failed to include file!');
if (!condition){
include_once('./inc/header.inc.php');
echo "Errormessage";
include_once('./inc/footer.inc.php');
die();
}
I hope this is what you wanted.
Just a minor improvement to LorenzoP's method:
(#include("file.php")) or die("Failed to include!");
// notice the # sign!
This way, you save yourself 2 ugly lines of php warning when inclusion fails. Otherwise I think this is truly the best way to handle failed includes. (Also, his answer should be the accepted one.)
If the execution of your included file is not dependent on the current file (no shared variables, functions, etc.), then use
file_get_contents('link_to_file.php');
instead of an include method. When you force the file to execute independently it will not make a effect in the script execution.
die() is just an exit with an error, you can't include files with it and I don't really understand why you want to. Could you provide more details as to what you're trying to accomplish?