如何将变量作为 stdin 从 PHP 传递到命令行

发布于 2024-08-24 05:44:28 字数 2362 浏览 1 评论 0原文

我正在尝试编写一个 PHP 脚本,该脚本使用 pdftk 应用程序将 XFDF 与 PDF 表单合并,并且将合并后的 PDF 输出给用户。根据 pdftk 文档,我可以通过 stdin 传递表单数据,并将 PDF 输出到 stdout 流。从命令行使用 pdftk 的正常的、文件非流的方式是:

pdftk blankform.pdf fill_form formdata.xfdf output filledform.pdf

要在命令行上使用流,您需要输入:

pdftk blankform.pdf fill_form - output -

我有几个问题:

1)我已经让 pdftk 通过 stdout 使用 xfdf 文件(而不是 stdin),如下所示:

    exec("pdftk blankform.pdf fill_form formdata.xfdf output -", $pdf_output);
    file_put_contents("filledform.pdf",$pdf_output);

但是根据 Adob​​e Reader 的说法,它创建的 pdf 已损坏,并且使用文本编辑器快速查看该文件显示至少,它没有将行结尾设置在应有的位置。我有一个由 pdftk 创建的相同的 PDF,它输出到一个文件,并且 pdf 在文本编辑器中看起来很好,所以我知道不是 pdftk 输出了错误的数据。

2)我一生都无法弄清楚如何在 PHP 中设置 stdin 流,以便我可以使用该流作为 pdftk 的输入。从我在 PHP 文档中读到的内容来看,stdin 是只读的,那么什么东西是如何进入该流的呢?

理想情况下,我希望保持这个非常简单并避免使用 proc_open() 。我尝试使用该函数,但不太成功,这可能是我的错,而不是该函数的错,但实际上我的目标很简单,我宁愿避免使用我不需要的强大函数。

理想情况下,我的代码看起来像这样:

 $form_data_raw = $_POST;
 $form_data_xfdf = raw2xfdf($form_data_raw); //some function that turns HTML-form data to XFDF

 $blank_pdf_form = "blankform.pdf";

 header('Content-type: application/pdf');
 header('Content-Disposition: attachment; filename="output.pdf"');

 passthru("pdftk $blank_pdf_form fill_form $form_data_xfdf output -);

请注意,可以将实际的 xml 字符串放入命令行中,但我得到了非常不可靠的结果。

编辑

在很多帮助下,我现在明白我真正的问题是“如何将变量通过管道传递到 PHP 中的命令行执行”。显然 proc_open 是最好的方法,或者至少是最直接的方法。由于我花了很长时间才弄清楚这一点,而且我对谷歌的研究表明其他人可能会遇到困难,所以我将发布专门解决我的问题的代码:

$blank_pdf_form = "blankform.pdf";
$cmd = "pdftk $blank_pdf_form fill_form - output -";

$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w")
);

$process = proc_open($cmd, $descriptorspec, $pipes);

if (is_resource($process)) {

    //row2xfdf is made-up function that turns HTML-form data to XFDF
    fwrite($pipes[0], raw2xfdf($_POST));
    fclose($pipes[0]);

    $pdf_content = stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    $return_value = proc_close($process);

    header('Content-type: application/pdf');
    header('Content-Disposition: attachment; filename="output.pdf"');
    echo $pdf_content;
}

I am trying to write a PHP script that uses the pdftk app to merge an XFDF with a PDF form and output the merged PDF to the user. According to the pdftk documentation, I can pass the form data in via stdin and have the PDF output to the stdout stream. The normal, file-not-stream way to use pdftk from the command line is:

pdftk blankform.pdf fill_form formdata.xfdf output filledform.pdf

to use streams on the command line, you'd enter:

pdftk blankform.pdf fill_form - output -

I have a couple of problems:

1) I have gotten pdftk to return output via stdout using an xfdf file (instead of stdin) like so:

    exec("pdftk blankform.pdf fill_form formdata.xfdf output -", $pdf_output);
    file_put_contents("filledform.pdf",$pdf_output);

But the pdf that it creates is corrupt, according to Adobe Reader and a quick peek at the file with a text editor shows that, at the very least, it is not setting the line endings where they should be. I have an identical PDF created by pdftk where it output to a file, and the pdf looks fine in the text editor, so I know that it's not pdftk that's outputting bad data.

2) I can not for the life of me figure out how to set the stdin stream in PHP so that I can use that stream as my input for pdftk. From what I'm reading on the PHP documentation, stdin is read-only, so how does anything ever get into that stream?

