如何使用 proc_open() 函数通过管道传输到 PHP 进程?

How to pipe to PHP process using the proc_open() function?

在这种情况下有两个 PHP 文件,stdin.php(子进程组件)和 proc_open.php(父进程组件),两者都存放在同一个域的public_html文件夹中。还有 Program X,将数据通过管道传输到 stdin.php。


stdin.php(此组件有效)

这是一个不应该通过浏览器执行的过程,因为它注定要接收来自程序 X 的输入,并将其全部备份在一个文件(名为 stdin_backup)中。 这个过程正在运行,因为每次程序 X 通过管道输入时,这个过程都会完全备份它。如果在未传递输入的情况下执行此过程(例如从浏览器执行它的情况),则该过程会创建一个文件(名为 stdin_error),其中包含文本 "ERROR".

下面,部分代码被省略,因为该过程有效(如上所述)。显示的代码只是为了说明:

#!/usr/bin/php -q
<?php
   // Get the input
    $fh_stdin = fopen('php://stdin', 'rb');

    if (is_resource($fh_stdin)) {
        // ... Code that backs up STDIN in a file ...
    } else {
        // ... Code that logs "ERROR" in a file ...
    }
?>

proc_open.php(该组件不工作)

这是一个必须通过浏览器执行的进程,并且注定要像程序 X 一样将输入传递给 stdin.php。这个过程是失败的,因为每次执行,都没有stdin.php被执行的信号:没有stdin_error文件,没有stdin_backup文件,甚至没有PHPerror_log 文件.

代码:

// Execute a PHP process and pipe input to it
//  - Specify process command
$process_path = __DIR__ . '/stdin.php';
$process_execution_command = 'php ' . $process_path;

//  - Specify process descriptor
$process_descriptor = array(
    0 => array('pipe', 'r') // To child's STDIN
);

//  - Specify pipes container
$pipes = [];

//  - Open process
$process = proc_open($process_execution_command, $process_descriptor, $pipes);

if (is_resource($process)) {
    //  - Send data to the process STDIN
    $process_STDIN = 'Data to be received by the process STDIN';
    fwrite($pipes[0], $process_STDIN);
    fclose($pipes[0]);

    //  - Close process
    $process_termination_status = proc_close($process);
}

我不确定传递给 proc_open() 的命令是否正确,因为我没有找到这种情况的示例,并且如上所述,该脚本失败了。我不知道 proc_open.php.

还有什么不正确的地方

另外,当我执行 proc_open.php 过程时,会产生一个无限循环,一遍又一遍地打印下一个字符串:

X-Powered-By: PHP/5.5.20 Content-type: text/html; charset=UTF-8


尝试了 popen('php ' . __DIR__ . '/stdin.php', 'w'),结果完全相同:无限循环错误打印与上面相同的字符串,没有错误,没有日志,也没有 stdin.php 执行的信号。

如果我对你的问题的理解正确,你想打开一个进程并将数据写入该进程的 STDIN 流。您可以为此使用 proc_open 函数:

$descriptors = array(
    0 => array("pipe", "r"),  // STDIN
    1 => array("pipe", "w"),  // STDOUT
    2 => array("pipe", "w")   // STDERR
);

$proc = proc_open("php script2.php", $descriptors, $pipes);
fwrite($pipes[0], "Your data here...");
fclose($pipes[0]);

$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);

fclose($pipes[1]);
fclose($pipes[2]);

$exitCode = proc_close($proc);

如果您只想测试您的第二个脚本,使用shell命令可能会更容易:

$ echo "your data" | php script2.php

或者,

$ php script2.php < datafile.txt

更新,考虑到您对问题的编辑

使用popen功能时,您可以打开进程进行读取或写入。这允许您读取进程的 STDOUT 流或写入 STDIN 流(但不能同时进行;如果需要,您将需要使用 proc_open)。如果要写入 STDIN 流,请将 "w" 指定为 popen 的第二个参数以打开写入过程:

$fh_pipe = popen(
    'php script1.php',
    'w'   // <- "w", not "r"!
);

fwrite($fh_pipe, 'EMAIL TEXT') ;
pclose($fh_pipe);