PHP exec doesn't get stdout after long execution - php

I got a program written in C and compiled with gcc, which I've tested for memory leaks etc in both Linux with Valgrind and in Windows with drmemory, and that with the relevant problematic argv arguments. I've found absolutely no problem doing so, and I get the output I expect when doing so. The only libraries included, and barely used are, stdio.h, stdlib.h, string.h, sys/time.h. Only output is printf and fopen to a specific file, which of course is closed after use, no messing with around with stdout or stderr or something like that.
I call this program from PHP with exec, and the program seems to work perfectly almost all the time, except for some few times when the executable takes like 30+ seconds or something along those lines. The problem is then that it seems I don't get the stdout that I should get assigned to the $output argument with the PHP exec function call, neither does it return anything, which should be the last line outputted from the program. The return value argument for the exec function gets set to 0, which really is the only return value the main function in the C program is set to return, there's no exit or anything else. I've of course set the time limit of the PHP script to 0, and it can run for hours just fine. Should also be noted I run this PHP script from cmd.exe in Windows 7 with administrator privileges.
I've been debugging this so much now, and before I decided to post here, I wanted to see if it actually got to the printf part of my program where the output I want should be printed, so I made it write the exact same string to file right after the printf. Guess what? It wrote the expected result to that file......
From this I take it that PHP exec somehow don't get the stdout output after a certain amount of time. Anyone got any ideas on how to fix this?
I guess a possible fix is to make the PHP script check the created file for the output instead of getting it through the $output argument that should get it from stdout. Perhaps do this when it gets nothing from $output, but this seems like a very shabby workaround.
Is there some kind of setting I've missed?
I'm running PHP 5.6.6.
EDIT:
I've also already made sure to set this at the start of the PHP script before I even started doing any of the tests etc:
error_reporting(E_ALL);
set_time_limit(0);

Did you try to extend the maximum execution time in your server configuration (or by using set_time_limit())? The default one is 30 as I remember correctly. Maybe this causes the problems.

Related

Passing variables from PHP to python

I have a python script. When I run the script from the command line as:
python upgrade.py arg1 arg2
The script runs successfully.
Now I am trying to pass the same variables via PHP code using:
passthru("python upgrade_device.py $arg1 $arg2");
The script does not execute.
I am accepting the arguments using:
sys.argv
The arguments are passed correctly
I have tested using print
This is specific command where the execution fails:
child=pexpect.spawn('ssh admin#%s'%ip_addr)
ip_addr is one of the arguments passed from PHP. Right below this command I am ip_addr so as to find what value is passed to the command. and the value is as expected.
I have the ip_addr variable stored correctly.
I have even type casted it to string so that should not be problem.
In general, is there a difference of format in passing variables from the command line and passing from PHP
For my understanding i think passing it through shell and php is the same, i can't be sure for 100% but that what i know from experience.
For your case if you have verified with print that it's the right string to pass (mean take the output and test it in the terminal if it work) if it work, than verify if the python script file is in the same directory as the php script file, because the shell will be opened at the current php script path. And so the shell command should respect that. For example let assume php script file is in the root "/", and python script file is in "/myPythonScripts/imageProccessing/" then when you execute something like "python myPyScript.py 646545645" for example, in this example in php you should execut "python ./myPythonScripts/imageProccessing/myPyScript.py 646545645", as i said the shell is launched on the php script path.
Now if that's not the problem, then try escaping the string first, with escapeshellcmd(). And see what it give. There is characters that are not supported by the shell, or that have a certain signification and parsed by the shell differently. make sure none of them is passed as argument.
In case none of the above is helpful try to use execshell() instead, and see what it give. Too probable that will not make a difference.
Edit: In case nothing helped, try to change just a bit the way of the exchange is done, and use the way it's done in this response using json https://stackoverflow.com/a/14048046/7668448 (it's a kind of more convenient)
Please if any of that solved the problem, precise in a response which one was! I hope it will help. Also if it's not your case it may be useful for other persons in the future. Think also about giving the solution when you do! (i also personally interested too)

How to catch the result of a background PHP script launched from inside PHP?

