I need to pass a multi-word argument from PHP to Python.
Passing only a single word poses no problem, however, how do I add the additional parameter that will result in a successful solution?
I have tried several ways to pass the additional parameter without any success, it result in either a 500 Internal Server Error or no response from the python script. Using 2>&1 also do not return any error messages.
There are six instances where additional parameter are optional or required for a successful response.
I can send the single word argument:
$command = escapeshellcmd("python /home/nova_api.py 'getwithdrawalhistory' 2>&1");
This will return the proper response of:
{"items":[],"message":"Your trade history with recent first","page":1,"pages":0,"perpage":100,"status":"success","total_items":0}
My attempts to pass the additional parameter from PHP to Python:
$command = escapeshellcmd("python /home/nova_api.py 'getwithdrawalhistory, { \'page\': 1 }' 2>&1");
$command = escapeshellcmd("python /home/nova_api.py 'getwithdrawalhistory, { \'page\': \'1\' }' 2>&1");
$command = escapeshellcmd("python /home/nova_api.py 'getwithdrawalhistory, { \'page\': \"1\" }' 2>&1");
All three result in a blank page - no response and no error returned.
You're doing the right thing by escaping, but using escapeshellcmd isn't what you want. It has no concept of arguments, so isn't working the way you expect. PHP provides a method to quote and escape individual arguments to shell commands:
<?php
$cmd = "python";
$args = [
"/home/nova_api.py",
"getwithdrawalhistory, { 'page': 1 }",
];
// just a fancy way of avoiding a foreach loop
$escaped_args = implode(" ", array_map("escapeshellarg", $args));
$command = "$cmd $escaped_args 2>&1";
Related
I have an application mostly written in PHP, but there is a npm package that has functionality that I need to incorporate into my application. I must pass a string of HTML into the Node.js application but am having issues in getting things correct. I'm using:
exec('node '.$rootPath.'node/app.js '.$imageId.' email '.escapeshellcmd($emailString).' 2>&1', $output, $retVar);
to send the data to my Node.js application, but I'm unsure as to how to decode it once it gets there and needs to be processed via JavaScript. Is there a way to unescape escapeshellcmd() in JavaScript? Or is there a different way I should pass these long strings of HTML over the command-line?
EDIT: Here is the exact method I'm using to pass my info to Node.js:
try{
$emailString = escapeshellcmd($decoded);
//`node $rootPath'node/app.js' $imageId email $emailString 2>&1`;
exec('node '.$rootPath.'node/app.js '.$imageId.' email "'.$emailString.'" 2>&1', $output, $retVar);
print_r($output);
}catch(Exception $e){
echo $e->getMessage()."\n";
}
And here is app.js:
process.argv.forEach(function(value, index, array){
if(index == 2){
id = value;
}
if(index == 3){
type = value;
}
if(index == 4){
visual = value;
}
});
console.log('******* FROM NODE********');
console.log(visual);
It seems like only the first line is getting passed or collected and printed back, and it looks like it's still encoded (unless the console is re-encoding when printing). Also I'm not sure why it seems to be appending values instead of overwriting them:
Array
(
[0] => ******* FROM NODE********
\<head\>\<style type=text/css\>body \{padding:0\; margin:0\; text-align:center\;.tbl1 \{background-color:\#a53f0f\; color:\#fff\; text-align:center\; font-size:\<body data-gramm=true data-gramm_editor=true data-gramm_id=ccdbd45c-b0bf-4691-9\<table border=0 cellpadding=0 cellspacing=0 style=background-color:
)
Array
(
[0] => ******* FROM NODE********
\<head\>\<style type=text/css\>body \{padding:0\; margin:0\; text-align:center\;.tbl1 \{background-color:\#a53f0f\; color:\#fff\; text-align:center\; font-size:\<body data-gramm=true data-gramm_editor=true data-gramm_id=ccdbd45c-b0bf-4691-9\<table border=0 cellpadding=0 cellspacing=0 style=background-color:
[2] => ******* FROM NODE********
\<html xmlns=http://www.w3.org/1999/xhtml xmlns:v=urn:schemas-microsoft-com:vml \<meta name=viewport content=width=device-width,e\>
)
Note: You should use streams over arguments for data to be processed. This is the common way as commands work in the Unix world.
In your code you try to use escapeshellcmd to escape double quote " an encapsulated argument string. This does not work. There is an escapeshellarg PHP function as well. It will encapsulate the string in single quotes ' and escape characters that are even in single quoted strings treated in a special way by the shell.
Assuming $decoded is something like
$decoded = '<body lang="en">very boring message</body>';
then you do not enclose it into quotes yourself. Let escapeshellarg do the trick.
$emailString = escapeshellarg($decoded);
$imageIdString = escapeshellarg($imageId);
exec("node app.js {$imageIdString} email {$emailString} 2>&1", $output, $retVar);
As mentioned above, you really should consider to work on streams instead of arguments. The advantage is that the data can grow to an arbitrary size. Further more proc_open handles STDOUT and STDERR separately. This can be done like that:
try
{
if($handle = proc_open("node app.js {$imageId} email";, [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $streams))
{
[$stdin, $stdout, $stderr] = $streams;
fwrite($stdin, $decoded);
fclose($stdin);
$output = stream_get_contents($stdout);
fclose($stdout);
$error = stream_get_contents($stderr);
fclose($stderr);
proc_close($handle);
}
echo 'OUTPUT:', PHP_EOL, $output, PHP_EOL;
echo 'ERRORS:', PHP_EOL, $error, PHP_EOL;
}
catch(Exception $e)
{
echo $e->getMessage(), PHP_EOL;
}
Here is an example node.js script handling both, data by arg as well as by stdin:
(() =>
{
'use strict';
console.log('******* FROM NODE********');
const
getStdin = require('get-stdin');
var id, type, visual;
[,, id, type, visual] = process.argv;
// if 4th command line argument is present, use that
if(undefined !== visual)
processData(visual);
// otherwise read data from stdin stream
else
getStdin().then(visual =>
{
processData(visual);
});
function processData(data)
{
console.log('id' , id );
console.log('type', type);
console.log('STDIN:', data);
console.error('no errors');
console.log('******* DONE *******');
}
})();
While Quasimodo's clone's answer does work, his comment on the question made me think about passing the large strings of HTML. I have instead opted to write the html to file and reference with the id.
I am trying to write a php code that takes coefficients from a html form, sends them to a python algorithm that returns a json object. That object is a list of player names, basically {"Ji" : "Firstname Lastname"} for i from 1 to 15.
The python code (interface.py) I have to create this json is :
import json
i=0
for joueur in best_team:
i+=1
output["J%s"%(i)]=joueur['nom']
out=json.dumps(output)
print(out)
best_team is a list of player dictionnaries with data on them. My player names don't involve any non ASCII characters or whatever.
My php code is the following :
$command = "python interface.py";
$command .= " $coeff1 $coeff2 $coeff3 $coeff4 $coeff5 $coeff6 $coeff7 $coeff8 $coeff9 $coeff10 2>&1";
$pid = popen( $command,"r");
while( !feof( $pid ) )
{
$data = fread($pid, 256);
$data= json_decode($data) ;
echo $data->J1;
flush();
ob_flush();
echo "<script>window.scrollTo(0,99999);</script>";
usleep(100000);
}
pclose($pid);
I call the coefficients from the html and then send back the results via a js file.
But I just get the following error : Notice: Trying to get property of non-object.
Nothing wrong with the js file because if I try instead :
$string = '{"foo": "bar", "cool": "attributlong"}';
$result = json_decode($string);
echo $result ->cool;
It works.
Also if I have instead in my python file :
out={"foo":"bar","word":"longerthaneightcharacters"}
out=json.dumps(out)
print(out)
It works as well (replacing J1 by word in php code of course).
And funny enough, if i have in python:
output={}
i=0
for joueur in best_team:
i+=1
output["J%s"%(i)]="short"
output["J%s"%(i)]=str(output["J%s"%(i)])
out=json.dumps(output)
print(out)
It works, and if I replace "short" by "longerthaneightcharacters" it doesn't work anymore.
So basically my question is, why is there a maximum number of characters in my output loop and how can I bypass it ? Thanks, I am very confused.
I am breaking my head to make this work but I am in a dead end. I have no idea what I am doing wrong.
I play with php and python; trying to execute a python script through php exec(), return an output and pass it to another python script.
This is my workflow:
1) Through jquery and an ajax request I pass some data to a php file (exec1.php) which looks like this:
$number = $_POST['numberOfClusters'];
$shape = $_POST['shapeFilePath'];
// EXECUTE THE PYTHON SCRIPT
$command = "python ./python/Module1.py $number $shape";
exec($command,$out,$ret);
print_r($out);
print_r($r); //return nicely 1.
2) The python file which I run Module1.py looks like this:
# this is a list of list of tuples
cls000 = [[(365325.342877, 4385460.998374), (365193.884409, 4385307.899807), (365433.717878, 4385148.9983749995)]]
# RETURN DATA TO PHP
print cls000
3) Then I have a nested AJAX request inside the success function of my previous AJAX request in which I pass the response (in this case the cls000 list) into a php script called (exec2.php) like this:
# PASS VARIABLES FROM FORM
$number = $_POST['numberOfClusters'];
$shape = $_POST['shapeFilePath'];
$clusterCoords = $_POST['response']; # response from previous Ajax request
// EXECUTE THE PYTHON SCRIPT
$command = "python ./python/Module2.py $number $shape $clusterCoords";
exec($command,$out,$ret);
print_r($out); ## THIS GIVES ME AN EMPTY ARRAY!!
print_r($ret); ## THIS GIVES ME A RETURN STATUS: 2
4) My Module2.py script looks like this:
number = int(sys.argv[1])
shape = sys.argv[2]
cls000 = json.loads(sys.argv[3])
# RETURN DATA TO PHP
print cls000
What am I doing wrong? If I remove this line 'cls000 = json.loads(sys.argv[9])' and return for example 'shape' everything works fine. But when I try to return cls000 I get a status code 2.
What am I missing here?
Is it possible to pass BASH associative arrays as argv to PHP scripts?
I have a bash script, that collects some variables to a bash associative array like this. After that, I need to send it to PHP script:
typeset -A DATA
DATA[foo]=$(some_bash_function "param1" "param2")
DATA[bar]=$(some_other_bash_function)
php script.php --data ${DATA[#]}
From PHP script, i need to access the array in following manner:
<?php
$vars = getopt("",array(
"data:"
));
$data = $vars['data'];
foreach ($data as $k=>$v) {
echo "$k is $v";
}
?>
What I've tried
Weird syntax around the --data parameter follows advice from a great post about bash arrays from Norbert Kéri how to force passed parameter as an array:
You have no way of signaling to the function that you are passing an array. You get N positional parameters, with no information about the datatypes of each.
However this sollution still does not work for associative arrays - only values are passed to the function. Norbert Kéri made a follow up article about that, however its eval based solution does not work for me, as I need to pass the actual array as a parameter.
Is the thing I'm trying to achieve impossible or is there some way? Thank you!
Update: What I am trying to accomplish
I have a few PHP configuration files of following structure:
<?php
return array(
'option1' => 'foo',
'option2' => 'bar'
)
My bash script collects data from user input (through bash read function) and stores them into bash associative array. This array should be later passed as an argument to PHP script.
php script.php --file "config/config.php" --data $BASH_ASSOC_ARRAY
So instead of complicated seds functions etc. I can do simple:
<?php
$bash_input = getopt('',array('file:,data:'));
$data = $bash_input['data'];
$config = require($config_file);
$config['option1'] = $data['option1'];
$config['option2'] = $data['option2'];
// or
foreach ($data as $k=>$v) {
$config[$k] = $v;
}
// print to config file
file_put_contents($file, "<?php \n \n return ".var_export($config,true).";");
?>
This is used for configuring Laravel config files
Different Approach to #will's
Your bash script:
typeset -A DATA
foo=$(some_bash_function "param1" "param2")
bar=$(some_other_bash_function)
php script.php "{'data': '$foo', 'data2': '$bar'}"
PHP Script
<?php
$vars = json_decode($argv[1]);
$data = $vars['data'];
foreach ($data as $k=>$v) {
echo "$k is $v";
}
?>
EDIT (better approach) Credit to #will
typeset -A DATA
DATA[foo]=$(some_bash_function "param1" "param2")
DATA[bar]=$(some_other_bash_function)
php script.php echo -n "{"; for key in ${!DATA[#]}; do echo - "'$key'":"'${DATA[$key]}'", | sed 's/ /,/g' ; done; echo -n "}"
this does what you want (i think) all in one bash script. You can obviously move the php file out though.
declare -A assoc_array=([key1]=value1 [key2]=value2 [key3]=value3 [key4]=value4)
#These don't come out necesarily ordered
echo ${assoc_array[#]} #echos values
echo ${!assoc_array[#]} #echos keys
echo "" > tmp
for key in ${!assoc_array[#]}
do
echo $key:${assoc_array[$key]} >> tmp # Use some delimeter here to split the keys from the values
done
cat > file.php << EOF
<?php
\$fileArray = explode("\n", file_get_contents("tmp"));
\$data = array();
foreach(\$fileArray as \$line){
\$entry = explode(":", \$line);
\$data[\$entry[0]] = \$entry[1];
}
var_dump(\$data);
?>
EOF
php file.php
the escaping is necessary in the cat block annoyingly.
I'm trying to run a C program of adding two numbers with PHP in a web browser. But when I run the command
exec"gcc name.c -o a & a" it
returns some garbage result like sum is : 8000542.00. It doesn't ask for any input.
I want to give inputs to scanf from the browser. Please suggest to me how can I resolve my problem.
I have tried this but couldn't handle it successfully.
$desc = array(0=> array ('pipe','w'), 1=> array ('pipe','r'));
$cmd = "C:\xampp\htdocs\add.exe";
$pipes=array();
$p = proc_open($cmd,$desc,$pipes);
if(is_resource($p))
{
echo stream_get_contents($pipes[0]);
fclose($pipes[0]);
$return_value=proc_close($p);
echo $return_value;