Я пытаюсь написать 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; }
Я не уверен, чего вы пытаетесь достичь. Вы можете прочитать stdin с URL-адресом php: // stdin. Но это 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; } ?>
1) Почему вы выходите на стандарт, а затем помещаете этот материал в файл? Почему бы просто не оставить pdftk в файле, т. Е.
exec("pdftk blankform.pdf fill_form formdata.xfdf output filledform.pdf");
2) Используйте proc_open()
. Не стесняйтесь публиковать любые проблемы, которые у вас есть с функцией.