Passing an array from php via command line to R - php

I have a problem, e am executing a R script from php via command line, and i need to give it two arrays for calculation.
I call the script by running:
Rscript nls.R ??? ???
??? and ??? are my arrays that i need to "give" to R, in order for it to calculate certain values.
Anyone knows how to do this? It is not limited to php, because it is command line - i just need to know if an array can be passed to R via command line and how.
How would R catch it, with what command?
Thanks a lot.
Regards

The command you are looking for is commandArgs() .
Now, if you have for example a list if integers separated by commas in a string, you can get the integers
s = '1,2,3,4,5'
your_list = lapply(strsplit(s, ','), as.numeric)[[1]]
There might be more straight-forward ways achieving this.
EDIT:
better example (should also work with Rscript)
$ R "1,2,3,4,5"
...
>lapply(strsplit(commandArgs()[[2]], ','), as.numeric)[[1]]
[1] 1 2 3 4 5

Assuming you want to run R in a process of serving a web page, there are some better ways of invoking R than command line; the problem is that R interpreter starts very slow and you are wasting lots of time and CPU power to start it over and over again.
You may for instance make a small R server with triggr and talk to it using a client made with PHP sockets.
The simpler yet heavier idea is to make an rApache app and either talk to it with CURL or use it directly as AJAX or even HTML provider.

You'll have to adapt your R script and include a call to commandArgs(). When used with the option trailingOnly=TRUE, it will return a character vector with the space-separated arguments after the call. This will allow you to further manipulate the arguments.
Given a script myscript.r:
#My script
x <- commandArgs(trailingOnly=TRUE)
print(x)
print(str(x))
You can call from the command line Rscript myscript.r 1 2 3 and get
Loading required package: ...
...
[1] "1" "2" "3"
chr[1:3] "1" "2" "3"
NULL
F:\Temp
This gives you the possibility to pass names of text files with your arrays to the Rscript. If I combine different languages, I usually use text files to save intermediate results, it makes things go a bit more smooth.
Beware, if you use any of the options of Rscript (eg --no-save), you have to put them before the script, eg Rscript --no-save myscript.r

You can't pass such things (well, not easily) to Rscript. Rscript has the -e option, of which there can be more than one, which are R expressions. So you could get PHP to produce a character string that is an R expression creating your arrays, and pass each expression to create an array via separate -e arguments.
You can also pass in command line arguments that the R function commandArgs() can grab and make available for you. See an example here, but you may have to play around with how the arguments get pass in and evaluated by R.
Depending on the size of the arrays, the above more than likely won't be useful. In which case you will have to look at other ways of communicating with R than via Rscript.

Related

Passing variable from PHP to perl is only reading first word

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.

What is the safest way to access CLI program in PHP

