• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • php_check_syntax()

    (PHP 5 < 5.0.5)

    检查PHP的语法(并执行)指定的文件

    说明

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

    对指定的$filename进行语法检查,检测脚本的错误。

    此函数除了会执行(但不会输出)$filename,其他与命令行中使用php -l相似。

    例如,如果函数在文件$filename中被定义了,则该函数在执行php_check_syntax()后可用。但是$filename输出内容不会被输出。

    Note:

    因为某些技术原因,该函数已被弃用,并且从PHP中移除了。请以commandline使用php -l somefile.php取而代之。

    参数

    $filename

    需要被检测的文件。

    $error_message

    如果使用了参数$error_message,它会包含语法检测出的错误信息。$error_message以引用方式传递。

    返回值

    如果语法检测通过返回TRUE,未通过或者文件无法打开则返回FALSE

    更新日志

    版本说明
    5.0.5函数从PHP中移除。
    5.0.3php_check_syntax()之后调用exit()会导致一个段错误。
    5.0.1$error_message通过引用传递

    范例

    php -l somefile.php

    以上例程的输出类似于:

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

    参见

    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;
    }
    ?>
    
    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.

    上篇:pack()

    下篇:php_strip_whitespace()