dompdf/dompdf · error · Dompdf\Exception
Permission denied on $file. The communication protocol is no
Error message
Permission denied on $file. The communication protocol is not supported.
What it means
loadHtmlFile() enforces a protocol whitelist before any I/O: the URI's scheme must be a key of Options::allowedProtocols (defaults: data://, file://, http://, https://). Any other scheme — or a scheme an administrator removed while hardening dompdf against SSRF/LFI — throws this permission error immediately. It is a security control, not an incidental failure.
Source
Thrown at src/Dompdf.php:357
*
* Parse errors are stored in the global array `$_dompdf_warnings`.
*
* @param string $file A filename or URL to load.
* @param string|null $encoding Encoding of the file.
*/
public function loadHtmlFile($file, $encoding = null)
{
$this->setPhpConfig();
if (!$this->protocol && !$this->baseHost && !$this->basePath) {
[$this->protocol, $this->baseHost, $this->basePath] = Helpers::explode_url($file);
}
$protocol = strtolower($this->protocol);
$uri = Helpers::build_url($this->protocol, $this->baseHost, $this->basePath, $file, $this->options->getChroot());
$allowed_protocols = $this->options->getAllowedProtocols();
if (!array_key_exists($protocol, $allowed_protocols)) {
throw new Exception("Permission denied on $file. The communication protocol is not supported.");
}
if ($protocol === "file://") {
$ext = strtolower(pathinfo($uri, PATHINFO_EXTENSION));
if (!in_array($ext, $this->allowedLocalFileExtensions)) {
throw new Exception("Permission denied on $file: The file extension is forbidden.");
}
}
foreach ($allowed_protocols[$protocol]["rules"] as $rule) {
[$result, $message] = $rule($uri);
if (!$result) {
throw new Exception("Error loading $file: $message");
}
}
[$contents, $http_response_header] = Helpers::getFileContent($uri, $this->options->getHttpContext());
if ($contents === null) {View on GitHub (pinned to b14267808b)
Solutions
- Extend the whitelist deliberately: $options->setAllowedProtocols([...]) — note it REPLACES the map, so include every protocol you need with their rules.
- Or fetch the document yourself (curl/Guzzle) and pass the body to $dompdf->loadHtml($html) — this respects app-level network controls instead of dompdf's.
- If remote loading is not required, keep it disabled and generate/load local HTML.
Example fix
// before
$dompdf->loadHtmlFile('ftp://example.com/report.html'); // throws: ftp not allowed
// after: either whitelist the protocol
$dompdf->getOptions()->setAllowedProtocols([
'data://' => ['rules' => []],
'file://' => ['rules' => []],
'http://' => ['rules' => []],
'https://' => ['rules' => []],
'ftp://' => ['rules' => []],
]);
// or bypass with explicit fetching
$dompdf->loadHtml(file_get_contents_curl('ftp://example.com/report.html')); Defensive patterns
Strategy: validation
Validate before calling
$scheme = strtolower(parse_url($file, PHP_URL_SCHEME) . '://');
$allowed = $dompdf->getOptions()->getAllowedProtocols();
if (!array_key_exists($scheme, $allowed)) {
throw new InvalidArgumentException("Protocol not allowed by dompdf config: $file");
}
$dompdf->loadHtmlFile($file); Try / catch
try {
$dompdf->loadHtmlFile($file);
} catch (\Dompdf\Exception $e) {
if (strpos($e->getMessage(), 'communication protocol is not supported') !== false) {
$dompdf->loadHtml(file_get_contents_via_app_client($file)); // app-controlled fetch
}
} Prevention
- Derive the allowed-protocol configuration from one place in your app so code and config cannot drift.
- Default to fetching remote documents with your HTTP client and passing strings to loadHtml().
- Document the SSRF rationale for any protocol you keep enabled.
When it happens
Trigger: $dompdf->loadHtmlFile('ftp://server/doc.html') or any wrapper outside the whitelist; a deployment calls setAllowedProtocols() with only file:// (anti-SSRF hardening) while application code still loads http(s):// URLs; custom stream wrappers used as the document source.
Common situations: Hardening dompdf after security guidance (removing remote protocols), then legacy features that render remote pages break; passing wrapper-prefixed paths like phar:// or php://temp; inconsistent configuration between staging and production.
Related errors
AI-assisted analysis of dompdf/dompdf@b14267808b (2026-08-21).
Data as JSON: /api/errors/c7774251cae14447.
Report an issue: GitHub.