php_check_syntax

(PHP 5 < 5.0.5)

php_check_syntax Check the PHP syntax of (and execute) the specified file

Opis

php_check_syntax ( string $filename [, string &$error_message ] ) : bool

Performs a syntax (lint) check on the specified filename testing for scripting errors.

This is similar to using php -l from the commandline except that this function will execute (but not output) the checked filename.

For example, if a function is defined in filename, this defined function will be available to the file that executed php_check_syntax(), but output from filename will be suppressed.

Informacja:

For technical reasons, this function is deprecated and removed from PHP. Instead, use php -l somefile.php from the commandline.

Parametry

filename

The name of the file being checked.

error_message

If the error_message parameter is used, it will contain the error message generated by the syntax check. error_message is passed by reference.

Zwracane wartości

Returns TRUE if the lint check passed, and FALSE if the link check failed or if filename cannot be opened.

Rejestr zmian

Wersja Opis
5.0.5 This function was removed from PHP.
5.0.3 Calling exit() after php_check_syntax() resulted in a Segfault.
5.0.1 error_message is passed by reference.

Przykłady

php -l somefile.php

Powyższy przykład wyświetli coś podobnego do:

PHP Parse error: unexpected T_STRING in /tmp/somefile.php on line 81

Zobacz też:

add a note add a note

User Contributed Notes 2 notes

up
-8
matt dot nospam at pryor dot org dot uk
16 years ago
While developing an app where I have to include PHP files written by a user, I came across the following problem:

I used "php -l somefile.php" to check the syntax of the file I was about to include and if it passed, I would include it - so far so good. But in some test cases, the file I was including would have other includes/requires inside it. If one of these was invalid, then I would still get the parse error that I was trying to avoid.

I got round it using this:

<?php
   
function CheckSyntax($fileName, $checkIncludes = true)
    {
       
// If it is not a file or we can't read it throw an exception
       
if(!is_file($fileName) || !is_readable($fileName))
            throw new
Exception("Cannot read file ".$fileName);
       
       
// Sort out the formatting of the filename
       
$fileName = realpath($fileName);
       
       
// Get the shell output from the syntax check command
       
$output = shell_exec('php -l "'.$fileName.'"');
       
       
// Try to find the parse error text and chop it off
       
$syntaxError = preg_replace("/Errors parsing.*$/", "", $output, -1, $count);
       
       
// If the error text above was matched, throw an exception containing the syntax error
       
if($count > 0)
            throw new
Exception(trim($syntaxError));
       
       
// If we are going to check the files includes
       
if($checkIncludes)
        {
            foreach(
GetIncludes($fileName) as $include)
            {
               
// Check the syntax for each include
               
CheckSyntax($include);
            }
        }
    }
   
    function
GetIncludes($fileName)
    {
       
// NOTE that any file coming into this function has already passed the syntax check, so
        // we can assume things like proper line terminations
           
       
$includes = array();
       
// Get the directory name of the file so we can prepend it to relative paths
       
$dir = dirname($fileName);
       
       
// Split the contents of $fileName about requires and includes
        // We need to slice off the first element since that is the text up to the first include/require
       
$requireSplit = array_slice(preg_split('/require|include/i', file_get_contents($fileName)), 1);
       
       
// For each match
       
foreach($requireSplit as $string)
        {
           
// Substring up to the end of the first line, i.e. the line that the require is on
           
$string = substr($string, 0, strpos($string, ";"));
           
           
// If the line contains a reference to a variable, then we cannot analyse it
            // so skip this iteration
           
if(strpos($string, "$") !== false)
                continue;
           
           
// Split the string about single and double quotes
           
$quoteSplit = preg_split('/[\'"]/', $string);
           
           
// The value of the include is the second element of the array
            // Putting this in an if statement enforces the presence of '' or "" somewhere in the include
            // includes with any kind of run-time variable in have been excluded earlier
            // this just leaves includes with constants in, which we can't do much about
           
if($include = $quoteSplit[1])
            {
               
// If the path is not absolute, add the dir and separator
                // Then call realpath to chop out extra separators
               
if(strpos($include, ':') === FALSE)
                   
$include = realpath($dir.DIRECTORY_SEPARATOR.$include);
           
               
array_push($includes, $include);
            }
        }
       
        return
$includes;
    }
