這是我自己嘗試做的:
$ 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 上? :)