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)

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

관련 정보