I'm writing a PHP library that will need to reach out to the system and access a command line program that doesn't have a PHP interface (or PHP library). As such, I was wondering what is the best (and the safest way) to access the system to retrieve output from a CLI program? I've taken a look at both system() and exec(), but still not sure which is the best to use in a situation like this.
The library will get a string of user-passed text, and transmit it to the command line, retrieving back another string of text. Obviously, with passing user-provided data to the CLI, I will be doing a verification to ensure that no executable data can be passed.
I would suggest shell_exec() together with escapeshellcmd() and escapeshellarg().
To clarify (I was on the go when I first posted this answer): The right way to secure a shell command is:
$exe = 'cat';
$args = array('/etc/passwd');
$args = array_map('escapeshellarg', $args);
$escaped = escapeshellcmd($exe . ' ' . implode(' ', $args));
Here's a legitimate demo (and a nefarious demo as well) of the above code.
The above is just a dummy example, of course. But the main idea is that you apply escapeshellarg() to each argument and then call escapeshellcmd() on the whole command string (including the path to the executable and the previously escaped arguments). This is critical in arbitrary commands.
Note: By secure, I mean making it impossible to perform shell injection attacks by escaping characters that have special meaning like >, <, &&, | and more (see the Wikipedia link) while at the same time properly quoting spaces and other characters that may also have special interpretations by the shell.
With that aside, if you're already white-listing all the commands allowed, you already have the best possible security and you don't need the above functions (althought it doesn't hurt to use them anyway).
Regarding the actual calling function, they all pretty much do the same thing with a few quirks. Personally, I prefer shell_exec() since its return value is more versatile (from this page):
exec(): returns the last line of output from the command and flushes nothing.
shell_exec(): returns the entire output from the command and flushes nothing.
system(): returns the last line of output from the command and tries to flush the output buffer after each line of the output as it goes.
passthru(): returns nothing and passes the resulting output without interference to the browser, especially useful when the output is in binary format.
Except from the system() exit return code, you can mimic the behavior of all the other functions with the return value of shell_exec(). However, the inverse it's either harder to do, or just not possible.
I hope this clears things up for you.
Ideally, you would use passthru() from a pre-defined list of possible inputs (so that if user input == 'operation_a' you can { passthru('operation_a'); } without worrying about sanitizing input). Otherwise, use passthru() with some serious sanitation of input. passthru() allows you to capture the output of the command and pass the whole lump back to the browser. This function is particularly useful if you are expecting binary output (like from image generation, &c.).

PHP, pass parameters from command line to a PHP script

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.

Sharing Memcache with PHP and Python

I am trying to share a Memcache key between Python and PHP. Python writes the key and PHP reads it. I am using the Cakephp framework, with php-pecl-memcache (not php-pecl-memcached), and the python-memcache all python library.
Python:
mc = memcache.Client( ["127.0.0.1:11211"])
key = "key1"
value = 1323779849
mc.set(key, value)
PHP:
echo Cache::read('key1', 'memcached');
PHP can't read the variable, I get weird "MemcachePool::get() [http://php.net/memcachepool.get]: Failed to uncompress data" errors; I suspect it has to do with memcached flags that are set differently in each library.
This is what happens when I telnet to memcached:
Python sets key:
get key1
VALUE key1 1 12
1323779849
.
END
PHP sets key:
get key1
VALUE key 1 0 12
1323779849
END
Is there a way to override these flags and just 'do your own thing'?
Are there php/python memcache libraries that play better together?
Alternatively, is there a simple way to create a common memory space between python/php?
Finally got it to work. Lot's of stuff wasn't working as expected.
One problem is that php and python use different flags to do different things.
Not a problem in an all-python or all-php solution, but for inter-environment communication a real problem. A useful resource is http://www.hjp.at/zettel/m/memcached_flags.rxml, which shows that python-memcache flags long integer as '2', which php-memcache does not understand, hence the compression error. I amended python-memcache to include a 'flag-override' in the set function. This variable simply forces a particular flag irrespective of what python memcache thinks it ought to be. This allowed me to re-flag Int from 2 to 0. I will prob branch the current version of python-memcache and submit it to Github. This allowed me to force the python long int flag (2) to something php would understand (0).
CakePhp prior to 1.3.3 stores all keys in memcached with an additional key_expires key, flagged as 768, etc, etc. Without this additional key it cannot find the key you are looking for. Thankfully this behaviour was dumped in later Cakephp version (I simply upgraded to 1.3.13) and it works well now.
When you put something via python memcached, it's probably pickled. So PHP cannot unpickle it. I would try to use some kind of very basic type maybe ctypes? Maybe raw strings?
I had a similar problem, using PHP and pymemcache. I serialized Python dictionary with https://www.php2python.com/wiki/function.serialize/ and wrote that to memcache. PHP side also had it's own way of storing into memcache, and memcache values written by PHP and Python seemed to be the same, but PHP couldn't read Python set value properly, so it puzzled me a lot. PHP read it as a String, being unable to deserialize it / convert it to an Array. Then I got to read memcache values using netcat, like this:
echo -e 'get my-key\r' | nc 192.168.1.17 11211
Python set value returned:
VALUE my-key 0 1460
, while PHP set value had:
VALUE my-key 1 1460
Not knowing how to deal with these flags, I simply used this - on PHP side, if I got a String "a:{s:6..." instead of an Array, I used PHP's unserialize() method to make it an Array and it worked.

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.

Categories