Which function will you prefer to execute system commands with PHP? - php

like func("rm -rf /usr/local/)
Which 'func' will you use to do that?

It depends on what you want to obtain.
If you want to display the ouput of the command that has been executed, passthru does the trick :
This function should be used in place
of exec() or system() when the output
from the Unix command is binary data
which needs to be passed directly back
to the browser. A common use for this
is to execute something like the
pbmplus utilities that can output an
image stream directly.
If you want to get the output of the command in a variable as a whole string, you can use shell_exec (which is the same as using the backtick operator) :
Execute command via shell and return
the complete output as a string
And, if you want to get it line by line, you'll use exec :
If the output argument is present,
then the specified array will be
filled with every line of output from
the command. Trailing whitespace, such
as \n, is not included in this array.
And, finally, if you need a bit more control, you'll use proc_open -- see the documentation, about that one ; it's a bit more tricky, I guess.
Still, when using those :
Don't forget you are calling a program that has to be available on the host machine
This means if you are using a Linux command, your application will most likely not work on windows
Depending on the configuration of PHP, it is possible that only a couple of commands could be available ; see safe_mode_exec_dir, about that
Using this means launching another processus -- probably not that good for performances
So, I'd use those only when it is really necessary.

You would use PHP's exec function. Other options include system, passthru, and the backtick operator.

Personally I think proc_open is the best approach.
http://php.net/proc_open
This gives you far more control over input, output and let's you check it's exit status and STDOUT, which is more than most other commands for system calls. It also doesn't hold up the system while the command exits.

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)

What is the best practice to run PHP script from PHP script?

