¿Cómo abrir el proceso de archivo sustituido desde php?

¿Cómo abrir el proceso de archivo sustituido desde php?

Esto es lo que intenté hacer yo mismo:

$ type 1.sh
#!/bin/bash -eu
php -r 'var_dump(file_get_contents($_SERVER["argv"][1]));' -- <(echo 1)
$ ./1.sh
PHP Warning:  file_get_contents(/dev/fd/63): failed to open stream: No such file or directory in Command line code on line 1

Warning: file_get_contents(/dev/fd/63): failed to open stream: No such file or directory in Command line code on line 1
bool(false)

Lo probé en Debian 6( php-5.4.14, bash-4.1.5) y Arch Linux( php-5.4.12, bash-4.2.42).

UPD

$ strace -f -e trace=file php -r 'var_dump(file_get_contents($_SERVER["argv"][1]));' -- <(echo 1)
...
open("/usr/lib/php5/20100525/mongo.so", O_RDONLY) = 3
lstat("/dev/fd/63", {st_mode=S_IFLNK|0500, st_size=64, ...}) = 0
readlink("/dev/fd/63", "pipe:[405116]"..., 4096) = 13
lstat("/dev/fd/pipe:[405116]", 0x7fff5ea44850) = -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", "31536"..., 4096) = 5
lstat("/proc/31536", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
lstat("/proc", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/31536/fd/pipe:[405116]", O_RDONLY) = -1 ENOENT (No such file or directory)
PHP Warning:  file_get_contents(/dev/fd/63): failed to open stream: No such file or directory in Command line code on line 1

Warning: file_get_contents(/dev/fd/63): failed to open stream: No such file or directory in Command line code on line 1
bool(false)

$ strace -f -e trace=file php <(echo 12)
...
open("/usr/lib/php5/20100525/mongo.so", O_RDONLY) = 3
open("/dev/fd/63", O_RDONLY)            = 3
lstat("/dev/fd/63", {st_mode=S_IFLNK|0500, st_size=64, ...}) = 0
readlink("/dev/fd/63", "pipe:[413359]", 4096) = 13
lstat("/dev/fd/pipe:[413359]", 0x7fffa69c3c00) = -1 ENOENT (No such file or directory)
lstat("/dev/fd/63", {st_mode=S_IFLNK|0500, st_size=64, ...}) = 0
readlink("/dev/fd/63", "pipe:[413359]", 4096) = 13
lstat("/dev/fd/pipe:[413359]", 0x7fffa69c19b0) = -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", "32214"..., 4096) = 5
lstat("/proc/32214", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
lstat("/proc", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
2

Respuesta1

El problema es que quieres que php lea la entrada de un descriptor de archivo, pero lo obligas a leer como un archivo normal.

Primero, prueba esto:

$ echo <(ls)
/dev/fd/63

entonces puedes procesar lsla salida leyendo /dev/fd/63. La sustitución del proceso devolverá el archivo file descriptor, que otro comando utiliza para leer su salida.

En su caso, usa $_SERVER["argv"][1], lo que significa que php se interpretará así:

file_get_contents(/dev/fd/63)

Desde el manual de php, puedes ver el prototipo de file_get_contentsla función:

string file_get_contents ( string $filename [, bool $use_include_path =
false [, resource $context [, int $offset = -1 [, int $maxlen ]]]] )

Ops, php se considerará /dev/fd/63un archivo normal aquí, pero en realidad es un archivo file descriptor.

Para acceder al descriptor de archivo, debe utilizar php://fd, php://fd/63accederá al contenido del descriptor de archivo 63:

$ php -r 'var_dump(file_get_contents("php://".substr($_SERVER["argv"][1],-5)));' -- <(echo test.txt)
string(9) "test.txt
"

Puedes ver que ahora PHP puede procesar contenido en formato /dev/fd/63. Pero nuestro propósito es leer el contenido del archivo, que se proporciona mediante sustitución de procesos (en mi ejemplo, es test.txt). No sé mucho sobre php, así que agrego otro file_get_contents:

$ php -r 'var_dump(file_get_contents(file_get_contents("php://".substr($_SERVER["argv"][1],-5))));' -- <(echo -n test.txt)
string(13) "Hello world!
"

Utilizo echo -npara eliminar la nueva línea de la salida de eco; de lo contrario, php verá la salida "test.txt\n".

Nota

Para obtener más información sobre cómo acceder al descriptor de archivos en php, puede veraquí.

Respuesta2

Este es el problema:

readlink("/dev/fd/63", "pipe:[405116]"..., 4096) = 13
lstat("/dev/fd/pipe:[405116]", 0x7fff5ea44850) = -1 ENOENT

Sin ninguna buena razón (en mi humilde opinión), phpintenta obtener el nombre real del destino del enlace. Lamentablemente, el destino del enlace no forma parte del sistema de archivos, por lo que el intento de acceder a ese nombre falla y provoca este error. El enlace simbólico sólo se puede abrir como tal. Considero que esto es un error en php. Podrías usar un FIFO en su lugar:

mkfifo /my/fifo; output_cmd >/my/fifo & php -r ... /my/fifo

Respuesta3

Esta es una vieja pregunta, pero acabo de descubrir la respuesta, así que pensé en compartirla. Quizás ayude a alguien.

En su lugar , puede utilizar el php://contenedor de secuencia para abrir el descriptor de archivo:

 $fd = $argv[1];
 $handle = fopen(str_replace('/dev/','php://',$fd)); 

Entonces, en lugar de abrir el /dev/fd/[nn]descriptor de archivo proporcionado por el sistema operativo. Estarás abriendo php://fd/[nn]lo que funcionará. No estoy seguro de por qué falla la apertura del descriptor de archivo en algunos sistemas pero no en otros.

Este fue unviejo errory se suponía que había sido arreglado.

Respuesta4

Esto es lo que terminé usando...

php -r "var_dump(file_get_contents('php://stdin'));" < <(echo this is a win)

Si estás intentando hacer otras cosas con stdin, esto obviamente no funcionará para ti, y esto no es diferente de

php -r "var_dump(stream_get_contents(STDIN));" < <(echo this is a win)

lo que me lleva a preguntarme qué es lo que realmente intentabas hacer y por qué estás atascado en file_get_contents. :)

Referencia -http://php.net/manual/en/wrappers.php.php

información relacionada