Comment passer des variables comme stdin en ligne de commande à partir de PHP
j'essaie d'écrire un script PHP qui utilise le pdftk application pour fusionner un XFDF avec un formulaire PDF et produire le PDF fusionné à l'utilisateur. Selon la documentation pdftk, je peux passer les données du formulaire dans via stdin
et avoir le PDF de sortie de la stdout
stream. La façon normale, file-not-stream d'utiliser pdftk depuis la ligne de commande est:
pdftk blankform.pdf fill_form formdata.xfdf output filledform.pdf
pour utiliser les flux sur la ligne de commande, vous devez taper:
pdftk blankform.pdf fill_form - output -
j'ai un couple de problèmes:
1) j'ai obtenu pdftk pour retourner la sortie via stdout
en utilisant un fichier xfdf (au lieu de stdin
):
exec("pdftk blankform.pdf fill_form formdata.xfdf output -", $pdf_output);
file_put_contents("filledform.pdf",$pdf_output);
mais le pdf qu'il crée est corrompu, selon Adobe Reader et un rapide coup d'oeil au fichier avec un éditeur de texte montre que, à tout le moins, il ne fixe pas les fins de ligne où ils devraient être. J'ai un PDF identique créé par pdftk où il sort vers un fichier, et le pdf semble bien dans l'éditeur de texte, donc je sais que ce n'est pas pdftk qui envoie de mauvaises données.
2) je ne peux pas pour la vie de me comprendre comment mettre le stdin
stream en PHP pour que je puisse utiliser ce stream comme entrée pour pdftk. D'après ce que je lis sur la documentation PHP,stdin
est en lecture seule, alors comment ne jamais entrer dans le flux?
idéalement, j'aimerais que ce soit très simple et éviter d'utiliser proc_open()
. J'ai essayé d'utiliser cette fonction et n'a pas été très réussi, ce qui est probablement ma faute, pas le mais mes objectifs sont assez simples, je préfère éviter d'utiliser des fonctions robustes dont je n'ai pas besoin.
idéalement, mon code ressemblerait à quelque chose comme:
$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 -);
Juste un heads-up, il est possible de mettre le code xml de la chaîne dans la ligne de commande, mais j'ai eu très résultats peu fiables avec cette.
Modifier
Avec beaucoup d'aide, je comprends maintenant que ma vraie question était: "comment pouvez diriger une variable à une exécution de ligne de commande en PHP". Apparemment proc_open est la meilleure façon d'y aller, ou du moins la plus simple. Comme il m'a fallu une éternité pour comprendre cela et puisque mes recherches sur Google suggère que d'autres peuvent être en difficulté, je vais poster le code qui a spécifiquement travaillé pour mon problème:
$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 réponses
je ne suis pas sûr de ce que vous essayez d'atteindre. Vous pouvez lire stdin avec l'URL php: / / stdin. Mais c'est le stdin de la ligne de commande PHP, pas celui de pdftk (via exec).
Mais je vais vous donner un +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) Pourquoi sortez-vous de la norme et mettez-vous ce genre de choses dans un fichier? Pourquoi ne pas simplement avoir pdftk dump vers le fichier, i.e.
exec("pdftk blankform.pdf fill_form formdata.xfdf output filledform.pdf");
2) Utiliser proc_open()
. N'hésitez pas à poster tout problème que vous avez avec la fonction.