Ideally, I would like to keep this really simple and avoid using proc_open(). I attempted to use that function and wasn't very sucessful, which is probably my fault, not the function's, but really my goals are simple enough I'd rather avoid using robust functions I don't need.

Ideally my code would look something like:

 $form_data_raw = $_POST;
 $form_data_xfdf = raw2xfdf($form_data_raw); //some function that turns HTML-form data to XFDF

 $blank_pdf_form = "blankform.pdf";

 header('Content-type: application/pdf');
 header('Content-Disposition: attachment; filename="output.pdf"');

 passthru("pdftk $blank_pdf_form fill_form $form_data_xfdf output -);

Just a heads up, it is possible to put the actual xml string in the command line, but I've had very unreliable results with this.

Edit

With much help, I now understand that my real question was "how can pipe a variable to a command line execution in PHP". Apparently proc_open is the best way to go, or at least the most straightforward. Since it took me forever to figure this out and since my research on Google suggests others may be struggling, I'll post the code that specifically worked for my problem:

$blank_pdf_form = "blankform.pdf";
$cmd = "pdftk $blank_pdf_form fill_form - output -";

$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w")
);

$process = proc_open($cmd, $descriptorspec, $pipes);

if (is_resource($process)) {

    //row2xfdf is made-up function that turns HTML-form data to XFDF
    fwrite($pipes[0], raw2xfdf($_POST));
    fclose($pipes[0]);

    $pdf_content = stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    $return_value = proc_close($process);

    header('Content-type: application/pdf');
    header('Content-Disposition: attachment; filename="output.pdf"');
    echo $pdf_content;
}

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

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

发布评论

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

评论(2

煮茶煮酒煮时光 2024-08-31 05:44:28

我不确定你想要实现什么目标。您可以使用 URL php://stdin 读取 stdin。但这是来自 PHP 命令行的标准输入,而不是来自 pdftk 的标准输入(通过 exec)。

但我会给 proc_open() +1


<?php

$cmd = sprintf('pdftk %s fill_form %s output -','blank_form.pdf', raw2xfdf($_POST));

$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => null,
);

$process = proc_open($cmd, $descriptorspec, $pipes);

if (is_resource($process)) {
    // $pipes now looks like this:
    // 0 => writeable handle connected to child stdin
    // 1 => readable handle connected to child stdout

    fwrite($pipes[0], stream_get_contents(STDIN)); // file_get_contents('php://stdin')
    fclose($pipes[0]);

    $pdf_content = stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    // It is important that you close any pipes before calling
    // proc_close in order to avoid a deadlock
    $return_value = proc_close($process);


    header('Content-type: application/pdf');
    header('Content-Disposition: attachment; filename="output.pdf"');
    echo $pdf_content;
}
?>

I'm not sure about what you're trying to achieve. You can read stdin with the URL php://stdin. But that's the stdin from the PHP command line, not the one from pdftk (through exec).

But I'll give a +1 for proc_open()


<?php

$cmd = sprintf('pdftk %s fill_form %s output -','blank_form.pdf', raw2xfdf($_POST));

$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => null,
);

$process = proc_open($cmd, $descriptorspec, $pipes);

if (is_resource($process)) {
    // $pipes now looks like this:
    // 0 => writeable handle connected to child stdin
    // 1 => readable handle connected to child stdout

    fwrite($pipes[0], stream_get_contents(STDIN)); // file_get_contents('php://stdin')
    fclose($pipes[0]);

    $pdf_content = stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    // It is important that you close any pipes before calling
    // proc_close in order to avoid a deadlock
    $return_value = proc_close($process);


    header('Content-type: application/pdf');
    header('Content-Disposition: attachment; filename="output.pdf"');
    echo $pdf_content;
}
?>
微凉 2024-08-31 05:44:28

1)为什么要输出到标准输出,然后将这些内容放入文件中?为什么不直接将 pdftk 转储到文件中,即

exec("pdftk blankform.pdf fill_form formdata.xfdf output filledform.pdf");

2) 使用 proc_open()。如果您对该功能有任何问题,请随时发布。

1) Why are you outputting to standard out and then putting that stuff into a file? Why not just have pdftk dump to the file, i.e.

exec("pdftk blankform.pdf fill_form formdata.xfdf output filledform.pdf");

2) Use proc_open(). Feel free to post any problems you have with the function.

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