Вот что я попробовал сделать сам:
$ 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? :)