I've got some PHP code that I want to run as a background process. That code checks a database to see if it should do anything, and either does it or sleeps for awhile before checking again. When it does something, it prints some stuff to stdout, so, when I run the code from the command line, I typically redirect the output of the PHP process to a file in the obvious way: php code.php > code.log &.
The code itself works fine when it's run from the shell; I'm now trying to get it to run when launched from a web process -- I have a page that determines if the PHP process is running, and lets me start or stop it, depending. I can get the process started through something like:
$the_command = "/bin/php code.php > /tmp/code.out &";
$the_result = exec($the_command, $output, $retval);
but (and here's the problem!) the output file-- /tmp/code.out -- isn't getting created. I've tried all the variants of exec, shell_exec, and system, and none of them will create the file. (For now, I'm putting the file into /tmp to avoid ownership/permission problems, btw.) Am I missing something? Will redirection just not work in this case?
Seems like permission issues. One way to resolve this would be to:
rename your echo($data) statements to a function like fecho($data)
create a function fecho() like so
.
function fecho($data)
{
$fp = fopen('/tmp/code.out', 'a+');
fwrite($fp, $data);
fclose($fp);
}
Blurgh. After a day's hacking, this issue is finally resolved:
The scheme I originally proposed (exec of a statement with
redirection) works fine...
...EXCEPT it refuses to work in /tmp. I
created another directory outside of the server's webspace and opened
it up to apache, and everything works.
Why this is, I have no idea. But a few notes for future visitors:
I'm running a quite vanilla Fedora 17, Apache 2.2.23, and PHP 5.4.13.
There's nothing unusual about my /tmp configuration, as far as I know (translation: I've never modified whatever got set up with the basic OS installation).
My /tmp has a large number of directories of the form /tmp/systemd-private-Pf0qG9/, where the latter part is a different set of random characters. I found a few obsolete versions of my log files in a couple of those directories. I presume that this is some sort of Fedora-ism file system juju that I will confess to not understanding, and that these are orphaned files left over from some of my process hacking/killing.
exec(), shell_exec(), system(), and passthru() all seemed to work, once I got over the hump.
Bottom line: What should have worked does in fact work, as long as you do it in the right place. I will now excuse myself to take care of a large bottle of wine that has my name on it, and think about how my day might otherwise have been spent...

It seems php exec is not waiting for execution

Here's the thing,
$file="myjpg.jpg";
$runme="/var/www/html/facedetect/facedetect ".$file;
$output=shell_exec($runme);
var_dump($output);
Turns
NULL
But in reality the exact same command run through ssh takes a little while to complete, about 15 seconds and it does return an output.
So I'm thinking that PHP isn't waiting and exits before that completes.
What can be done to fix this? any special setting in the ini, something.
Or is there a miss configuration somewhere that might be related for shell_exec not to send myjpg.jpg as the argument for the executable. I'm just clueless about this.
shell_exec() returns NULL when the command fails; i.e. when it returns a none-zero exit value.
This is most probably the case.
To debug, try exec(), which always returns a value, it will return the error.
My gut-feeling is that /var/www/html/facedetect/facedetect or $file; are not accessible by the user that runs PHP (probably www-data).

popen and poclose under zend-server

I've stumbled upon a phenomenon that I can't explain myself.
I'm using popen to execute php and then execute a php script that way, and pclose to close that.
So far so fine. I ran into quite some severe troubles as the script where I used this didn't execute and instead after trying it 3 times in a row I crashed the zend-server (no page would open any more). I found out that the reason to this was that I used a wrong directory for the php.exe. Example:
if (pclose(popen("C:\wrongDir\php\php.exe C:\Zend\Apache2\htdocs\myApp\public\mytest.php 57 > C:\Logs\1\0\jobOut.log 2> C:\Logs\1\0\jobErr.log"))>-1)
{
.....
}
Aside from the "wrongDir" all other dirs were correct....the popen even created the jobOut and jobErr files (which were empty). (remark: PHP is not in a searchpath that is why it wasn't found without the correct path)
Even though I now solved the problem....I have the question if this is a normal behaviour there, or if I have done something wrong (maybe even server settings). As from what I read in the manual about both commands it sounded to me that in the my case I should have had a return value of either -1 or 0 and not the problem I ran into with the process and then the server hanging).
Thanks.
It appears that pclose() doesn't return the exit status of the process but rather of it's ability to close the process.
To get the process termination 'code' use pcntl_wifexited() and pcntl_wexitstatus()
http://php.net/manual/en/function.pclose.php
http://php.net/manual/en/function.pcntl-wexitstatus.php

