问题:是否可以在 exec 或 passthru 命令中使用 php:// memory ?
我可以在exec或passthru中使用php变量没有问题,但是我遇到了php:// memory的问题
背景:
我试图用PDFTK消除我所有的临时pdf文件写作
1)我正在写一个临时的fdf文件
2)使用#1形式填写临时pdf文件
3)对所有pdfs重复#1和#2
4)将所有pdf合并在一起。
这当前有效 - 但它会创建大量文件,并且是瓶颈。
我想通过使用虚拟文件php:// memory
来加快pdftk的速度首先,我试图虚拟化#1中使用的fdf文件。单独回答这个问题就足以得到“正确答案”。 :)
代码如下:
$fdf = 'fdf file contents here';
$tempFdfVirtual= fopen("php://memory", 'r+');
if( $tempFdfVirtual ) {
fwrite( $tempFdfVirtual, $fdf);
} else {
echo "Failure to open temporary fdf file";
exit;
}
rewind( $tempFdfVirtual);
$url = "unfilled.pdf";
$temppdf_fn = "output.pdf";
$command = "pdftk $url fill_form $tempFdfVirtual output $temppdf_fn flatten";
$error="";
exec( $command, $error );
if ($error!="") {
$_SESSION['err'] = $error;
} else {
$_SESSION['err'] = 0;
}
我收到错误代码#1。如果我执行stream_get_contents($ tempFdfVirtual),它会显示内容。
感谢您的期待!
答案 0 :(得分:4)
php://memory
和php://temp
(实际上任何文件描述符)仅适用于当前运行的php进程。此外,$tempFdfVirtual
是一个资源句柄,因此将它放在字符串中是没有意义的。
您应该通过标准输入将资源句柄中的数据传递给流程。您可以使用proc-open
执行此操作,这使您可以更好地控制子进程的输入和输出,而不是exec
。
请注意,由于某种原因,您无法将“php:// memory”文件描述符传递给进程。 PHP会抱怨:
警告:proc_open():不能将MEMORY类型的流表示为文件描述符
使用php://temp
代替,它应该是完全相同的,除非它会在流变得足够大时使用临时文件。
这是一个经过测试的示例,说明了使用proc_open()
的代码的一般模式。这应该包含在函数或其他抽象中:
$testinput = "THIS IS A TEST STRING\n";
$fp = fopen('php://temp', 'r+');
fwrite($fp, $testinput);
rewind($fp);
$cmd = 'cat';
$dspec = array(
0 => $fp,
1 => array('pipe', 'w'),
);
$pp = proc_open($cmd, $dspec, $pipes);
// busywait until process is finished running.
do {
usleep(10000);
$stat = proc_get_status($pp);
} while($stat and $stat['running']);
if ($stat['exitcode']===0) {
// index in $pipes will match index in $dspec
// note only descriptors created by proc_open will be in $pipes
// i.e. $dspec indexes with an array value.
$output = stream_get_contents($pipes[1]);
if ($output == $testinput) {
echo "TEST PASSED!!";
} else {
echo "TEST FAILED!! Output does not match input.";
}
} else {
echo "TEST FAILED!! Process has non-zero exit status.";
}
// cleanup
// close pipes first, THEN close process handle.
foreach ($pipes as $pipe) {
fclose($pipe);
}
// Only file descriptors created by proc_open() will be in $pipes.
// We still need to close file descriptors we created ourselves and
// passed to it.
// We can do this before or after proc_close().
fclose($fp);
proc_close($pp);
未经测试的特定于您使用PDFTK的示例:
// Command takes input from STDIN
$command = "pdftk unfilled.pdf fill_form - output tempfile.pdf flatten";
$descriptorspec = array(
0 => $tempFdfVirtual, // feed stdin of process from this file descriptor
// 1 => array('pipe', 'w'), // Note you can also grab stdout from a pipe, no need for temp file
);
$prochandle = proc_open($command, $descriptorspec, $pipes);
// busy-wait until it finishes running
do {
usleep(10000);
$stat = proc_get_status($prochandle);
} while ($stat and $stat['running']);
if ($stat['exitcode']===0) {
// ran successfully
// output is in that filename
// or in the file handle in $pipes if you told the command to write to stdout.
}
// cleanup
foreach ($pipes as $pipe) {
fclose($pipe);
}
proc_close($prochandle);
答案 1 :(得分:1)
这不只是你正在使用php://memory
,它是任何文件句柄。文件句柄仅存在于当前进程。对于所有意图和目的,您从fopen返回的句柄不能转移到脚本之外的任何其他位置。
只要您正在使用外部应用程序,您就会陷入使用临时文件的困境。您唯一的另一个选择是尝试将数据传递给stdin上的pdftk,并检索stdout上的输出(如果它支持)。据我所知,调用外部进程以及对其描述符(stdin / stdout)的访问权限的唯一方法是使用proc_
函数族,特别是proc_open。