Is it possible to check PHP file syntax from PHP? - php

I load dynamically PHP class files with autoload.
And those files could be missing or corrupted by some reason.
Autoload will successfully report missing files so application logic could handle that. But if those files are corrupted, then the whole processing halts with blank screen for the user and "PHP Parse error: syntax error" in error log.
Is it possible to check syntax of PHP file from PHP code?
I've looked here: http://us.php.net/manual/en/function.php-check-syntax.php - it's deprecated.
And
exec("php -l $file");
seems to be a wrong way (http://bugs.php.net/bug.php?id=46339)
Thoughts?

You really shouldn't try to check for non-correct PHP files at execution time : it'll kill the response time of your application !
A "better way" would be to use php -l from command line when you're done modifying a PHP script ; or include it in your build process if you're using one ; or plug it as an SVN pre-commit hook if you're using SVN and can define SVN hooks.
In my opinion, almost any given solution would be better than checking that yourself at execution time !
Considering errors like the ones you want to avoid will probably won't happen often, it is probably better to... just let them happen.
ONly thing is : activate logs, and monitor them, the be able to detect quickly when tere is a problem :-)
Of course, this doesn't prevent you from dealing with the case of missing files ; but that's a different matter...

Another way you can make one php file in your root directory called
checkSyntax.php
<?php
for($i=1; $i < count($argv); $i++){
$temp = "php -l " . $argv[$i];
$output = exec($temp);
echo "\n$output";
}
?>
now, open your bashrc file to make a shortcut to run this file.
add below line to run checkSyntax.php
alias checkSyntaxErrors='php /root/checkSyntax.php'
and now goto your source directory do svn st.
it shows you list of files, now easily run the command.
checkSyntaxErrors file1.php file2.php .......
this will check all your files passing as arguments.
enjoy :)

In short: i can't see a way to do this, but have an idea which might be sufficient.
There are log monitoring programs or can filter the logs via standard tools for files with parse errors. If a file appears, you put the villain filename into a black list and your autoloader checks before load against this list.
With this method, at first time you'll serve a blank screen (assumig error reporting to the output are turned on on production servers) but the second will have a page without the faulty component.
In the autoloader you should have a list or naming scheme to always try to loading mandatory classes (other ways your application might be in an inconsistent state)

You could also do some unit testing, where you load the PHP you're dynamically executing and assert that exec("php -l $fileName") is valid. If you did that you'd be able to verify it once in your tests, generating it with appropriate variables, and have a reasonable level of confidence your PHP was good.

This is an old question, but it seems in recent php versions we can do this
try {
include_once($file);
} catch (\ParseError $e) {
// Parse error
} catch (\Throwable $e) {
// Any other error
}

Related

PHP script dies when run via CRON job

Let me start by saying I am totally not a PHP programmer - this was dumped on me to fix.
I have a function that sits in a file by itself, that basically looks like this:
<?php
function UploadFile($source, $destination){
$debugLogPath = '/biglongpath/debug.log';
file_put_contents($debugLogPath,PHP_EOL . "Beginning UploadFile function", FILE_APPEND);
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
require_once('Net/SFTP.php');
...Rest of the ftp code here...
}
?>
It's using phpseclib. If I run the main PHP script (that calls this function...) via a web browser, everything works great. When I run that same script via a CRON job, it dies as soon as this function is called. I've verified this by writing out a debug log right before calling the function - the first statement before the function is written to the log, but the "Beginning UploadFile function" is never written.
I'm guessing that maybe it has something to do with the require_once statement - maybe either a path problem or permissions issue when it's executed via CRON?
I've tried wrapping the entire function contents in a try/catch and writing out the Exception, but it still just dies.
I wonder why there are 3 helpful flags, when the question states, that the file is being written? However, this is not the CLI error log and therefore will not automagically log any errors there.The second one suggestion made appears more likely, while there are even more possibilities:
Make sure that these modules are being loaded for the PHP-CLI:
libsodium, openssl, mcrypt, gmp (as the composer.json hints for).
Running php --ini should show which INI files were loaded. Even if the corresponding INI files are there, make sure the instructions inside them are not commented out with a ;.
Manually running the script from CLI, as the user which runs the cronjob suggested, with error reporting enabled. If this shouldn't help, single-step into it with xdebug, to see where exactly it bugs out (NetBeans, Eclipse, VS Code and a few other IDE do support PHP debugging). This requires some effort to set it up, but then it provides a far better debugging methodology.

