Как открыть файл Process Replaced из PHP?

Как открыть файл Process Replaced из PHP?

Вот что я попробовал сделать сам:

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

Я протестировал это на Debian 6( php-5.4.14, bash-4.1.5) и Arch Linux( php-5.4.12, bash-4.2.42).

ОБНОВЛЕНИЕ

$ 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

решение1

Проблема в том, что вы хотите, чтобы PHP считывал входные данные из файлового дескриптора, но вы заставляете его читать как обычный файл.

Сначала попробуйте это:

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

затем вы можете обработать lsвывод, прочитав /dev/fd/63. Подстановка процесса вернет file descriptor, который используется другой командой для чтения ее вывода.

В вашем случае вы используете $_SERVER["argv"][1], что означает, что php будет интерпретировать так:

file_get_contents(/dev/fd/63)

В руководстве по PHP вы можете увидеть прототип file_get_contentsфункции:

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

Упс, php /dev/fd/63здесь будет рассматриваться как обычный файл, но на самом деле это file descriptor.

Чтобы получить доступ к файловому дескриптору, необходимо использовать php://fd, php://fd/63будет получен доступ к содержимому файлового дескриптора 63:

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

Вы можете видеть, теперь php может обрабатывать содержимое в /dev/fd/63. Но наша цель — чтение содержимого файла, которое предоставляется через подстановку процесса (в моем примере это test.txt). Я не очень хорошо разбираюсь в php, поэтому добавляю еще одно 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!
"

Я использую его echo -nдля удаления новой строки из вывода echo, в противном случае php увидит вывод "test.txt\n".

Примечание

Более подробную информацию о доступе к дескриптору файла в PHP можно найти здесь.здесь.

решение2

Это проблема:

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

Без какой-либо веской причины (IMHO) phpпытается получить настоящее имя цели ссылки. К сожалению, цель ссылки не является частью файловой системы, поэтому попытка доступа к этому имени не удалась и привела к этой ошибке. Символическая ссылка может быть открыта только как таковая. Я считаю это ошибкой в php​​. Вместо этого вы можете использовать FIFO:

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

решение3

Это старый вопрос, но я только что нашел ответ, поэтому решил поделиться. Может, кому-то поможет.

Вместо этого вы можете использовать php://потоковую оболочку для открытия файлового дескриптора:

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

Так что вместо открытия /dev/fd/[nn]файлового дескриптора, предоставленного ОС. Вы будете открывать php://fd/[nn]то, что будет работать. Я не уверен, почему открытие файлового дескриптора не удается в некоторых системах, но не в других.

Это былостарая ошибкаи должен был быть исправлен.

решение4

Вот что я в итоге использовал...

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

Если вы пытаетесь сделать что-то другое с помощью stdin, то это, очевидно, не сработает для вас, и это ничем не отличается от

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

что заставляет меня задуматься, что же вы на самом деле пытались сделать, и почему вы застряли на file_get_contents? :)

Ссылка -http://php.net/manual/en/wrappers.php.php

Связанный контент