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 6( php-5.4.14bash-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://fdphp://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 -necho 出力から改行を削除します。そうしないと、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]したがって、 OS によって提供されるファイル記述子を開く代わりに、開くと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

関連情報