How can I troubleshoot why my PHP script won't work in cron when it does from the command line?

I've got a script that calls two functions, A and B, from the same class. A creates an Amazon virtual server and B destroys one, both via shell_exec()'s of Amazon's command line tools. The script, doActions.php, pulls actions from a queue. If the action is "create" it creates an instance; when the action is "destroy" it kills one.
The script works fine to execute both A and B when I execute it from the command line: php script.php.
When I put it on a cron, it runs but only successfully runs the B function. It deletes destroys instances but won't create them.
The point of failure is clearly function B. It chokes at the first and most important shell_exec, returning and echoing nothing.
echo $string = shell_exec('/home/user/public_html/domain.com/private/ec2-api-tools/bin/ec2-run-instances ami-23b6534a -k gsg-keypair -z us-east-1a');
Unless you know something specific about the way Amazon's command line tools work, please suggest to me reasons why a shell_exec might work in one case and not the other.
Another shell_exec in the same place behaves as expected:
echo $string = shell_exec ('echo overflow');
My guess is that it has to do something with permissions. But when I have it run shell_exec('whoami') it return "root," and when I su and run the command it works fine. I'm having a hard time thinking of creative ways to troubleshoot why my PHP script won't work in cron when it does from the command line. Can you suggest some?
When something runs from the command line but refuses to do so within cron, it's often an environment issue (path or some other environment variable that's needed by the code you're running).
For a start you should modify the script to output the current environment (shell_exec('env')?) at the very top and examine the output from the command line and cron.
Hopefully, there will be something obvious such as AMAZON_EC2_VITAL_VAR but, if not, you should move the cron environment towards your command line one, one variable at a time, until it starts working.
A quick test to ascertain this. From your command line, do:
env >/tmp/pax_env.sh
Then run your PHP script from a shell script which first executes:
. /tmp/pax_env.sh
so that the environments are identical.
And keep in mind that su on its own doesn't give you the same environment as you'd get from logging in directly as a specific user (su - does, I think). You may want to check the behaviour for when you log in as root directly.
Re your comment:
Yes, I do believe you've got it. I'm likely going to mark your answer as correct but need you to suffer through a few addendums about your clever solution. First of all, what's the best way to execute the pax_env.sh script? Does shell_exec() work?
Never let it be said I didn't work for my money :-) No. The shell_exec will almost certainly be running a sub-shell so the variables would be set in that sub-shell but would not affect the PHP parent process.
My advice, if you wanted all those variables set, would be to create a shell-script consisting of all the commands in /tmp/pax_env.sh (probably prefixing each with export) followed by the command you currently have running in cron, something along the lines of:
export PATH=.:/usr/bin
export PS1=Urk:
export PS2=MoreUrk:
/home/user/pax/scriptB.php
Then run that script from cron rather than /home/user/pax/scriptB.php directly. That will ensure the environment is set up before your PHP code is called.
Astute readers will have noticed the phrase "if you wanted all those variables set" above. I don't personally think it's a good idea to dump all your command line variables into the shell script for the cron job. I'd prefer to actually find out which ones are needed and only include those. That lessens the pollution your cron job has to run under. For example, it's unlikely that the PS1/PS2 prompt variables will be required for your PHP script.
If it works, you can set all the environment variables - I just prefer the absolute minimum so I don't have to worry too much when things change.
A way of finding out what's needed is to comment out one export at a time until your script breaks again. Then you know that variable is needed. Once it works with the maximum amount of export statements commented out, you can just delete those commented export statements altogether and what remains, however improbable, must be okay (with apologies to Sir Arthur Conan Doyle).

Categories