Problem making system calls with PHP scripts - php

I have the following PHP script:
<?php
$fortune = `fortune`;
echo $fortune;
?>
but the output is simply blank (no visible errors thrown).
However, if I run php -a, it works:
php > echo `fortune`;
Be careful of reading health books, you might die of a misprint.
-- Mark Twain
php >
Am I missing a config directive or something that would cause this?
Edit: So, I tried running my script using $ php-cgi fortunetest.php and it worked as expected. Maybe the issue is with Apache2?

Anyways, I found the solution: fortune lived in /usr/games, so I thought it might be a $PATH issue, but when I did su www-data and ran $ fortune it worked as expected, and /usr/games was in $PATH. Apparently, Apache was using a different $PATH variable even though it was running under user www-data, so I rewrote the script to use /usr/games/fortune instead of plain fortune and it worked. Since fortune wasn't the point of the script, it was kind of a waste of time, but lesson learned.

the fortune command just outputs a quotation or famous quote for you. You can just simply store those quotations in a flat text file, or if you have a database, store them in a table. Then use the rand() function or similar in PHP to generate a random number and use this number to get that row in the quotations file/table. This way, your PHP script is not dependent on whether the system has the fortune command installed or not.

Use full paths like /usr/games/fortune instead of just fortune. Apache doesn't always expand paths automatically.
<?php passthru('/usr/games/fortune'); ?>
To find a full path do which in the shell e.g..
which fortune

Honestly I don't know. However It might be you have to say echo $fortune instead.

Related

Using PHP to call Virtualenv’ed Python Script

