这是我自己尝试做的:
$ 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
) 上进行了测试。
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
答案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 ]]]] )
Ops,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
没有任何充分的理由(恕我直言)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 上? :)