note 80878 added to function.php-check-syntax

From: Date: Tue, 05 Feb 2008 13:35:55 +0000
Subject: note 80878 added to function.php-check-syntax
Groups: php.notes 
Request: Send a blank email to php-notes+get-135789@lists.php.net to get a copy of this message
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. ---- Server IP: 87.124.64.96 Probable Submitter: 138.38.249.188 ---- Manual Page -- http://www.php.net/manual/en/function.php-check-syntax.php Edit -- https://master.php.net/note/edit/80878 Del: integrated -- https://master.php.net/note/delete/80878/integrated Del: useless -- https://master.php.net/note/delete/80878/useless Del: bad code -- https://master.php.net/note/delete/80878/bad+code Del: spam -- https://master.php.net/note/delete/80878/spam Del: non-english -- https://master.php.net/note/delete/80878/non-english Del: in docs -- https://master.php.net/note/delete/80878/in+docs Del: other reasons-- https://master.php.net/note/delete/80878 Reject -- https://master.php.net/note/reject/80878 Search -- https://master.php.net/manage/user-notes.php

« previous php.notes (#135789) next »