简体   繁体   English

PHP 不会打开 fifo 进行写入

[英]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.我正在围绕一个从命名文件获取输入的复杂二进制文件编写一个小包装器(在 PHP 7.0.33 中)。 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.由于这将处理机密,我不想将数据提交到文件系统,因此使用 FIFO 而不是传统文件。 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).二进制文件将愉快地从 FIFO 中读取其数据(使用 2 个 shell 会话进行测试 - 在其中一个我创建了 fifo 并启动了二进制文件,在第二个中我将一个文件放入了 fifo)。

However in PHP the call to fopen() blocks, regardless if I specify w, a or c但是在 PHP 中,无论我指定 w、a 还是 c,对 fopen() 的调用都会阻塞

  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.虽然如果没有任何内容读取数据,我希望写入会阻塞,但我没想到 fopen() 会阻塞。

It does appear to work (execution continues, and the binary is started) with "w+" however the binary fails with它似乎确实可以使用“w +”工作(执行继续,并且二进制文件启动)但是二进制文件失败了

 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:当我将文件放入 FIFO 时,这同样有效:

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

file_put_contents("output", $in);

but when I write to the FIFO from the PHP code....但是当我从 PHP 代码写入 FIFO 时......

fopen(import): failed to open stream: No such file or directory in ...

By default, opening a FIFO will block until there is at least one reader and writer.默认情况下,打开 FIFO 将阻塞,直到至少有一个读写器。 The rationale for this is that the kernel has no place to stash the pipe data if no process is there to consume it.这样做的理由是,如果没有进程可以使用 kernel ,则没有地方存储 pipe 数据。 man page for fifo : 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. ... FIFO 特殊文件在文件系统上没有内容,文件系统条目仅用作参考点,以便进程可以使用文件系统中的名称访问 pipe。

The kernel maintains exactly one pipe object for each FIFO special file that is opened by at least one process.对于由至少一个进程打开的每个 FIFO 特殊文件,kernel 只维护一个 pipe object。 The FIFO must be opened on both ends (reading and writing) before data can be passed. FIFO 必须在两端(读取和写入)都打开,才能传递数据。 Normally, opening the FIFO blocks until the other end is opened also.通常,打开 FIFO 会阻塞,直到另一端也打开。

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).另一种是在打开文件时设置O_NONBLOCK标志(您可以在之后将其设置回阻止)。 AFAIK you can't do that with fopen. AFAIK 你不能用 fopen 做到这一点。 Example with dio library:带有dio库的示例:

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

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.这样做的警告是,如果没有读取器,上述过程将写入数据,然后立即退出,然后数据将永远丢失。

For the benefit of anyone finding this question in Google and seeking a more detailled solution than comment on semisecure's answer:为了任何在 Google 中找到这个问题并寻求比对 semisecure 的答案发表评论更详细的解决方案的人的利益:

if (pcntl_fork()) {
    `binary myfifo`;
} else {
    $fh=fopen('myfifo', 'w');
    fputs($fh, $data);
    fclose($fh);
}

(but you might also want to add a SIGALRM on the writer in case "binary" does not execute / flush the pipe). (但您可能还想在编写器上添加一个 SIGALRM 以防“二进制”不执行/刷新管道)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM