I know there are already 3 standard streams: STDIN (0), STDOUT (1), and STDERR (2). I am testing the possibility of utilizing non-standard streams (> 2) in PHP.
My intention is to write to a non-standard FD (FD 3) if it is writable, otherwise fallback to an alternative (which defaults to STDERR). I have tried the following code, which is working perfectly fine:
<?php
//This is done so that notices regarding invalid FDs are thrown as errors
set_error_handler('errorHandler');
function errorHandler($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) return;
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}
file_put_contents("php://fd/1", "Writing to STDOUT!n");
file_put_contents("php://fd/2", "Writing to STDERR!n");
write2Fd(3, "Writing to FD 3!n");
function write2Fd(int $fd, string $contents, int $alt = 2) {
try {
//Try writing to the given FD
file_put_contents("php://fd/$fd", $contents);
} catch(Exception $e) {
//Fallback to alternative FD
file_put_contents("php://fd/$alt", $contents);
}
}
?>
I am running the program on a Linux (Arch) system in Bash shell with the following command:
php test.php 3>fd3out.txt
This output is shown in the terminal:
Writing to STDOUT!
Writing to STDERR!
And this text is found inside the fd3out.txt file:
Writing to FD 3!
The code is inspired from this answer, which achieves the same task in Python.
Using try-catch seems to be a hacky way to solve the problem of checking whether a stream is writable or not. I have also tried alternative solutions which involve using file_exists and is_writable:
function write2Fd(int $fd, string $contents, int $alt = 2) {
$file = "php://fd/$fd";
if (file_exists($file) && is_writable($file)) file_put_contents($file, $contents);
else file_put_contents("php://fd/$alt", $contents);
}
But for some reason, both the checks return false even if FD 3 is created by the parent process.
What is the correct way to check if a stream is available and whether it is writable or not in PHP?