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

2022-08-30 14:38:33

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

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

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

pdftk blankform.pdf fill_form - output -

我有几个问题:

1)我已经得到了pdftk通过使用xfdf文件(而不是)返回输出,如下所示:stdoutstdin

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

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

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

理想情况下,我想保持这个非常简单,并避免使用.我试图使用那个函数,但不是很成功,这可能是我的错,而不是函数的错,但实际上我的目标很简单,我宁愿避免使用我不需要的健壮函数。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;
}

答案 1

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

但是我会给+1proc_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;
}
?>

答案 2

1)你为什么要输出到标准输出,然后将这些东西放到一个文件中?为什么不直接将pdftk转储到文件中,即

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

2) 使用 .请随时发布您对该功能的任何问题。proc_open()


推荐