How to use php variable insisde system command - php

How do I use a PHP5 variable inside a system() call
$dir = '/etc/somedir';
eg system("ls $dir")
I think I'm missing something
I am actually passing a variable from a post
e.g.
$username = $_POST[username];
to a system call
system("processData --user $username --pass $password");
this isn't working, so i trivialised down to a simple
example

You are doing it fine except that you are missing semi-colon (;)
system("ls $dir");
You can also do like:
system("ls" . $dir);
Note:
When allowing user-supplied data to be
passed to this function, use
escapeshellarg() or
escapeshellcmd() to ensure that
users cannot trick the system into
executing arbitrary commands.

it looks like you are not.. could you extend your example? are there any errors returned? what does the system() function return?
you should keep in mind that system() returns only the last line of the run command.
also, instead of 'ls' you can use a built-in php function like dir() or DirectoryIterator

Related

PHP Nested escapeshellarg()

I am using PHP to generate a shell command that I then pass to PHP's exec() function. I am extensively using escapeshellarg() to make sure there aren't any security issues and also to ensure that certain Linux shell attributes and operators are being applied in the right spots (like stream redirects).
So here is a general example of my problem:
I am nesting escapeshellarg() three times, like this:
echo "first_program -f " . escapeshellarg("second_program -f ". escapeshellarg("third_program -f " . escapeshellarg("value")));
The output of this is:
first_program -f 'second_program -f '\''third_program -f '\''\'\'''\''value'\''\'\'''\'''\'''
As you can see, once it gets to the third escapeshellarg() function call, it starts going crazy with escaping characters.
When this gets executed by the exec() function, it doesn't un-escape it correctly and therefore doesn't execute correctly.
Am I missing something? Or does the escapeshellarg() function break if you nest it like this? It works only nesting it twice, but then on the third nesting it goes crazy. Should I be using escapeshellcmd() in some places? I'm passing all of these in as arguments so I don't see why I wouldn't use the escapeshellarg().

Is this usage of exec() safe when using escapeshellarg()?

I have this code :
$path = "/somedirectory/$user";
echo exec('du -s '.escapeshellarg($path));
This code is used to check how many space the user use in his directory. The $user value can be any alphanumeric value and ".-"
Is it safe to use it ?
escapeshellarg ensures that the value is interpreted as a single, plain shell argument without further shell expansion (e. g., no ​`…`​, $(…), ${…}, etc.). That means that any value in $path is passed as is as a single argument to du.
However, as already mentioned, it does not prevent from passing arguments that may be malicious when interpreted by the executable.
This is safe in the sense that it won't run arbitrary commands, but depending on how $user gets set, .. could sneak in there, which would let whoever is looking at this to see the size of the / directory, which may or may not be of concern to you.
Safe if only your exec does not rely on any $user related commands.
For example, $user . "/du -s " is absolutely unsafe.

Calling perl from php?

I have a php script that handles a form input. For design reasons both a bit out of my control, and which I do not entirely wish to change, I have to call a perl script with the parameters specified in the html form.
I sanitized all inputs and then output them to a file called input, which is read by the perl script named, for sake of brevity in this question, script.pl. Script.pl should do some stuff and then write all outputs to a file named output.
I call the perl script from php like so:
system('perl script.pl 2>errors');
No good, nothing happens. output is not created, errors is not created, and the side effect does not occur.
My apache runs as www-data user and group id. My directory is set with 775 settings with ownership as me:www-data. (My user name is replaced with "me" for sakes for privacy).
My question is two fold:
1) Am I doing this wrong? If so how should I improve upon the code?
2) Is there a more sane way to catch errors in system execution?
After programming in perl for a while, php feels like a pain in the ass.
OS: Ubuntu server edition
popen can be used to get the shell's response. that is your best bet. Which can help you debug why system is angry. also, if your pl is saying "hello" and "bye", popen can even read that.
If the command to be executed could not be found, a valid resource is returned. This may seem odd, but makes sense; it allows you to access any error message returned by the shell
Ideally, I would have taken data from stdin and written to stdout. popen would allow neat access to both.
popen('pwd;perl script.pl 2>errors;echo done');
then you can see where were you (directory) when system got called and did it "done".
In the past I have used shell_exec() or backticks to accomplish this.
The documentation for shell_exec's return value indicates it is identical to the backtick operator:
Return Values
The output from the executed command.
Hope that helps.
system() only returns the status code.
$var = shell_exec ("ls");
print $var;
$var = `ls -l`;
print $var;
Is perl in the path? Maybe you need to specify it fully (e.g. /usr/bin/perl). Is system() returning false, indicating a failure? If you try something simpler, like system('/usr/bin/true', $retval), does $retval get set to 1?
Take a look at the PHP system() documentation. The following is the function prototype of system():
string system ( string $command [, int &$return_var ] )
Pass in a 2nd argument and then print out the return string as well as the second variable. See what the error says.

Execute an external command by passing an array, with spaces in filenames

