标准输入到第二个命令/密码保护的 zip php

Stdin to second command / password protected zip with php

我希望创建一个 oneliner,将 stdin 流转换为受密码保护的 zip 存档中的(命名)文件。

到目前为止我有:

mkfifo importlog.txt; cat - > importlog.txt & zip --password testpass - --fifo importlog.txt; rm importlog.txt;

当我将 cat - 替换为 echo "content" 时效果很好,但是当 cat - 就位时,会创建一个带有空 importlog.txt 的 zip 文件。我确实更喜欢流式传输内容,因为内容会很多。

我想我的问题是如何将 stdin 流式传输到第二个命令,但很可能我忽略了其他解决方案。我正在尝试通过 php 脚本将其与 proc_open 和 fwrite.

一起使用

我认为单行 bash 代码无法解决此问题。我最终编写了一个更大的 php 函数,通过命名管道流式传输内容。

function createSingleFileZipArchive($filename, $contents, $password = null){

    $filename = (string) $filename;
    if(mb_strlen(trim($filename)) === 0){
        throw new LengthException('Filename empty');
    }

    //create subfolder in tempdir containing process id to prevent concurrency issues
    $tempDir = sys_get_temp_dir().'/phpzip-'.getmypid();
    if(!is_dir($tempDir)){
        mkdir($tempDir);
    }

    //create FIFO and start zip process that reads fifo stream
    $madeFifo = posix_mkfifo($tempDir.'/'.$filename, 0600);
    if($madeFifo === false){
        throw new RuntimeException('failed to create fifo to stream data to zip process.');
    }
    $proc = proc_open('cd '.$tempDir.'; zip'.($password === null ? null : ' --password '.escapeshellarg($password)).' - --fifo '.escapeshellarg($filename), [['pipe', 'r'],['pipe', 'w'],['pipe', 'w']], $pipes);
    if($proc === false){
        throw new RuntimeException('failed to start zip-process');
    }

    //write to fifo
    $in = fopen($tempDir.'/'.$filename, 'w'); //always open fifo writer after reader is opened, otherwise process will lock
    fwrite($in, $contents);
    fclose($in);

    //get output before reading errors.
    //If no errors/debug output was generated the process could otherwise hang.
    $output = stream_get_contents($pipes[1]);

    //check if any errors occurred
    if ($err = stream_get_contents($pipes[2])) {
        $errorOutput = [];
        foreach(explode($err,PHP_EOL) as $errLine){
            $errLine = trim($errLine);
            if(strlen($errLine) > 0 && strpos($errLine, 'Reading FIFO') === false && strpos($errLine, 'adding:') === false){ //ignore default notices.
                $errorOutput[] = trim($errLine);
            }
        }
        if(count($errorOutput) > 0){
            throw new RuntimeException("zip-error: ".implode('; ',$errorOutput));   
        }
    }

    //cleanup
    foreach($pipes as $pipe){
        fclose($pipe);
    }
    proc_close($proc);
    unlink($tempDir.'/'.$filename);
    rmdir($tempDir);

    //done
    return $output;

}

file_put_contents('importlog.zip',createSingleFileZipArchive('importlog.txt','test contents','testpass'));