제가 직접 시도한 작업은 다음과 같습니다.
$ 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_contents
PHP 매뉴얼에서 함수 의 프로토타입을 볼 수 있습니다 .
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 -n
echo 출력에서 줄 바꿈을 제거하는 데 사용합니다. 그렇지 않으면 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에 갇혀 있는지 궁금합니다. :)