php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #53465 Cannot open file descriptor streams
Submitted: 2010-12-03 18:24 UTC Modified: 2010-12-11 02:53 UTC
From: dchurch at sciencelogic dot com Assigned: cataphract (profile)
Status: Duplicate Package: Filesystem function related
PHP Version: 5.3.3 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: dchurch at sciencelogic dot com
New email:
PHP Version: OS:

 

 [2010-12-03 18:24 UTC] dchurch at sciencelogic dot com
Description:
------------
PHP cannot open, read from, or write to arbitrary file descriptors, a feature that is necessary for communications with certain utilities that expect input or output on certain file descriptors.  When programming in C, this functionality is provided by fdopen().  A feature request was filed over seven years ago for PHP to have a similar capability through the php:// stream wrapper (#26158), but the bug was marked as bogus for no adequately defined reason.

The alternative to being able to use a fdopen()-like function is to open the file descriptor as a named file through /dev/fd/ or /proc/self/fd/.  This works in C using fopen("/dev/fd/<descriptor>", "w"), but it does not work in PHP because PHP incorrectly attempts to dereference the pseudo-symlink before opening it.

I have a C program and a PHP script that both attempt to do the same thing: open file descriptor 3 for writing using /dev/fd/3, read until EOF from standard in and write to the file descriptor.  Both should be run as:

(executable) 3>&1 | cat

Test script:
---------------
PHP script:
<?php
$file = fopen("/dev/fd/3", "w");

if (!$file) exit(1);

$input = stream_get_contents(STDIN);
fwrite($file, $input);
fclose($file);

C program:
#include <stdio.h>

int main() {
  char buf[8192];
  int count;
  FILE *file;

  file = fopen("/dev/fd/3", "w");

  if (file == NULL) {
    perror("Opening /dev/fd/3");
    return 1;
  }

  while ((count = fread(buf, 1, sizeof(buf), stdin)) > 0) {
    fwrite(buf, count, 1, file);
    if (feof(stdin)) break;
  }
  return 0;
}

Expected result:
----------------
Input should be mirrored to file descriptor 3; when called using the command line above, it should be mirrored to standard output.

Actual result:
--------------
I get the following warning:

PHP Warning:  fopen(/dev/fd/3): failed to open stream: No such file or directory in test.php on line 2

An strace of the PHP process shows the incorrect behavior:

lstat("/dev/fd/3", {st_mode=S_IFLNK|0300, st_size=64, ...}) = 0
readlink("/dev/fd/3", "pipe:[637257]", 4096) = 13
lstat("/dev/fd/pipe:[637257]", 0x7fff76ae8140) = -1 ENOENT (No such file or directory)
lstat("/dev/fd", {st_mode=S_IFLNK|0777, st_size=13, ...}) = 0
readlink("/dev/fd", "/proc/self/fd"..., 4096) = 13
lstat("/proc/self/fd", {st_mode=S_IFDIR|0500, st_size=0, ...}) = 0
lstat("/proc/self", {st_mode=S_IFLNK|0777, st_size=64, ...}) = 0
readlink("/proc/self", "28234"..., 4096) = 5
lstat("/proc/28234", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
lstat("/proc", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/28234/fd/pipe:[637257]", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1 ENOENT (No such file or directory)


Patches

php_fd_open.diff (last revision 2010-12-06 22:24 UTC by cataphract@php.net)

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-12-06 23:24 UTC] cataphract@php.net
The following patch has been added/updated:

Patch Name: php_fd_open.diff
Revision:   1291674246
URL:        http://bugs.php.net/patch-display.php?bug=53465&patch=php_fd_open.diff&revision=1291674246
 [2010-12-06 23:29 UTC] cataphract@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: cataphract
 [2010-12-06 23:29 UTC] cataphract@php.net
I've attached a patch (against trunk) that allows duping+open arbitrary file descriptor. /dev/fd doesn't seem like a good option because it's not portable.

Example:
<?php
$f = fopen("php://fd/1", "w");
fwrite($f, "test");

Can you see if this is enough?

Thanks.
 [2010-12-08 21:17 UTC] dchurch at sciencelogic dot com
This works like a charm.  I much prefer the php://fd/ syntax to fixing the /dev/fd symlink trickery, anyway.  The patch also applies cleanly against the 5.3 branch.  Will this be in 5.3.4?
 [2010-12-09 01:31 UTC] cataphract@php.net
5.3.4 is in the final stages of the release process, so it will not be possible. Maybe 5.3.5, if the release manager agrees with the inclusion.
 [2010-12-11 02:52 UTC] cataphract@php.net
Automatic comment from SVN on behalf of cataphract
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=306215
Log: - Implemented request #26158/bug #53465 (open arbitrary file descriptor with fopen)
 [2010-12-11 02:53 UTC] cataphract@php.net
-Status: Assigned +Status: Duplicate
 [2010-12-11 02:53 UTC] cataphract@php.net
Committed to 5.3 and trunk.

I'm marking this as a duplicate and request #26158 as closed.

Thank you for your report.
 [2013-07-04 06:46 UTC] jakub dot lopuszanski at nasza-klasa dot pl
The problem with "php://fd/3" instead of "/dev/fd/3" is that when I use 
anonymous fifos in bash like this:

php -r 'var_dump($argv);' <(echo "hello")

then the output is as follows:

array(2) {
  [0]=>
  string(1) "-"
  [1]=>
  string(10) "/dev/fd/63"
}

which means that if you have an existing PHP program which accepts filenames, 
you have to add extra "if" to it, with special case just to handle /dev/fd/63 -> 
php://fd/3 conversion. I think that this adds extra complexity for the developer  
in a place where Linux tried hard to eliminate it.
 [2014-12-04 22:51 UTC] dave at lyte dot id dot au
It's a bit of a crazy work around, but if you're stuck with 5.3.3 for now (because it's the supported version in RHEL6 still) and you really really really want to do this:

$pid = getmypid();
$writeFd = popen("cat - > /proc/$pid/fd/3", 'w');
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Nov 23 23:01:26 2024 UTC