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.
Related
I am trying to pass a string from PHP into a Perl script, uppercase each word, and then pass the uppercase string back to PHP where I echo it out. I know I can do that in PHP, but there are other reasons why I will need to pass the string between PHP and Perl.
If the variable $user_input is "first second third" I want the echo statement in the PHP program to echo "FIRST SECOND THIRD", but right now it is only echoing "FIRST".
How do I get my Perl script to read in and uppercase each word, not just the first one? (The variable user_input is not necessarily fixed at a length of three words, it could be more or fewer.)
Here is the relevant PHP:
$result = shell_exec('/usr/bin/perl /var/www/my_site/myperl.pl ' . $user_input);
$user_input = $result;
echo $user_input;
And this is my Perl program (myperl.pl):
#!/usr/bin/perl
use warnings;
my $var1 = shift;
foreach $var ($var1){
print uc $var ;
}
I've tried changing several things in the Perl code (using #var1 for example) but can't seem to get it to work. Thanks in advance for any help you can provide.
Do not use shell_exec() with unescaped input. This function is really easy to use in an unsafe manner, and can lead to command injection security vulnerabilities. Here, you have run into issues around your lack of escaping. Slightly simplifying things, you are trying to execute the following command:
# shell_exec('/usr/bin/perl /var/www/my_site/myperl.pl ' . $user_input)
/usr/bin/perl /var/www/my_site/myperl.pl first second third
Since the variable contents are just pasted into the command line, it is split at spaces and passed to the command as separate arguments.
The safest approach is to bypass shell expansion and executing the intended program directly. Unfortunately, core PHP does not provide convenient functions for this task.
If you want to continue using the convenient shell_exec() function, you MUST escape the variable before constructing the shell command. For example:
shell_exec('/usr/bin/perl /var/www/my_site/myperl.pl ' . escapeshellarg($user_input))
This would lead to the following shell command being executed (note the single quotes around the argument):
/usr/bin/perl /var/www/my_site/myperl.pl 'first second third'
After that, your Perl code should work as expected.
Arguments passed to a Perl program are available in the builtin global #ARGV array.
The shift function takes an array name as an argument, and removes the first element from that array and returns it. When used without an argument it operates on #ARGV, or if in a subroutine on #_ array which holds arguments passed to the subroutine.
So the code you show takes the first argument passed to the program and works with it.† Then, the shown foreach loop goes over just that one scalar (single-valued) variable.
Instead, you want to extract or copy the whole #ARGV and then to iterate over that array ‡
use warnings;
use strict;
use feature qw(say);
my #args = #ARGV;
foreach my $arg (#args) {
say uc $arg; # with a new line
# print uc $arg; # no newline, all come out "stuck" together
}
Now you can process those (instead of just uc-ing them), what I presume is intended.
If you indeed wanted to merely print out upper-cased input then
say uc for #ARGV; # each on a line on its own
# print uc for #ARGV; # no newline between them
suffices. (The uc takes $_ by default.)
† If the PHP program passes one string to the Perl program, not expanded (broken into) words by a shell or some such, then your Perl code should work as it stands. But the code shown here works in that case as well, and it will always process all arguments.
‡ Or of course one can work with the #ARGV directly
foreach my $arg (#ARGV) { ... }
I copy it in the text to preserve it because normally it is parsed separately by libraries.
I want to pass parameters from PHP Command Line Interface, and then read in the values using PHP script, something like this:
<?php
$name1 = $argv[1];
echo $name1;
?>
I pass the variable from CLI like this:
C:\xampp\php\php.exe name.php Robby
The above works, I get Robby as the output.
But I want to do something like this:
C:\xampp\php\php.exe name.php -inputFirstName="Robby"
So that the user is well informed to enter the correct parameters in the correct places. What is the appropriate way to parse these parameters?
When calling a PHP script from the command line you can use $argc to find out how many parameters are passed and $argv to access them. For example running the following script:
<?php
var_dump($argc); //number of arguments passed
var_dump($argv); //the arguments passed
?>
Like this:-
php script.php arg1 arg2 arg3
Will give the following output
int(4)
array(4) {
[0]=>
string(21) "d:\Scripts\script.php"
[1]=>
string(4) "arg1"
[2]=>
string(4) "arg2"
[3]=>
string(4) "arg3"
}
See $argv and $argc for further details.
To do what you want, lets say
php script.php arg1=4
You would need to explode the argument on the equals sign:-
list($key, $val) = explode('=', $argv[1]);
var_dump(array($key=>$val));
That way you can have whatever you want in front of the equals sign without having to parse it, just check the key=>value pairs are correct. However, that is all a bit of a waste, just instruct the user on the correct order to pass the arguments.
I use this fairly concise method:
if($argc>1)
parse_str(implode('&',array_slice($argv, 1)), $_GET);
Which would handle a call such as:
php script.php item1=4 item2=300
By sending it into $_GET you automatically handle web or CLI access.
For commentary, this is doing the following:
If the count of arguments is greater than one (as first item is the name of the script) the proceed
Grab the arguments array excluding first item
Turn it into a standard query string format with ampersands
use parse_str to extract to the $_GET array
While the answer is correct and you could do the parsing by hand, PHP also offers the getopt() function that might actually provide useful here.
There's also object-oriented alternatives (written in PHP, available in a number of libraries) that might turn out to be what you need. Googling for "php getopt" will yield helpful results.
you can send parameters as one argument then parse that argument like a $_GET array
C:\xampp\php\php.exe name.php "inputFirstName=Robby&LastName=John"
and in your PHP file
if (!empty($argv[1])) {
parse_str($argv[1], $_GET);
}
you'll get arguments in $_GET array like usual
The getopt() function is probably the most correct answer in the case of the question. Especially since it was made platform independent with PHP 5.3. In the particular case of this question and parsing multiple parameters, one way to leverage this function would be as follows:
$defaultValues = array("inputFirstName" => "");
$givenArguments = getopt("", array("inputFirstName:"));
$options = array_merge($defaultValues, $givenArguments);
$inputFirstName = $options['inputFirstName'];
The call to set $inputFirstName with the value "Robby" would be:
> php script.php --inputFirstName="Robby"
Explanation
Default values for all expected parameters are set in the $defaultValues array. Input sent through via command line arguments are collected by PHP's getopt function and stored by the $givenArguments. Note that the colon (:) at the end of the "inputFirstName:" string indicates that this is a required argument. Without a colon here, only the presence of the argument would be detected, not the actual value (more information in the PHP Manual). Merging these two arrays together on the third line results in array with all expected parameters being set with either default values or arguments provided from the command line/terminal if they are available.
I don't know if at the time this question has being asked what i going to answer to it was available but if you call php-cgi -f myfile.php var=something you can retrieved whit $var=$_GET['var']; from the command line then you don't have to change your code to call it from the web browser or the command line
If you don't mind using a library, I suggest you take a look at The Console Component by Symfony.
It can be used to create command line applications and supports the use of Arguments & Options.
The documentation page contains a couple of excellent examples to get you started.
Of course under the hood it uses the same techniques as explained by vascowhite.
your best hope is to use
exec("php -f php.file.php example=js.json > ech0");
echo file_get_contents("ech0");
unlink("ech0");
That's what I use in PipesJS
You can parse the user input on your program looking for specific strings such as -inputFirstName="x" (using regular expressions, for example) and then set the correct variable to x.
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
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.
I want to run a PHP script from the command line, but I also want to set a variable for that script.
Browser version: script.php?var=3
Command line: php -f script.php (but how do I give it the variable containing 3?)
Script:
<?php
// number of arguments passed to the script
var_dump($argc);
// the arguments as an array. first argument is always the script name
var_dump($argv);
Command:
$ php -f test.php foo bar baz
int(4)
array(4) {
[0]=>
string(8) "test.php"
[1]=>
string(3) "foo"
[2]=>
string(3) "bar"
[3]=>
string(3) "baz"
}
Also, take a look at using PHP from the command line.
If you want to keep named parameters almost like var=3&foo=bar (instead of the positional parameters offered by $argv) getopt() can assist you.
Besides argv (as Ionut mentioned), you can use environment variables:
E.g.:
var = 3 php -f test.php
In test.php:
$var = getenv("var");
As well as using argc and argv as indicated by Ionut G. Stan, you could also use the PEAR module Console_Getopt which can parse out unix-style command line options. See this article for more information.
Alternatively, there's similar functionality in the Zend Framework in the Zend_Console_Getopt class.
A lot of solutions put the arguments into variables according to their order. For example,
myfile.php 5 7
will put the 5 into the first variable and 7 into the next variable.
I wanted named arguments:
myfile.php a=1 x=8
so that I can use them as variable names in the PHP code.
The link that Ionuț G. Stan gave at
http://www.php.net/manual/en/features.commandline.php
gave me the answer.
sep16 at psu dot edu:
You can easily parse command line arguments into the $_GET variable by using the parse_str() function.
<?php
parse_str(implode('&', array_slice($argv, 1)), $_GET);
?>
It behaves exactly like you'd expect with cgi-php.
$ php -f somefile.php a=1 b[]=2 b[]=3
This will set $_GET['a'] to '1' and $_GET['b'] to array('2', '3').