PHP system() - return status is always 0 - php

I need to get the following scripts running.
// File: script_a.php
<?php exit(1); ?>
// File: script_b.php
<?php
system('php script_a.php', $return);
var_dump($return);
?>
Now my problem: On my windows system running script_b.php shows int(1) as expected. On our Unix-Server I always get int(0), what makes it impossible for me to check, if a certain failure happens inside the script_a.php.
Does anybody knows this problem and how to solve it?

You might want to check if it's calling the right php executable on th Unix machine. On many UNIX systems you would need to call the php-cli executable insted of the php one for use on the command line.
Another thing to check would be permissions. Maybe the user executing the script_b.php script doesn't have permissions to execute script_a?

__halt_compiler() is called somewhere , able to check that ?

Try making the PHP system call with the absolute path of both the PHP executable and the script filename, e.g.: system('/usr/bin/php /path/to/script_a.php', $return);. Maybe it's a path issue. (You may find the absolute path of your PHP executable with: which php).
Also, as someone suggested, try debugging the actual return value of script_a.php on your UNIX server by running php script_a.php; echo $? on the command line. That echo will output the last return value, i.e., the value returned by script_a.php.
Anyway, I suggest doing an include with a return statement as described in Example #5 of the include() documentation. If you can adapt your scripts like this, it's a more efficient way of communicating them.
// File: script_a.php
<?php return 1; ?>
// File: script_b.php
<?php
$return = (include 'script_a.php');
var_dump($return);
?>

Have you checked if safe_mode is enabled on unix server?
PHP Note:
Note: When safe mode is enabled, you
can only execute files within the
safe_mode_exec_dir. For practical
reasons, it is currently not allowed
to have .. components in the path to
the executable.
Or maybe the system function is forbidden to be executed?

I can't reproduce it either (PHP 5.3.3, Ubuntu).
When I set the exit-value to something better grep-able, like "666", tracing the scripts returned also what is expected:
strace -f php5 script_b.php 2>&1 | grep EXITSTATUS
[pid 18574] <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 666}], 0, NULL) = 18575
waitpid(18574, [{WIFEXITED(s) && WEXITSTATUS(s) == 666}], 0) = 18574
The "-f" to strace let's it follow child processes as you use the system call. "2>&1" redirects stderr to stdout to let everything grep. You can also pipe it to "|less" to go through but the output is long and not very readable.

I can't reproduce this on my system, Ubuntu Hardy. Here's a sample:
/tmp$ mkdir /tmp/sbuzz
/tmp$ cd /tmp/sbuzz
/tmp/sbuzz$ echo '<?php exit(1); ?>' >script_a.php
/tmp/sbuzz$ cat >script_b.php
<?php
system('php script_a.php', $return);
var_dump($return);
?>
/tmp/sbuzz$ php script_b.php
int(1)
/tmp/sbuzz$ echo '<?php exit(2); ?>' >script_a.php
/tmp/sbuzz$ php script_b.php
int(2)
/tmp/sbuzz$
Exit code 0 means successful execution of the program, so it kind of sounds like you are perhaps running the wrong script_a.php or perhaps the "php" executable isn't doing what you are expecting? Perhaps you have a script called "php" that is in your path before the interpreter? What does "which php" report? On my system it says "/usr/bin/php".
If PHP can't find the script, it would exit with 1, for example:
/tmp/sbuzz$ cat script_b.php
<?php
system('php doesnt_exist_script_a.php', $return);
var_dump($return);
?>
/tmp/sbuzz$ php script_b.php
Could not open input file: doesnt_exist_script_a.php
int(1)
/tmp/sbuzz$
In this case I changed the script_b.php to try to run a script that doesn't exist, and I get the exit code 1 (it should be 2 if it completed successfully, because I changed the script_a above), but it also shows the error that it couldn't run the program.
You might want to try changing it to specifically run the full path to the PHP executable:
system('/usr/bin/php script_a.php')
or also the full path to the script as well:
system('/usr/bin/php /tmp/sbuzz/script_a.php')
You could also try specifically executing a program that will return 1, just as another data-point, such as:
system('false')
system('bash -c "exit 69"')
You might want to try an exit code other than 1, which is a common failure. That's why I did "exit 69" above. "false" will exit with 1.
Also, of course, try running the script_a.php directly:
/tmp/sbuzz$ php script_a.php
/tmp/sbuzz$ echo $?
2
/tmp/sbuzz$
The "$?" is the exit code of the last run command, at the shell prompt.