I'd use the following code:
$SERVER_PATH = dirname(__FILE__);
shell_exec($PHP_LOCATION.' '.$SERVER_PATH."/script.php?k1=v1&k2=v2 > /dev/null 2>/dev/null &");
Where:
$PHP_LOCATION should contain the path to PHP,
$SERVER_PATH - is current working directory (fortunately the script to run is in the same directory),
> /dev/null 2>/dev/null & added to make this call asynchronous (taken from Asynchronous shell exec in PHP question)
This code has two problems:
As far as I remember ?k1=v1&k2=v2 will work for web-call only, so in this particular case parameters will not be passed to the script.
I don't really know how to init the $PHP_LOCATION variable to be flexible and to work on the most hosts.
I conducted some research regarding both problems:
To solve 1 suggested to use -- 'parameters_string' but it is also recommended to modify the script to parse parameters string which looks a bit clumsy. Is there a better solution?
To solve 2 I found a solution to use PHP_BINARY but this is a PHP 5.4+ case (I'm using 5.3). But the original question was about to run PHP of the same version as the original script version. So for me (as I use PHP 5.3 only) is there probably a solution?
EDIT 0
Let me do some explanation why I stuck to this weird (for PHP) approach:
Those PHP scripts should be separate from each other:
one of those will analyze the data and
the second will generate PNG graphs as a final result.
Those scripts aren't intended to run simultaneously, this means that the second can run at it's own schedule it is only needed that the run should be upon its data will be ready (which done by the first script). So no data should be passed back from second script (child) to the first (parent).
EDIT 1
As seeing from most of the comments the main discussion goes to forking direction. However I'd like to make stress on the point 1 and 2 asked in the original questions. I have some reasons to solve the task in the way I pointed out and I tried to point all that reason. If some of my points looks weird, please post a comment - I will make it more clear or I will change the main question.
Thank you in advance!
How to get executable
Assuming you're using Linux, you can use:
function getBinaryRunner($binary)
{
return trim(shell_exec('which '.$binary));
}
For instance, same may be used for checking if needed stuff is installed:
function checkIfCommandExists($command)
{
$result = shell_exec('which '.$command);
return !empty($result);
}
Some points:
Yes, it will work only for Linux
You should be careful with user input if it is allowed to be passed to shell commands: escapeshellarg() and company
Indeed, normally PHP should not be used for stuff like this as if it is about asynchronous requests, better to either implement forking or run commands from external workers.
How to pass parameters
With doing shell_exec() via file system path you're accessing the file and, obviously, all "GET" parameters are becoming just part of file name, it is no longer "URI" as there is no web-server to process that. So you have two options:
Invoke call via accessing your web-server. So it will be like:
//Yes, you will use wget or, better, curl to make web-request from CLI
shell_exec('wget http://your.web-server.domain/script.php?foo=bar');
Downside here: if you'll access your web-server via public DNS, it will cause network gap and all processing overheads. Benefit - obviously, you will not have to expect anything else in your script and make no distinction between CLI and non-CLI calls
Use $_SERVER array in your script and pass parameters as it should be with CLI:
shell_exec('/usr/bin/php /path/to/script.php foo bar');
//inside your script.php you will see:
//$_SERVER['argv'][0] is "script.php"
//$_SERVER['argv'][1] is "foo"
//$_SERVER['argv'][2] is "bar"
Yes, it will require modification in the script, and, probably, some logic of how to map "regular" web-requests and CLI ones. I would suggest even to think of separating CLI-related stuff to different scripts bundle so not to mess that logic.
More about "asynchronous run"
When you do php script.php & you just run it in background mode. That, however, still keeps parent-child relation for your process. That means - if parent process dies, it's childs will also be removed. To be precise, SIGHUP will be triggered and to avoid this situation you should use nohup command. It will allow to emulate "detaching" of a process and therefore making it's run reliable and independent of circumstances happening to parent process.

Why won't shell_exec execute files but does execute simple commands?

Is there any reason why I can not complied files in PHP's shell_exec/exec/system function?
Example of something that does work in command line and PHP's shell_exec function:
<?php
$data = shell_exec("ls");
echo $data;
?>
Example of something that does not work in PHP's shell_exec function but will work in command line (I can confirm that):
<?php
$data = shell_exec("./c-compiled-file argv1 argv2 argv3");
echo $data;
?>
Is there anything I can do on my server so this will work? I've looked everywhere and no solutions I found fixed the problem. The compiled file is in the same directory as the PHP script as well, it just won't execute it. Also if you're asking, yes I have tried this with SSH2 and it still will not execute.
Also PHP is not in safe mode and NO functions are disabled.
Some common glitches when executing external commands from PHP that work fine from shell:
Command uses relative paths but PHP is launched from an arbitrary location:
Use getcwd() / chdir() to get/set working directory
PHP and shell run with different user credentials. This is often the case when PHP runs through a web server.
PHP and shell run different commands. Many people call stuff like exec("foo $bar") and doesn't even check what "foo $bar" contains.
No error checking is done. The bare minimum is to capture and print standard output, standard error, status code and, of course, all PHP error messages including warnings and notices.
You can redirect stderr to sdtout
You can use a PHP function that allows to capture more information, such as exec()
The web server is disallowed to execute the command at operating system level.
Lookout for SELinux or similar tools.
Just a guess, but the binary you're trying to execute might not have the proper permissions. Prepeding it with ./ in the command line forces it to execute, but PHP probably strips that for security purposes. Try this:
chmod +x c-compiled-file
You want to use system in the second case, and not shell_exec.
system executes an external program and displays the output.
shell_exec executes a command via shell and returns the complete output as a string.
and for good measure:
exec simply executes an external program.
Furthermore you want to make sure your external program is executable and (though you have stated it, I'll restate this) has execute permissions for the user which is running the web server. You also want to make sure the directory your external program is running in has the ability to write to its directory or /tmp or whatever output directory you have set.
Finally you should always use absolute paths for executing things like this in cron or php or whatever... so don't use ./c-compiled-file argv1 argv2 argv3, but instead use /home/username/c-compiled-file argv1 argv2 argv3 or whatever the full path is.

PHP system() help no simple commands work

I am trying to run a shell from one of my controllers in a PHP codeigniter applications,
I am trying to run the file /x/sh/xpay4.sh however I just get 127 returned to the screen, I can even use basic commands like ls or pwd can any suggest why this would be, I thought it might be safe_mode when I ini_get('safe_mode') it returns 1
system function is restricted in safe mode.
You can only execute executables
within the safe_mode_exec_dir. For
practical reasons it's currently not
allowed to have .. components in the
path to the executable.
escapeshellcmd() is executed on the
argument of this function.
http://www.php.net/manual/en/features.safe-mode.functions.php
system() returns only the last line of the shell output.
Sounds likt this is "127".
If you need the whole output instead, try:
$output = array();
exec('/x/sh/xpay4.sh', $output);
echo implode("<br>", $output);

How to pass (cli) arguments by file in Ant

I'm using Ant to build my project, generate docs and check coding strandard violations. I use some external tool through exec task. Exec prefixes the output lines with [exec]
This string messes my output up.
If I specify the -e switch in the command line, it remains quiet.
Is there a way to
specify the -e switch on every run in the build.xml file?
or something else equivalent.
Maybe the Java System Properties will help ... see http://ant.apache.org/manual/running.html#sysprops
In particular, I think that setting the property build.compiler.emacs to true may help. Anyway, I doubt that setting (or, re-setting it via ant-extensions) it in the build file helps, as properties are designed to be immutable.

Categories