Как передать переменные как stdin в командную строку из PHP - PullRequest
27 голосов
/ 06 марта 2010

Я пытаюсь написать 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);

Но PDF-файл, который он создает, поврежден, согласно Adobe Reader, и быстрый просмотр файла с помощью текстового редактора показывает, что, по крайней мере, он не устанавливает окончания строк там, где они должны быть. У меня есть такой же PDF-файл, созданный pdftk, где он выводится в файл, и pdf отлично выглядит в текстовом редакторе, поэтому я знаю, что это не pdftk, выводящий неверные данные.

2) Я не могу понять, как установить поток stdin в PHP, чтобы я мог использовать этот поток в качестве входных данных для 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;
}

Ответы [ 2 ]

26 голосов
/ 06 марта 2010

Я не уверен в том, чего ты пытаешься достичь.Вы можете прочитать stdin с помощью URL php: // stdin.Но это стандартный ввод из командной строки PHP, а не из pdftk (через exec).

Но я дам +1 за 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;
}
?>
0 голосов
/ 06 марта 2010

1) Почему вы выводите в стандартный формат, а затем помещаете этот материал в файл? Почему бы просто не создать дамп pdftk в файл, т.е.

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

2) Используйте proc_open(). Не стесняйтесь сообщать о любых проблемах, связанных с этой функцией.

...