Try:
<?php
die(1);
?>
If that fails as well, check out the stdout of:
strace php script_a.php

Not sure if these problems are related, but you may take a look on exec always returns -1 (or 127) as i had a similar problem in the past... even if i didn't acually solved it.
In your case, it might be another problem, not sure how it would be reproduceable, but i've seen caeses where the return string for an unknown command would be the return string from bash (bash: command not found). On most servers i dont anything though. You may try and check the shell setup for the current user(i assume it would be www-data)

Taking in consideration of your comment that your problem is occuring in UNIX system when your script_b is something like
system('php script_a.php | tee myLogFile', $return);
You may use this syntax
system("bash -c 'php script_a.php | tee log.txt ; exit \${PIPESTATUS[0]}'", $return);
Do man bash and search for PIPESTATUS for more details.

I know this is an old thread, but I just had a similar problem.
The exit status was being set to 0 when I had the script run in the background, something like
system('php script_a.php &', $return);
Could you have been doing that but just generalizing for readability?

you need to be running as root or use sudo to access via php.
try something like this:-
system('sudo /usr/bin/php -f script_a.php', $return);
in your script_b.php
and edit /etc/sudoers to add the following line:-
apache ALL=(ALL) NOPASSWD: /usr/bin/php -f script_a.php
if php is not in /usr/bin/php change that reference
and also mention the full path of script_a.php file somthing like /var/www/html/script_a.php or path where it is physically located.
Thanks.

Related

Allow PHP/Apache to shell_execute commands on Ubuntu

I'm trying to execute a command through PHP with shell_exec. The PHP file is hosted by Apache on my Ubuntu server.
When I run this:
echo shell_exec("ps ax | grep nginx");
Then I get to see data. But when I run another command, for example:
echo shell_exec("cat /usr/local/nginx/config/nginx.config");
Then it's not showing anything at all. But when I copy that command and paste it in my terminal, then it executes fine.
My Apache server is running as user www-data. So I edited sudoers and added this line:
www-data ALL=(ALL:ALL) ALL
I know this is a security risk, but I wanted to make sure (for now) that www-data is able to execute all commands. But, for some reason I'm still not able to execute all commands with my PHP script.
Anyone any idea what to do?
have you read http://php.net/manual/en/function.shell-exec.php
There is quite a discussion in comments section. Top comment is:
If you're trying to run a command such as "gunzip -t" in shell_exec and getting an empty result, you might need to add 2>&1 to the end of the command, eg:
Won't always work:
echo shell_exec("gunzip -c -t $path_to_backup_file");
Should work:
echo shell_exec("gunzip -c -t $path_to_backup_file 2>&1");
In the above example, a line break at the beginning of the gunzip output seemed to prevent shell_exec printing anything else. Hope this saves someone else an hour or two.
echo shell_exec("sudo cat /usr/local/nginx/config/nginx.config");
Try that.

Running PhantomJS from PHP with exec()

I've got the following script:
#!/bin/sh
export DISPLAY=:0
phantomjs --version
It try to run it from the following PHP script:
<?php
$result = shell_exec('sh test.sh');
echo $result;
?>
This script return the following error:
[Thu Jun 19 10:31:31 2014] [error] [client] test.sh: line 3: phantomjs: command not found
I tried to run phantomjs -v by hand in a console, and it runs fine. I checked the PATH, and phantomjs is correctly defined and found.
The execution environment is a virtual Server with LiveConfig.
Can someone help me understand what I'm doing wrong ?
It could be an issue with shell_exec() and line breaks,
try adding "2>&1" to the string you are passing:
$result = shell_exec('sh test.sh 2>&1');
this worked for me, found it in the top comment here, naturally ;)
Your PATH probably lacks the location for the phantomjs executable. PhantomJS is probably installed in /usr/local/bin so you need to add this to your PATH variable:
#!/bin/sh
export DISPLAY=:0
PATH=$PATH:/usr/local/bin
phantomjs --version
To check what the current PATH is, you could begin the shell script with:
#!/bin/sh
echo $PATH
<?php
exec('/usr/local/bin/phantomjs path/somescript.js');
?>
Yes. Sometimes phantomjs don't need full path in some environment without generate any error. However, sometimes it does.
Always use the full path for all argument in the php command.
Did you use the fullpath for hello.js?
Do not use exec(). Never. It's a bad way.
Use the php-phantomjs and PhantomJS Runner instead.