?>

This checks as many of the includes inside the file as it possibly can without executing anything.
up
-9
kevin at metalaxe dot com
15 years ago
I've given it some thought and rewritten my function to take full advantage of the CLI -l option (that's lower L). It requires that you enable error reporting via your own php.ini file (which you should edit the function to apply) otherwise the return result is a worthless "Error parsing".

Anyway, I hope this is useful for someone. I'm sure it could use improvement, so use at your own risk. Demo here:
http://kevinpeno.com/projects/php_syntax_check.php

<?php
/**
*    Check Syntax
*    Performs a Syntax check within a php script, without killing the parser (hopefully)
*    Do not use this with PHP 5 <= PHP 5.0.4, or rename this function.
*
*    @params    string    PHP to be evaluated
*    @return    array    Parse error info or true for success
**/
function php_check_syntax( $php, $isFile=false )
{
   
# Get the string tokens
   
$tokens = token_get_all( '<?php '.trim( $php  ));
   
   
# Drop our manually entered opening tag
   
array_shift( $tokens );
   
token_fix( $tokens );

   
# Check to see how we need to proceed
    # prepare the string for parsing
   
if( isset( $tokens[0][0] ) && $tokens[0][0] === T_OPEN_TAG )
      
$evalStr = $php;
    else
       
$evalStr = "<?php\n{$php}?>";

    if(
$isFile OR ( $tf = tempnam( NULL, 'parse-' ) AND file_put_contents( $tf, $php ) !== FALSE ) AND $tf = $php )
    {
       
# Prevent output
       
ob_start();
       
system( 'C:\inetpub\PHP\5.2.6\php -c "'.dirname(__FILE__).'/php.ini" -l < '.$php, $ret );
       
$output = ob_get_clean();

        if(
$ret !== 0 )
        {
           
# Parse error to report?
           
if( (bool)preg_match( '/Parse error:\s*syntax error,(.+?)\s+in\s+.+?\s*line\s+(\d+)/', $output, $match ) )
            {
                return array(
                   
'line'    =>    (int)$match[2],
                   
'msg'    =>    $match[1]
                );
            }
        }
        return
true;
    }
    return
false;
}

//fixes related bugs: 29761, 34782 => token_get_all returns <?php NOT as T_OPEN_TAG
function token_fix( &$tokens ) {
    if (!
is_array($tokens) || (count($tokens)<2)) {
        return;
    }
  
//return of no fixing needed
   
if (is_array($tokens[0]) && (($tokens[0][0]==T_OPEN_TAG) || ($tokens[0][0]==T_OPEN_TAG_WITH_ECHO)) ) {
        return;
    }
   
//continue
   
$p1 = (is_array($tokens[0])?$tokens[0][1]:$tokens[0]);
   
$p2 = (is_array($tokens[1])?$tokens[1][1]:$tokens[1]);
   
$p3 = '';

    if ((
$p1.$p2 == '<?') || ($p1.$p2 == '<%')) {
       
$type = ($p2=='?')?T_OPEN_TAG:T_OPEN_TAG_WITH_ECHO;
       
$del = 2;
       
//update token type for 3rd part?
       
if (count($tokens)>2) {
           
$p3 = is_array($tokens[2])?$tokens[2][1]:$tokens[2];
           
$del = (($p3=='php') || ($p3=='='))?3:2;
           
$type = ($p3=='=')?T_OPEN_TAG_WITH_ECHO:$type;
        }
       
//rebuild erroneous token
       
$temp = array($type, $p1.$p2.$p3);
        if (
version_compare(phpversion(), '5.2.2', '<' )===false)
           
$temp[] = isset($tokens[0][2])?$tokens[0][2]:'unknown';

       
//rebuild
       
$tokens[1] = '';
        if (
$del==3) $tokens[2]='';
       
$tokens[0] = $temp;
    }
    return;
}
?>
To Top