In PHP shell_exec function with command "node welcome.js" does not return value

The welcome.js code is given below
console.log('Wellcome');
and the php file code is given below
$op = shell_exec('node welcome.js').PHP_EOL;
echo $op
If I run the php file in command line it print Wellcome but when I run from browser it does not print any output.
There are most likely errors here that you're not seeing.
Set 'error_reporting' to -1 and 'display_errors' to 1 in your php.ini and be sure to restart your webserver/fastcgi-listeners. This is more reliable than using ini_set() and error_reporting() in the script, which will fail if there are parse errors...see php:errorfunc.configuration for more detail.
Check the appropriate error log (depending on your settings and the Server API, this can be the httpd's error log, syslog, some independent file, or even going nowhere right now). Again, php:errorfunc.configuration can help you get things configured correctly, or suss out the current configuration.
The $PATH (or %PATH% on Win32) for an interactive login session is usually dramatically different than that of a running daemon. Try specifying the full path to the node binary.
I don't know off-hand which file-handle node's "console.log()" goes out to. Assuming you're using a bourne-style shell (such as bash) for the subshell here, you can try piping stderr to stdout, using something like: $op = shell_exec('/foo/bin/node welcome.js 2>&1').PHP_EOL; echo $op;
Make sure that 'welcome.js' is where you think it is in relation to the current working directory of your PHP process (although it's likely that node would warn you via one of the previous suggestions if this were not the case, it seemed worth pointing out as a potential pitfall.)

Processing Gem Data

I have a question regarding running a shell command via PHP. My goal is to successfully run compass compile [project] via PHP. I have tried the following:
echo system('compass compile [project]', $s); // prints [31m[0m
echo $s; // prints 1
echo passthru('compass compile [project]', $p); // prints [31m[0m
echo $p; // prints 1
echo shell_exec('compass compile [project]'); // prints [31m[0m
echo exec('compass compile [project]', $e, $ee);
print_r($e); // Array ( [0] => [31m[0m )
echo $ee; // prints 1
I even tried running a shell command to an executable file that contained compass compile test and I still got the same results as the trials above.
My questions
What does [31m[0m mean? Does this represent binary data? Do these represent bash colors as search engines suggest?
As far as I know, the output should be the following:
For kicks, I tried to execute via system(/usr/local/bin/compass compile [project]); and I got the same result. I double checked my path so I know I can execute these commands as expected. Here is the output from echo $PATH:
/usr/lib/lightdm/lightdm:
/usr/local/sbin:
/usr/local/bin:
/usr/sbin:
/usr/bin:
/sbin:/bin:
/usr/games:
/usr/local/games:
/var/lib/gems/1.9.1/bin
Is there a way to compile compass projects using PHP?
I've seen a similar error before.
Typically it is due to the things being output in the bash startup scripts. For example, I had an echo in one of my bash startups that jacked up a lot of scripts till I realized what was causing the problem.
Or, perhaps the user (www-data ?) doesn't actually have a home dir and appropriate startup scripts in place?
You can try this to get a non interactive shell:
exec("/bin/bash -c \"compass compile [project]\"", $e, $ee);
print_r($e);
echo $ee;
If you still have issues, try redirecting the output to a tmp file, an checking it:
exec("/bin/bash -c \"compass compile [project] > /tmp/compass.compile.output\"", $e, $ee);
print_r($e);
echo $ee;
See also: What's the difference between .bashrc, .bash_profile, and .environment?
The issue was fixed by using sass --compass and redirecting the stderr to stdout via echo shell_exec("sass --compass [project] 2>&1");
It was a pretty long and arduous process figuring this out since it's been awhile since I've dabbled in command line programs. Remember that error streams and output streams might be on different outputs. The easiest way to test this is to shovel the output into a file via:
# do this once with a good file and once with a file that will give errors
sass --poll style.scss > output.txt
If output.txt is empty then the error output is on the stderr stream such as the case above. We can correct this by redirecting the stderr to the srdout. For example:
sass --poll > output.txt 2>&1
#shows results
cat output.txt
I created a simple PHP script that redirects the output from one textarea to the other. The code can be found here.
First guess would be a permissions issue. Odds are the user account running PHP (unless you're running this from the command line, I'm guessing that this is the user that the httpd apache daemon is running under) doesn't have the permissions to do what you're asking. The errors are extremely unhelpful, however.
From what I can tell, it looks like an attempt to have the error show up in red on the command line. My guess is that there are hidden (or somehow never printed out) characters in-between the codes. Check out some of your apache and/or PHP error logs to see if anything helpful is showing up there that never made it into the PHP variable. Or, for kicks, try copy and pasting the output with the bash colors into a basic text editor and first delete each character from the beginning one by one... see if anything magically appears. If that doesn't work, try the same in reverse, backspacing from the end. Either way, there's an error occurring, so important that it must show in bold red letters to you, it's just not getting to you.
If it does in fact turn out to be a permissions issue, and it's one you can't remedy through permissions wrangling, you could create an intermediary file that your Apache user has permissions to write to, and your cron user has permissions to read from. Instead of running the code directly from PHP, put it in the file, then run a cron on a frequent basis looking for anything in that file, CHECKING IT FOR VALIDITY, and then running it through the compiler and removing it from the file.
It'd be ugly, but sometimes pretty things don't work.
You guessed it right it is colors but the way it is defined is not right. For more information regarding using colors in console please refer to this document. Also, for compiling SCSS via compass you can use shell_exec command in linux. For more information regarding shell_exec please refer to this document. Let us know how it goes.

syntax error checking in php on a project level rather than file

I have a large php project and different developers work on the same project. Changes in php file e.g syntax error can lead to 500 internal server error if another developer tries to run the same project - leaving the other developer clueless as to where the error is from. I need to download some batch file that checks the whole project and displays the line numbers and errors that occured for each file in the project and not just in one file e.g. when using php -l filename - instead I want it to be php -l project
If you are using linux, this command will check your current folder recursively for all php files, syntax check them and filter out the ones that are OK:
find . -name \*.php -exec php -l {} \; | grep -v "No syntax errors"
You'll get a nice list of files and errors.
Edit: Turns out the OP is looking for a way to activate error reporting. I'll leave this in place anyway because I'm sure it's good universal advice for many in similar situations.
I don't know your situation, but to me, it sounds like what you might really need is a proper deployment process using at least a version control system. Multiple developers working on the same files simultaneously without any version control is a recipe for disaster, that much I can guarantee you.
Some starting points:
Setting up a deployment / build / CI cycle for PHP projects
An introduction into VCS mercurial that is very nicely done and helps understand how version control works
Here is a programmers.SE question that might suit your situation: https://softwareengineering.stackexchange.com/questions/74708/source-control-on-a-live-shared-hosting-site
$it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator('.'));
$regx = new RegexIterator($it, '/^.*\.php$/i', // only matched text will be returned
RecursiveRegexIterator::GET_MATCH);
foreach ($regx as $file) {
$file = $file[0];
exec('php -l ' . $file); //check the syntax here
}

Bizarre file_get_contents() behavior with plain-text files & no extension?

I've been working on a local app over the last few days and I've noticed that one of my 'exec()' functions to call an external program didn't fire correctly. Upon further investigation it was obvious that the program did execute, but it quit prematurely as an important line utilizing 'file_get_contents()' didn't retrieve the contents of the file specified.
The file is a plaintext file without an extension. I'm guessing that 'file_get_contents()' is treating the file as a directory since there is no extension? It's strange because if I manually execute the same program from a web browser, everything works perfectly.
Here's an example line for clarity -
while(file_get_contents('plaintextfile') == "something"){
/// Do This
}
The above works just fine when I visit /program.php from a web browser, but when calling it like this it gives me a file/folder not found error for 'plaintextfile'.
exec('php /program.php', $output);
foreach($output as $output){
print $output . "<br>";
}
Thanks in advance to anyone who can shed some light on this situation. I'm really puzzled by this...
PHP as executed from the browser and executed by the command line (in the exec() call) may use different php.ini configurations, and may have different file search paths. The best course of action is to supply the full path to plaintextfile.
if(!file_get_contents('/path/to/plaintextfile')){
// file couldn't be read
}

Categories