Stdin到第二个命令/密码保护zip与PHP

时间:2015-03-31 08:18:15

标签: php bash zip stdin

我希望创建一个onbininer,将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流式传输到第二个命令,但我很可能忽略了另一个解决方案。我试图用proc_open和fwrite。

的php脚本来使用它

1 个答案:

答案 0 :(得分:1)

我认为不可能将此解决为单行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'));