Last night I spent 5.5 hours trying make PHP execute and receive the output of Virtualenv’ed Python script. Nothing worked; except for scripts that were not Virtualenv’ed.
What I am trying to do:
I am trying to make PHP call a virtualenv’d install of the Newspaper lib output text when I call it.
What I have now:
PHP: (updated)
<?php
$output = exec('newspaper2/bin/python3 /var/www/html/components/python/test.py 2>&1', $output2);
print_r(error_get_last());
echo $output2;
echo $output;
…this works when using a non-virtualenv script
Python: (updated)
from newspaper import Article
url = 'http://example.com/'
article = Article(url)
article.download()
article.html
article.parse()
article.authors
article.publish_date
string = article.text
print(string)
What the issue is:
I can run the script that PHP is running from the command line and it outputs just fine.
What I have tried:
With PHP, (I have tried all the “exec” calls for PHP) it cannot seem to open the virtual environment and returns nothing.
Before the script I have called “python3” and a few other things to no avail.
Yes, I have chmoded it to be executable…
I feel like this should be so simple.
I have tried suggestions on other posts and all over the web to no avail.
Questions:
Did I set up the virtualenv wrong?
At the top of the Python script, instead of the “#!/usr/bin/env python3” should I call something else?
If so, where do I find it? Should I start from scratch and will that
help?
Thank you for your help;
PS: I am running Ubuntu16, PHP7 and I need to use Python3
In the virtualenv'ed scripts (i.e. installed via the setuptools' entry-points), you should not touch the shebang (#!... first line). It is populated by the virtualenv & setuptools & related tools.
If you specify your own shebang, then it is not virtualenv'ed script. In that case, call python directly:
exec('/path/to/venv/bin/python3 /var/www/html/components/python/testing.py');
Alternatively, you can put the absolute path to the virtualenv's python binary to the py-script, but this does not look a good idea.
Also, remember that virtualenvs are non-relocatable. So they should stay in the path where they were created.
Also note that exec() returns only the last line of the output. You probably want shell_exec() or exec('...', $output) to get the whole output.
Also, it is unclear what happens with your script, and what is being printed on stderr. Try this command to see what is the error:
exec('/path/to/script 2>&1', $output)
#OR:
exec('/path/to/venv/bin/python3 /path/to/script 2>&1', $output)
OK, I finally figured it out and learned a lot in the process. The newspaper lib that I am using by default tries to write to the base of the users home directory. In this case, it was attempting to write to www-data, /var/www.
To fix this:
Go to the settings.py file in the newspaper library.
Edit the variable DATA_DIRECTORY = '.newspaper_scraper' and change it to DATA_DIRECTORY = '.path/to/writable/directory'
Save the file and you should be good to go.
I have no idea why it was not returning the errors that would have explained this sooner.
Hope this helps anyone else.
Thank you so much Sergey Vasilyev for your help. I appreciate it greatly.

why does shell_exec not work/ not output for certain commands?

echo shell_exec("ps auxwww");
echo shell_exec("cut -d. -f1 /proc/uptime");
echo shell_exec("date");
gives output;
echo shell_exec("ifconfig eth0");
echo shell_exec("top -n 1");
does not give output
all of these commands work fine when i log in as root through putty and exc them. I read some questions here of some similar issues, one said adding "2>&1" to the end of the command will fix it. That didn't do anything in my case. Also tried using just exec() instead of shell_exce(). Anyone know what's going on? / what I'm doing wrong?
thank you for your time
As far as I know, the commands that generate output through PHP have this in common:
Do not require root privileges
They just append stuff to standard output
Common issues include:
The program execution is failing and you never know because shell_excec() has really poor error checking features (though you could, at least, test its return value for null)
The command sends output to an interactive terminal.
And a program execution can fail for exactly the same reasons as in a regular shell:
Lack of privileges
Wrong or missing environment variables
Wrong or missing parameters and/or input data
Etc., etc., etc.
In your case:
ifconfig is normally at /sbin/ifconfig; non-root users do not have /sbin in their paths
top expects to update random bytes in a TTY window
My advice is to troubleshoot with a function that provides more information such as exec() but please make sure you actually read such info. It's also helpful to read stderr—you can redirect it somewhere else (a file or stdout) or use a function that can read it directly.

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...

calling Windows program from PHP file (through command-prompt)

I have tried calling a windows program several ways and I have gotten the same result each time.
The program opens up on my machine (without a GUI) but never closes each means that the browser is forever loading.
Though when executing the query string manually through the command line prompt the program closes. Not only that, but the program doesn't actually execute
(it is just launched i.e. there aren't any results).
I just want to know the proper way of starting a program with switches through PHP.
Here is the query string that works (closes the program after executing):
"C:\Program Files (x86)\Softinterface, Inc\Convert PowerPoint\ConvertPPT.exe" /S
"C:\Users\Farzad\Desktop\upload\test.ppt" /T "C:\Users\Farzad\Desktop\upload\test.png" /C 18
If the program never closes, then PHP can't return a value from exec(). The program must close. Chances are there is a problem accessing your files on your desktop in this manner. It will be executed with whatever permissions the webserver has defined.
http://php.net/manual/en/function.exec.php
You might consider the advanced functionality of proc_open(). It will give you access to all the necessary pipes, but I don't think that will help you in this situation.
If the target directory on your Windows machine is C:\Program Files (x86)\Softinterface, Inc\Convert PowerPoint\ConvertPPT.exe, you need to double-quote the directories that have space character within them.
To translate it into php terms, it should be like this:
$directory = 'C:\"Program Files (x86)"\"Softinterface, Inc"\"Convert PowerPoint"\ConvertPPT.exe';
$command = $directory . ' enter your arguments here';
exec($command, $output, $return_var);
// if $return_var == 0, you hit the jackpot.
The physical directory where your Windows desktop is stored belongs to your user profile folder. That means that other users (including the one Apache runs as, which is typical "Local System") won't have the appropriate permissions to read and write files on it. While you can adjust your Apache set-up to make it run with your own user, Farzad, it's more common to put web applications in an entirely different directory tree. It may happen that ConvertPPT.exe just stalls because it's trying to write a file at a location where it's not allowed. I suggest you create a top folder directory and make sure it's world-writeable (once finished, you can tighten these permissions if you like).
Once you discard (or confirm) that the issue is caused by lack of appropriate credentials, make sure you are escaping your command and arguments properly. See this link:
http://es2.php.net/manual/en/function.exec.php#101579
One more thing you can try is to close PHP sessions before issuing the call to exec():
http://es2.php.net/manual/en/function.exec.php#99781
You have probably run into this bug: http://bugs.php.net/bug.php?id=44994
which has been bothering me for ages, even today, on PHP 5.3.5.
It seems like there is some kind of deadlock between the error output of the program and the apache error log file handle into which the program is redirected to write its stderr output, making the program be stuck for ever until the apache processes are killed.
Also, when using passthru, or system, or the backtick operator, there's an intermediary "cmd.exe" process that is used to run the program in an invisible console, and I have seen this cmd process getting stuck without even running the program.
I don't really have a solution as of now, and it seems the bug, even though reproduced by many people, hasn't been resolved.

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