I have a PHP script that needs to execute programmes that will work on files that have spaces in the names. Most PHP functions for executing external commands (e.g. exec()) take an 1 string argument for the command line to execute. However then you have to do things like escapeshellarg() to make your input safe.
Is there some way to execute an external command in PHP with an array. So rather than:
exec("ls -l ".escapeshellarg($filename));
I can go:
exec(array("ls", "-l", $filename));
This would mean I don't have to worry about escaping the arguments. I want to avoid using escapeshellarg(), since the version I am using has a bug that strips out non-ASCII characters.
Java has this functionality http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Runtime.html#exec%28java.lang.String[]%29
Sounds like this isn't possible with PHP's builtin functions.
function myExec ( command, arguments )
{
exec( command + ' ' + implode( ' ', array_map( escapeshellarg, arguments ) ) );
}
Poke's answer is good - however, how many commands do they need to run? I would think about implementing a whitelist of commands and arguments - that way, you can be pretty darn sure they aren't injection malicious input. Something like:
$whitelistCommandArray = array('ls' => 'ls', ...);
if (isset($whitelistCommandArray[$userSuppliedCommand]])
{
//ok its a valid command, lets parse the args next
...
}
else echo "Unsupported command";
Update/edit:
Is a whitelist of arguments feasible?
What if OP needs to edit a multitude
of files? – Matchu
heh I dont know - it could be - totally depends on your needs.
$whitelistArray = array('ls' => array('a', 'l', 'h'), ...);
Something like that work - with both the command and then an array of arguments for it.

PHP - command line arguments in Windows

I'm trying to run PHP from the command line under Windows XP.
That works, except for the fact that I am not able to provide parameters to my PHP script.
My test case:
echo "param = " . $param . "\n";
var_dump($argv);
I want to call this as:
php.exe -f test.php -- param=test
But I never get the script to accept my parameter.
The result I get from the above script:
PHP Notice: Undefined variable: param in C:\test.php on line 2
param = ''
array(2) {
[0]=> string(8) "test.php"
[1]=> string(10) "param=test"
}
I am trying this using PHP 5.2.6. Is this a bug in PHP 5?
The parameter passing is handled in the online help:
Note: If you need to pass arguments to your scripts you need to pass -- as the first argument when using the -f switch.
This seemed to be working under PHP 4, but not under PHP 5.
Under PHP 4 I could use the same script that could run on the server without alteration on the command line. This is handy for local debugging, for example, saving the output in a file, to be studied.
Why do you have any expectation that param will be set to the value?
You're responsible for parsing the command line in the fashion you desire, from the $argv array.
You can use the getopt() function.
Check blog post PHP CLI script and Command line arguments.
The parameter passing is handled in the online help Note: If you need to pass arguments to your scripts you need to pass -- as the first argument when using the -f switch. This seemed to be working under PHP 4, but not under PHP 5.
But PHP still doesn't parse those arguments. It just passes them to the script in the $argv array.
The only reason for the -- is so that PHP can tell which arguments are meant for the PHP executable and which arguments are meant for your script.
That lets you do things like this:
php -e -n -f myScript.php -- -f -n -e
(The -f, -n, and -e options after the -- are passed to file myScript.php. The ones before are passed to PHP itself).
If you want to pass the parameters similar to GET variables, then you can use the parse_str() function. Something similar to this:
<?php
parse_str($argv[1]);
?>
Would produce a variable, $test, with a value of <myValue>.
PHP does not parameterize your command line parameters for you. See the output where your second entry in ARGV is "param=test".
You most likely want to use the PEAR package Console_CommandLine: "A full featured command line options and arguments parser".
Or you can be masochistic and add code to go through your ARGV and set the parameters yourself. Here's a very simplistic snippet to get you started (this won't work if the first part isn't a valid variable name or there is more than 1 '=' in an ARGV part:
foreach($argv as $v) {
if(false !== strpos($v, '=')) {
$parts = explode('=', $v);
${$parts[0]} = $parts[1];
}
}
Command-line example:
php myserver.php host=192.168.1.4 port=9000
In file myserver.php, use the following lines:
<?php
parse_str(implode('&', array_slice($argv, 1)), $_GET);
// Read arguments
if (array_key_exists('host', $_GET))
{
$host = $_GET['host'];
}
if (array_key_exists('port', $_GET))
{
$port = $_GET['port'];
}
?>
$argv is an array containing all your commandline parameters... You need to parse that array and set $param yourself.
$tmp = $argv[1]; // $tmp="param=test"
$tmp = explode("=", $tmp); // $tmp=Array( 0 => param, 1 => test)
$param = $tmp[1]; // $param = "test";
You can do something like:
if($argc > 1){
if($argv[1] == 'param=test'){
$param = 'test';
}
}
Of course, you can get much more complicated than that as needed.
If you like living on the cutting edge, PHP 5.3 has the getOpt() command which will take care of all this messy business for you. Somewhat.
You could use something like
if (isset($argv[1]) {
$arg1 = $argv[1];
$arg1 = explode("=", $arg1);
$param = $arg1[1];
}
(How to handle the lack of parameters is up to you.)
Or if you need a more complex scenario, look into a command-line parser library, such as the one from Pear.
Using the ${$parts[0]} = $parts[1]; posted in another solution lets you override any variable in your code, which doesn’t really sound safe.
You can use the $argv array. Like this:
<?php
echo $argv[1];
?>
Remember that the first member of the $argv array (which is $argv[0]) is the name of the script itself, so in order to use the parameters for the application, you should start using members of the $argv[] from the '1'th index.
When calling the application, use this syntax:
php myscript.php -- myValue
There isn't any need to put a name for the parameter. As you saw, what you called the var_dump() on the $argv[], the second member (which is the first parameter) was the string PARAM=TEST. Right? So there isn't any need to put a name for the param. Just enter the param value.

Categories