Я пытаюсь создать PDF-файл для получения заказа "на лету" из HTML, который также генерируется "на лету", а затем отправить его кому-нибудь по электронной почте.
Я действительно не хочу создавать файл, прикреплять его к электронному письму, а затем удалять файл, поэтому я пытаюсь отправить html в wkhtmltopdf через STDIN (из Perl), а затем захватить вывод PDF из wkhtmltopdf по электронной почте вложение с использованием MIME::Lite Email::Mime.
Это абсолютно работает при использовании Perl, позволяя людям загружать динамически сгенерированный PDF-файл с моего веб-сайта, но при попытке использовать его с MIME::Lite Email::Mime не работает. т работать. (это, вероятно, сработало бы, но поскольку оно устарело, вместо него мы используем Email::Mime)
Я абсолютно уверен, что это связано с отсутствием у меня фундаментального понимания работы с файловыми дескрипторами, конвейерами, обратными кавычками и другими редко используемыми вещами, и я хотел бы лучше понять эти вещи.
Вот что работает:
#!/usr/bin/perl
#### takes string containing HTML and outputs PDF to browser to download
#### (otherwise would output to STDOUT)
print "Content-Disposition: attachment; filename='testPDF.pdf'\n";
print "Content-type: application/octet-stream\n\n";
my $htmlToPrint = "<html>a bunch of html</html>";
### open a filehandle and pipe it to wkhtmltopdf
### *the arguments "- -" tell wkhtmltopdf to get
### input from STDIN and send output to STDOUT*
open(my $makePDF, "|-", "wkhtmltopdf", "-", "-") || die("$!");
print $makePDF $htmlToPrint; ## sends my HTML to wkhtmltopdf which streams immediately to STDOUT
exit 1;
Вы можете запустить это как есть из Apache, и он представит пользователю диалоговое окно загрузки и загрузит читаемый правильный PDF-файл с именем «testPDF.pdf».
РЕДАКТИРОВАТЬ: Решением является модуль Capture::Tiny (и Email::Mime):
#!/usr/bin/perl
use Capture::Tiny qw( capture );
use Email::Sender::Simple;
use Email::MIME::Creator;
my $htmlToPrint = "<html>a bunch of html</html>";
### it's important to capture STDERR as well, since wkhtmltopdf outputs
### its console messages on STDERR instead of STDOUT, so it can output
### the PDF to STDOUT; otherwise it will spam your error log
(my $pdfstream, my $consoleOutput, my @retvals) = capture {
open(my $makePDF, "|-", "wkhtmltopdf", "-", "-") || die("$!");
print $makePDF $htmlToPrint;
};
my @parts = (
Email::MIME->create(
attributes => {
content_type => "text/plain",
disposition => "inline",
charset => "US-ASCII",
encoding => "quoted-printable",
},
body_str => "Your order receipt is attached as a PDF.",
),
Email::MIME->create(
attributes => {
filename => "YourOrderReceipt.pdf",
content_type => "application/pdf",
disposition => "attachment",
encoding => "base64", ## base64 is ESSENTIAL, binary and quoted-printable do not work!
name => "YourOrderReceipt.pdf",
},
body => $pdfstream,
),
);
my $email = Email::MIME->create(
header_str => [
From => 'Some Person <[email protected]>',
To => '[email protected]',
Subject => "Your order receipt is attached...",
],
parts => [ @parts ],
);
Email::Sender::Simple->send($email);
exit 1;
Все это теперь отлично работает.
Большая часть проблемы заключается в том, что wkhtmltopdf не буферизует вывод PDF и не отправляет его построчно; он немедленно передает весь вывод PDF в STDOUT, как только получает ввод HTML из STDIN.
Я думаю, именно поэтому я не мог заставить работать open2 или open3.
Я также пробовал open (my $pdfOutput, "echo \"$htmlToPrint\"| wkhtmltopdf - -|")
, но это выполняется в оболочке, поэтому даже с $htmlToPrint
, заключенным в кавычки, команда подавляется символами, используемыми в HTML.
Надеюсь, кто-то найдет это полезным...
MIME::Lite
рекомендуется не использоватьMIME::Lite
. - person jordanm   schedule 30.01.2013MIME::Lite
тоже сработало бы, но я думаю, что использование более нового, рекомендованногоEmail::MIME
— это хорошо. Проблема заключалась в том, что вы не можете осуществлять двустороннюю связь с помощью каналов; вам нужен модуль типаCapture::Tiny
. Вложение электронной почты также должно было быть закодированоbase64
, чтобы работать. Пробовалbinary
иquoted-printable
безрезультатно. - person waldo22   schedule 02.02.2013