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.
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 have a file called functions.php.
This file consists includes to all the other function files, for example:
include_once("user_functions.php");
include_once("foo_functions.php");
I would like to catch errors where when I screw a code in one of those files, It wouldn't give the error to the entire system.
For example, if there is a parser error in foo_functions.php it will just not include it in functions.php.
Is that possible?
As of PHP 7, most eval/include errors, such as ParseError can be catched:
try {
include_once(__DIR__ . '/test.php');
} catch (\Throwable $e) {
var_dump($e);
}
Parser errors are fatal errors, so you can't catch them. See this question and answer for more details.
What you can do if you can run exec() is call php -l thefilename.php and check the result. See the manual for information on how this works. There are a few problems here, however:
This is extremely dangerous, because you are passing information to the command line. You absolutely must filter any user input very carefully, or you would be giving the user very broad access to your system.
exec() is often disabled, as it should be, because of the extremely high security risks of using it incorrectly.
There's really no good reason to include a file that you haven't already validated for syntax errors. If this is for plugins or something, then I understand your reasoning. If it is code you have control over, however, you should validate before putting it into production.
This code can check if file is exist or not, if file exist than include it.
<?
if(!is_file('user_functions.php')){
//There is no file user_functions.php . You may use file_put_contents('user_functions.php','<? //content ?>');
}else{
//ther is file user_functions.php, so include it.
include 'user_functions.php';
}
?>
And this one help you get syntax errors (PHP 7+ only)
<?
try {
include('user_functions.php');
}catch (ParseError $e) {
echo 'Error: '.$e->getMessage();
//syntax error, unexpected end of file, expecting ',' or ';'
}
?>
so if you use PHP 7+ you may use:
<?
if(!is_file('user_functions.php')){
echo 'Error: file is not exist';
}else{
//check errors
try {
include('user_functions.php');
}catch (ParseError $e) {
echo 'Error: '.$e->getMessage();
//syntax error, unexpected end of file, expecting ',' or ';'
}
}
?>
What if you put
error_reporting(E_ALL);
ini_set("display_errors", 1);
at the beginning of foo_functions.php ?
include() and include_once() return false if they fail. You can use this to check if the included files were successful.
if (!include('user_functions.php'))
echo 'user functions failed to include';
if (!include('foo_functions.php'))
echo 'foo_functions failed to include';
By changing the echos to handle your error logic, you should be able to do what you are asking.
The solution that I am using feels like a band-aid solution, but it will give you control back.
The idea is to use "eval()" to first check for errors. Also, ignore errors with the # in the beginning. Of course you will need to be careful with eval, so don't ever let users feed anything to it.
// first "eval" the file to see if it contains errors
$txt = file_get_contents($template_filename);
// eval starts out in php-mode. get out of it.
$txt = '?' . '>' . $txt;
ob_start();
$evalResult = #eval($txt);
ob_end_clean();
// if there are no errors
if($evalResult !== FALSE) {
require($template_filename);
} else {
error_log(print_r(error_get_last(), TRUE));
}
Please note that I think "file_get_contents + eval" = "require", or very close to it, so you may be able to just skip the require-part.
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.
I have a basic if-then-else statement to catch an "exception" but I can not do much in case the exception happens so I would like to exit my script at this point with a fatal error. How can I do this?
The code is:
if(ksort($hFileList)) $fileList = array_values($hFileList);
else ???
That is: I am duing all I can to ensure my $hFileList is there and looks as it should, but in case something unexpected happens, I would like to produce a standard php fatal error.
Shall I simply get rid of the if and let it "crash" instead?
just put a call to phps trigger_error method:
if( true === $errorCase ) {
trigger_error( $yourErrorMessage, E_ERROR );
}
that'll stop your script with a fatal error.
see php documentation also:
http://php.net/manual/de/function.trigger-error.php
You can also you die() function like:
if(ksort($hFileList))
{
$fileList = array_values($hFileList);
}
else
{
die("Error Occurred");
}
You could actually use trigger_error(..) if you do not want any exception-catching mechanisms.
You might like a more readable construct:
ksort($hFileList) or trigger_error("IT FAILED!",E_ERROR);
$fileList = array_values($hFileList);
Use good old exit() function maybe?
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.