Turn a form into a PDF
Written for mPDF 8.2 on PHP 8.1+. Updated 2 November 2026.
A common job is taking what someone typed into a form, such as an application or booking, and producing a tidy PDF of it. The PHP is short. The part that matters is treating the input as untrusted.
The form
<form method="post" action="/booking-pdf.php">
<label>Name <input name="name" required maxlength="100"></label>
<label>Email <input name="email" type="email" required></label>
<label>Date <input name="date" type="date" required></label>
<label>Notes <textarea name="notes" maxlength="2000"></textarea></label>
<button>Download confirmation</button>
</form>
The script
<?php
require __DIR__ . '/vendor/autoload.php';
function field(string $key, int $max): string
{
$value = trim((string) ($_POST[$key] ?? ''));
return mb_substr($value, 0, $max);
}
$name = field('name', 100);
$email = filter_var(field('email', 254), FILTER_VALIDATE_EMAIL);
$date = DateTime::createFromFormat('Y-m-d', field('date', 10));
$notes = field('notes', 2000);
if ($name === '' || !$email || !$date) {
http_response_code(422);
exit('Please fill in your name, a valid email and a date.');
}
$e = static fn (string $s): string => htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
$html = '<h1>Booking confirmation</h1>'
. '<table cellpadding="6">'
. '<tr><th align="left">Name</th><td>' . $e($name) . '</td></tr>'
. '<tr><th align="left">Email</th><td>' . $e($email) . '</td></tr>'
. '<tr><th align="left">Date</th><td>' . $date->format('j F Y') . '</td></tr>'
. '<tr><th align="left">Notes</th><td>' . nl2br($e($notes)) . '</td></tr>'
. '</table>';
$mpdf = new \Mpdf\Mpdf(['tempDir' => sys_get_temp_dir() . '/mpdf']);
$mpdf->SetTitle('Booking confirmation');
$mpdf->WriteHTML($html);
$mpdf->Output('booking-' . $date->format('Y-m-d') . '.pdf', \Mpdf\Output\Destination::DOWNLOAD);
Why the escaping matters
If raw input reaches WriteHTML(), a visitor can type HTML into your form, and mPDF will act on it:
- Local files:
<img src="/etc/passwd">, or similar tricks with other tags, can make mPDF try to read files on your server. - Server-side requests: an image URL pointing at an internal address makes your server fetch it.
- Layout breaking: even an innocent
<or&in a company name can corrupt the page.
htmlspecialchars turns all of these into harmless text. Escape every field, every time, including ones you think are safe, such as hidden inputs and select boxes, because the browser doesn’t stop anyone editing them. Build the HTML from your own template and only drop escaped values into it.
Also keep mPDF up to date. Security fixes for exactly this class of problem have shipped over the years.
Nice touches
nl2br()after escaping keeps the line breaks people typed.- Generate the file name from validated data, never straight from user input.
- For long free-text answers, set
autoScriptToLangandautoLangToFontso names and notes in any language display (see fonts and languages).