제가 직접 시도한 작업은 다음과 같습니다.
$ 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에 갇혀 있는지 궁금합니다. :)