Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
870 views
in Technique[技术] by (71.8m points)

pipe - PHP won't open fifo for writing

I am writing a wee wrapper (in PHP 7.0.33) around a complex binary which takes its input from a named file. As this will be processing secrets, I don't want to commit the data to the filesystem, hence using a FIFO rather than conventional file. The binary will happily read its data from a FIFO (tested using 2 shell sessions - in one I created the fifo and started the binary, in the second I catted a file into the fifo).

However in PHP the call to fopen() blocks, regardless if I specify w, a or c

  if (posix_mkfifo("myfifo", 0600)) {
     $writer=fopen("myfifo", 'w'); // this blocks
     `binary myfifo`;
     fputs($writer, $mydata);
  }

While I would expect writes to block if nothing is reading the data, I did not expect fopen() to block.

It does appear to work (execution continues, and the binary is started) with "w+" however the binary fails with

 QIODevice::read (QFile, "filename"): device not open

To investigate further, I wrote a simple replacement for the binary. Again this works when I cat a file into the FIFO:

$in='';
$fh=fopen($argv[1],'r');
if (is_resource($fh)) {
        print "File opened
";
        while (!feof($fh)) {
                $in.=fgets($fh);
        }
} else {
        print "failed to open file
";
}

file_put_contents("output", $in);

but when I write to the FIFO from the PHP code....

fopen(import): failed to open stream: No such file or directory in ...
question from:https://stackoverflow.com/questions/65621742/php-wont-open-fifo-for-writing

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

By default, opening a FIFO will block until there is at least one reader and writer. The rationale for this is that the kernel has no place to stash the pipe data if no process is there to consume it. man page for fifo:

... the FIFO special file has no contents on the file system, the file system entry merely serves as a reference point so that processes can access the pipe using a name in the file system.

The kernel maintains exactly one pipe object for each FIFO special file that is opened by at least one process. The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.

You can bypass this behaviour though. One way is like you've done - by opening the read and write end yourself. The other is to set O_NONBLOCK flag when opening the file (you can set it back to block afterwards). AFAIK you can't do that with fopen. Example with dio library:

<?php
echo "Opening
";
$writer = dio_open("myfifo", O_CREAT | O_WRONLY | O_NONBLOCK) or die("Could not create FIFO
");
echo "Open. Writing
";
dio_write($writer, "DATA");
echo "Done
";

The caveat with doing this is, if there is no reader, the process above will write the data, then exit immediately and then the data is lost forever.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...