mikl
mikl

Reputation: 1007

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

In this case there are two PHP files, stdin.php (child process component) and proc_open.php (parent process component), both are stored in the same folder of the public_html of a domain. There is also Program X, that pipes data into stdin.php.


stdin.php (this component works)

It is a process that should not be executed throught a browser, because it is destinated to receive input from Program X, and back it all up in a file (named stdin_backup). This process is working, because every time Program X pipes input, the process backs it up entirely. If this process is executed with input not passed (such is the case of executing it from a browser), the process creates a file (named stdin_error) with the text "ERROR".

Below, part of the code is ommited because the process works (as mentioned above). The code shown is just to illustrate:

#!/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 (this component isn't working)

It is a process that must be executed throught a browser, and is destinated to pass input to stdin.php, as Program X does. This process is failing, because every time it is executed, there is no signal of stdin.php being executed: no stdin_error file, no stdin_backup file, not even PHP error_log file.

Code:

// 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);
}

I am not sure if the command passed to proc_open() is correct, because I have not found examples for this case, and as mentioned above, this script is failing. I dont know what else can be incorrect with proc_open.php.

Also when I execute the proc_open.php process, an infinite loop produces, printing the next string over and over:

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


Tryed popen('php ' . __DIR__ . '/stdin.php', 'w') instead, and had exaclty the same result: the infinite loop error printing the same string of above, no errors, no logs, and no signals of stdin.php execution.

Upvotes: 4

Views: 7051

Answers (1)

helmbert
helmbert

Reputation: 38014

If I understand your question correctly, you want to open a process and write data into that process' STDIN stream. You can use the proc_open function for that:

$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);

If you simply want to test your 2nd script, It would probably be easier to simply use a shell command:

$ echo "your data" | php script2.php

Or alternatively,

$ php script2.php < datafile.txt

Update, accounting for your edit to the question

When using the popen function, you can either open the process for reading or writing. That allows you to read the process' STDOUT stream or write into the STDIN stream (but not both; if that's a requirement, you'll need to use proc_open). If you want to write into the STDIN stream, specify "w" as 2nd parameter to popen to open the process for writing:

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

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

Upvotes: 8

Related Questions