标准输入到第二个命令/密码保护的 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'));
我希望创建一个 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'));