PHPでプロセス置換ファイルを開く方法は?

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 6php-5.4.14bash-4.1.5)、Arch Linuxphp-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 ]]]] )

ああ、/dev/fd/63ここではPHPは通常のファイルとして扱われますが、実際にはfile descriptor

ファイル記述子にアクセスするには、ファイル記述子63の内容にアクセスするをphp://fd使用する必要があります。php://fd/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私はエコ出力から改行を取り除いた。それ以外の場合、PHPは「test.txt \ n」が出力されるのを見るでしょう。

ノート

PHPでファイル記述子にアクセスする方法の詳細については、以下を参照してください。ここ

答え2

問題は次のとおりです。

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

phpリンク先の実際の名前を取得しようとする妥当な理由(IMHO)はありません。残念ながら、リンク先はファイルシステムの一部ではないため、その名前へのアクセスが失敗し、このエラーが発生します。シンボリックリンクはこの方法でのみ開くことができます。私はこれが間違いだと思います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

関連情報