Command not found: PHP exec()

This is driving me crazy. I need to have php execute a command to restart a script running in node. I'm using a node app called forever to run said script. The code is as follows:
<?php
echo '<pre>';
echo exec('sudo -u dalton forever restart botti.js 2>&1');
echo '</pre>';
?>
However, when I run that, I get sudo: forever: command not found
Next, I try which forever and type forever, both which give me:
forever: /usr/local/bin/forever
I edit my code to:
echo exec('sudo -u dalton /usr/local/bin/forever restart botti.js 2>&1');
Edit: After a typo, the error is now:
/usr/bin/env: node: No such file or directory
I'm at my wit's end. Any ideas?
As the forever command only runs, when you give the full path, I suspect, that /usr/local/bin is not in your PATH environment variable, which contains all directories, that are searched for executable commands by default, separated by : (I suspect you're on Linux, may differ for other OS)
I suspect forever calls /usr/bin/env node. The error from env is probably caused by node being outside your PATH too.
To set your PATH in php, use putenv('PATH=<your path here>');
e.g. to append /usr/local/bin:
putenv('PATH=' . getenv('PATH') . ':/usr/local/bin')
This may also be a sudo issue, try the -E (preserve environment) switch.
Figured it out, I needed to define node as well:
$asdf = system('sudo -E -u dalton /usr/local/bin/node /usr/local/bin/forever restart botti.js 2>&1');
Create a symbolic link for forever
ln -s /usr/local/bin/forever /usr/bin/env/forever
And also for nodejs if incase it's still called "nodejs". Make it call as "node"
ln -s /usr/bin/nodejs /usr/bin/node
I will solve the forever execution problem.
For php side, try with this
echo shell_exec("your command sh");

PHP and Apache : shell_exec(wkhtmltopdf with xvfb) command doesn't work

I try to run the wkhtmltopdf (0.11.0 rc1) with php (5.4.2) on apache (2.4.2).
When I try to launch wkhtmltopdf-i386 --use-xserver http://www.google.com google.pdf 2>&1, I can find my pdf. Here my php code
<?php
$cmd= '/usr/bin/wkhtmltopdf-i386 http://www.google.com google.pdf 2>&1';
$ret = shell_exec($cmd);
echo $ret;
?>
It works with apache and as command line php test.php.
Because my target page contains many images and some "heavy" js charts. I have got a Segmentation Fault with the wkhtmltopdf command when I try to turn it into pdf.
The only way to make it work is to use xvfb as X11 emulator. The code looks like this :
<?php
$cmd= '/usr/bin/xvfb-run /usr/bin/wkhtmltopdf-i386 --use-xserver http://www.google.com google.pdf 2>&1';
$ret = shell_exec($cmd);
echo $ret;
?>
This script works with the command line php test.php but it doesn't work with apache. If I take a look into the apache's process with htop, I can see that there are two process (with php test.php) :
xvfb
wkhtmltopdf
When I launch with apache I have only xvfb process. It finish by a timeout from apache because it's waiting the wkhtmltopdf process.
I can make it works with apache (2.2.21) and php (5.3.10).
Is there something that I'm missing ? Maybe something in the apache's config-files ?
I was having the same problem. I was using the exec function, but the same applies to shell_exec. The function execution was disabled in php.ini.
SOLUTION: Remove the shell_exec string from the disable_functions at php.ini file.
I am not sure why your second version is not callable from Apache (must not be using the same shell, since shell_exec uses a shell?), but as a work-around could you (from Apache PHP) shell_exec("php test.php"); and get your intended result?
Perhaps also try one of the other process execution functions such as pcntl_exec.
it's mostly because of ownership and permissions, try
su www-data (for debian)
php test.php
you'll probably see the error.

sudo in php exec()

I don't know what the deal is here…
So I want to run an applescript: sudo osascript myscript.scpt
This works fine in the terminal, but not when I execute it via PHP's exec(); nothing happens. The console says
no tty present and no askpass program specified ; TTY=unknown ; …
I did my research, and it seems I'm missing the password for the sudo command. I tried a couple different ways to get around this, including:
writing %admin ALL=(ALL) ALL in /etc/sudoers
and proc_open() instead of exec()
none of which seem to be working, consequently driving me CrAzY!
So basically, is there a clear-cut way to get PHP to execute a simple terminal command?
EDIT: to clarify, myscript.scpt is a simple appleScript that changes the onscreen UI (for a larger project). In theory, simply osascript myscript.scpt should be enough, however the sudo is for some reason necessary to invoke some response from the system. If the sudo could be somehow eliminated, I don't think I would be having this permissions problem.
It sounds like you need to set up passwordless sudo. Try:
%admin ALL=(ALL) NOPASSWD: osascript myscript.scpt
Also comment out the following line (in /etc/sudoers via visudo), if it is there:
Defaults requiretty
I think you can bring specific access to user and command with visudo something like this:
nobody ALL = NOPASSWD: /path/to/osascript myscript.scpt
and with php:
#exec("sudo /path/to/osascript myscript.scpt ");
supposing nobody user is running apache.
php: the bash console is created, and it executes 1st script, which call sudo to the second one, see below:
$dev = $_GET['device'];
$cmd = '/bin/bash /home/www/start.bash '.$dev;
echo $cmd;
shell_exec($cmd);
/home/www/start.bash
#!/bin/bash
/usr/bin/sudo /home/www/myMount.bash $1
myMount.bash:
#!/bin/bash
function error_exit
{
echo "Wrong parameter" 1>&2
exit 1
}
..........
oc, you want to run script from root level without root privileges, to do that create and modify the /etc/sudoers.d/mount file:
www-data ALL=(ALL:ALL) NOPASSWD:/home/www/myMount.bash
dont forget to chmod:
sudo chmod 0440 /etc/sudoers.d/mount
I recently published a project that allows PHP to obtain and interact with a real Bash shell. Get it here: https://github.com/merlinthemagic/MTS
The shell has a pty (pseudo terminal device, same as you would have in i.e. a ssh session), and you can get the shell as root if desired. Not sure you need root to execute your script, but given you mention sudo it is likely.
After downloading you would simply use the following code:
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1 = $shell->exeCmd('/path/to/osascript myscript.scpt');
Run sudo visudo command then set -%sudo ALL=(ALL:ALL) to %sudo ALL=(ALL:ALL) NOPASSWD: ALL it will work.
I had a similar situation trying to exec() a backend command and also getting no tty present and no askpass program specified in the web server error log. Original (bad) code:
$output = array();
$return_var = 0;
exec('sudo my_command', $output, $return_var);
A bash wrapper solved this issue, such as:
$output = array();
$return_var = 0;
exec('sudo bash -c "my_command"', $output, $return_var);
Not sure if this will work in every case. Also, be sure to apply the appropriate quoting/escaping rules on my_command portion.
The best secure method is to use the crontab. ie Save all your commands in a database say, mysql table and create a cronjob to read these mysql entreis and execute via exec() or shell_exec(). Please read this link for more detailed information.
killProcess.php
I think directly calling a sudo command might be difficult because you are setting up the whole server to work without a password.
Perhaps as an alternative you could setup a CRONjob as root and monitor a flag file. Once the flag file exists it will run the osascript myscript.scpt and then delete the flag file.
This way you will keep SUDO secure from a config point of view and the server safer. To run the script you just need to touch the flag file from PHP.
It would of course introduce a delay of however many minutes you running the CRON job. It would also mean that you would have to redirect the output to a file and have a async monitor of the output, but it will depend on your application if this is a problem or not.
But it is an alternative that might protect the server.

Categories