php - 如何将变量作为标准输入从 PHP 传递到命令行

标签 php command-line stream stdin pdftk

我正在尝试编写一个使用 pdftk 的 PHP 脚本。应用程序将 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 使用 xfdf 文件(而不是 stdin)通过 stdout 返回输出,如下所示:

    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 是最好的方法,或者至少是最直接的方法。由于我花了很长时间才弄清楚这一点,而且我对 Google 的研究表明其他人可能正在苦苦挣扎,所以我将发布专门解决我的问题的代码:

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

最佳答案

我不确定您要达到的目标。您可以使用 URL php://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;
}
?>

关于php - 如何将变量作为标准输入从 PHP 传递到命令行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2390604/

相关文章:

PHP 创建的文件 | SSH 无法删除(权限被拒绝)

json - 转换文件完整内容nodejs

c# - 使用 Stream.BeginRead 的顺序异步读取

php - 将当前年份和月份与 sql 查询中输入的数据库年月进行比较

php - 如何在 laravel 中通过路由名称获取路由 url 模式?

php - Codeigniter - 限制从 URL 调用直接访问 Controller 功能

java - 如何在没有jar文件的情况下在命令行中编译和运行Netbeans java项目?

git - .gitignore 不会停止在文件中跟踪更改

android' 未被识别为内部或外部命令

java - 为什么我的 UART 在 Java 中的性能会有所不同?