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.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)

file_get_contentsPHP 매뉴얼에서 함수 의 프로토타입을 볼 수 있습니다 .

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 -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

관련 정보