php freezes when executing an external sh script

928 Views Asked by At

I'll try to explain my problem in a time line history:

I've tried to run several external scripts from php and to return the exit code to the server with an ajax call again. A single call should start or stop an service on that machine. That works fine on this developing machine.

  • OS : raspbian Os
  • Webserver : NginX 1.2.1
  • Php : 5.4.3.6

However I've exported the code to a larger machine with much more power and everything seemed to work fine but one thing: A single call causes the php-fpm to freezes and never to come back. By detailed examination I found out, that the call created a zombie process I can not terminate (even with sudo).

  • OS : Ubuntu
  • Webserver : NginX 1.6.2
  • Php : 5.5.9

The only solution seemed to stop the php-fpm proc and than to restart it again. Then everything seems to work fine again, as long as I try to call that script again.

Calling php line

exec("sudo ".$script, $output, $return_var);

(With all variables are normal 'strings' with no special chars)

Start script

#!/bin/sh
service radicale start 2>&1

The service by the way started, but every time the webserver freezes and I had to restart php manually, but that is not acceptable (even for a web server). But only for that single script and only for that service (radicale) with that solemn command (start).

Searching in Google brought me to the point that there is a conflict between the php commands exec() and session_start().

Links:

https://bugs.php.net/bug.php?id=44942

https://bugs.php.net/bug.php?id=44994

Their conclusion was, that that bug could be worked around with such a construct:

...
session_write_close();
exec("sudo ".$script, $output, $return_var);
session_start();
...

But that, for my opinion, was no debugging, but more a helplessly workaround, because you loose the functionality of letting the user know, that his actions have fully functioned, but more let him believe an error has occurred. Much more confusing is the fact, that it runs fully on the Raspberry Pi A, but not on a 64-bit machine with a much larger CPU and 8 GB RAM.

So is there a real solution anywhere or is this workaround the only way to solve that problem? I've read a article about php having some probs with exec/shell_exec and the recognition of the return value? How can that be lost? Someone's having a guess?

THX for reading that long awful English, but I'm no native speaker and was no well listening student in my lessons.

2

There are 2 best solutions below

2
On BEST ANSWER

This is not a real solution, but it's a better solution than none.

Calling a bash script with

<?php
...
exec("sudo ".$script, $output, $return_var);
...
?>

ends only in this special case in a zombie Thread. As php-fpm waits in expectation for a result, it still holds the line, not giving up nor time outs for the rest of its thread still living. So every other request to the php server is still in queue and will never be processed. That may be okay for some long living or working threads, but my request was done in some [ms].

I did not found the cause for this. As far as I could do debugging, I wasn't the triggered Radicale process fault, for this on gave a any time clean and brave 0 as in return. It seemed that a php process just couldn't get a return line from it and so it still waits and waits.

No time left I changed the malfunction script from

#!/bin/sh
service radicale start 2>&1

to

#!/bin/sh
service radicale start > /dev/null 2>&1 &

... so signaling every returning line to nirvana and disconnecting all subroutines. For now the server did not hung itself up and works as desired. But the feeling this may be a major bug in php still stays in the back of my head, with the hope, that - someday - someone may defeat that bug.

4
On

It is likely the case that the new machine simply is not set up the way the Raspberry PI was setup -

You need to do a few things in your shell before this will work on your larger machine:

1). Allow php to use sudo.

sudo usermod -G sudo -a your-php-user

Note that to get the username for your-php-user, you can just run a script that says:

<?php echo get_current_user(); ?> - or alternatively: <?php echo exec('whoami'); ?> -

2). Allow that user to use sudo without a password

sudo visudo - this command will open /etc/sudoers with a failsafe to keep you from botching anything.

Add this line to the very end:

your-php-user ALL=(ALL) NOPASSWD: /path/to/your/script,/path/to/other/script

You can put as many scripts there, separated by commas, as you need. Now, your script should work just fine.

AGAIN, please note that you need to change your-php-user to whatever your php user is.

Hope this helps!