将$ _POST传递给外部命令

时间:2018-11-27 22:37:21

标签: php post request pipe

我有一个程序可以从stdin读取JSON请求,我想在PHP中调用它。 这就是我现在所拥有的

<?php
echo exec(
  'echo \''.json_encode($_POST,JSON_NUMERIC_CHECK).'\' | '.
  'program'
);
?>

这有效,但是有没有更直接的方法在stdin中将字符串放入PHP? 可能与pipe(json_encode($_POST,JSON_NUMERIC_CHECK),'program')相似吗?

在这种情况下,我所拥有的可能很好,但是如果我需要代替二进制数据而不是JSON,该怎么办?如果太长而无法放入shell参数或包含单引号怎么办?

修改

按照miken32的建议,我这样使用proc_open()

$proc = proc_open(
  'LD_LIBRARY_PATH=/foo/bar/lib program args',
  array(0 => array('pipe','r'), 1 => array('pipe','w')),
  $pipes,
  NULL
  //, array('LD_LIBRARY_PATH','/foo/bar/lib')
);
if (is_resource($proc)) {
  fwrite($pipes[0],json_encode($_POST,JSON_NUMERIC_CHECK));
  fclose($pipes[0]);

  echo stream_get_contents($pipes[1]);
  fclose($pipes[1]);

  proc_close($proc);
}
?>

但是我必须在命令参数中添加LD_LIBRARY_PATH=/foo/bar/lib$env参数似乎无效。有人知道为什么吗?

1 个答案:

答案 0 :(得分:1)

您可以使用popen()创建到流程的管道:

<?php
$data = json_encode($_POST, JSON_NUMERIC_CHECK);
$p = popen("program", "w");
fwrite($p, $data . PHP_EOL);
$exit_code = pclose($p);

如果您需要从程序中获取数据,则会涉及更多事情,而您需要使用proc_open()

<?php
$data = json_encode($_POST, JSON_NUMERIC_CHECK);
$fds = [
    0=>["pipe", "r"], // STDIN
    1=>["pipe", "w"], // STDOUT
    2=>["pipe", "w"], // STDERR
];
$dir = "/path/to/working/directory";
$env = [
    "PATH"            => "/usr/local/foo/bin:/usr/local/bin:/usr/bin",
    "LD_LIBRARY_PATH" => "/usr/local/foo/lib/",
];
$p = proc_open("program", $fds, $pipes, $dir, $env);
fwrite($pipes[0], $data . PHP_EOL);
fclose($pipes[0]);
$return = stream_get_contents($pipes[1]);
$err    = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$exit_code = proc_close($p);
if ($exit_code == 0) {
    // successful return
    echo $return;
} else {
    // error
    echo "ERR: $err";
}