PDFTK 与 php://内存

发布于 2024-12-28 16:34:36 字数 1059 浏览 3 评论 0原文

问题:是否可以在 execpassthru 命令上使用 php://memory

我可以在 exec 或 passthru 中使用 php 变量,没有问题,但我在 php://memory 方面遇到问题

背景: 我正在尝试消除使用 PDFTK 编写的所有临时 pdf 文件。
1)我正在编写一个临时fdf文件
2) 使用 #1 填写临时 pdf 文件
3) 对所有 pdf 重复 #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),它会显示内容。

感谢您的关注!

Question: Is it possible to use php://memory on a exec or passthru command?

I can use php variables in the exec or passthru with no problem, but I am having trouble with php://memory

background:

I am trying to eliminate all of my temporary pdf file writing with PDFTK.
1)I am writing an temporary fdf file
2) form-fill a temporary pdf file using #1
3) repeat #1 and #2 for all the pdfs
4) merge all pdf's together.

This currently works - but it creates a lot of files, and is the bottleneck.

I would like to speed things up with pdftk by making use of the virtual file php://memory

First, I am trying to just virtualize the fdf file used in #1.
Answering this alone is enough for a 'correct answer'.   :)

The code is as follows:

$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;
}

I am getting an errorcode #1. If I do a stream_get_contents($tempFdfVirtual), it shows the contents.

Thanks for looking!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酷遇一生 2025-01-04 16:34:36

php://memoryphp://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);

php://memory and php://temp (and in fact any file descriptor) are only available to the currently-running php process. Besides, $tempFdfVirtual is a resource handle so it makes no sense to put it in a string.

You should pass the data from your resource handle to the process through its standard-in. You can do this with proc-open, which gives you more control over input and output to the child process than exec.

Note that for some reason, you can't pass a 'php://memory' file descriptor to a process. PHP will complain:

Warning: proc_open(): cannot represent a stream of type MEMORY as a File Descriptor

Use php://temp instead, which is supposed to be exactly the same except it will use a temporary file once the stream gets big enough.

This is a tested example that illustrates the general pattern of code that uses proc_open(). This should be wrapped up in a function or other abstraction:

$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);

Untested Example specific to your use of 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);
情话已封尘 2025-01-04 16:34:36

这不仅仅是您使用php://memory,它是任何文件句柄。文件句柄仅存在于当前进程中。出于所有意图和目的,从 fopen 返回的句柄不能传输到脚本之外的任何其他位置。

只要您使用外部应用程序,您就几乎无法使用临时文件。您唯一的其他选择是尝试将数据传递到 stdin 上的 pdftk,并在 stdout 上检索输出(如果它支持)。据我所知,调用外部进程并对其描述符(stdin/stdout)进行这种访问的唯一方法是使用 proc_ 系列函数,特别是 proc_open

It's not just that you're using php://memory, it's any file handle. File handles only exist for the current process. For all intents and purposes, the handle you get back from fopen cannot be transferred to any other place outside of your script.

As long as you're working with an outside application, you're pretty much stuck using temporary files. Your only other option is to try and pass the data to pdftk on stdin, and retrieve the output on stdout (if it supports that). As far as I know the only way to invoke an external process with that kind of access to its descriptors (stdin/stdout) is using the proc_ family of functions, specifically proc_open.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文