跳轉到

Chrome 渲染器

ChromeRenderer 是 Artisan 的核心渲染引擎,透過 Chrome DevTools Protocol(CDP)控制 Chromium 無頭瀏覽器實例,將 HTML/CSS 轉換為 PDF bytes。渲染器設計為無狀態——每次渲染呼叫從 BrowserPool 取得連線、執行渲染、歸還連線,自身不持有任何瀏覽器狀態。

PHP Compatibility

This example uses PHP 8.5 syntax. If your environment runs PHP 8.1 or 7.4, use NextPDF Backport for a backward-compatible build.

CSS 支援範圍

ChromeRenderer 透過真實 Chromium 引擎渲染,因此支援所有現代 CSS 特性:

CSS 特性 支援狀態 備註
Flexbox 完整支援 CSS Flexible Box Layout Module Level 1
Grid 完整支援 CSS Grid Layout Module Level 2
CSS 變數 (var()) 完整支援 Custom Properties
CSS Transforms 完整支援 2D & 3D
Web Fonts 完整支援 woff2、system fonts
@media print 完整支援 建議搭配 @page 規則
CSS Animations 靜態快照 渲染為動畫第一幀
backdrop-filter 完整支援 需 Chromium ≥ 76

建立渲染器

<?php

declare(strict_types=1);

use NextPDF\Artisan\ChromeRenderer;
use NextPDF\Artisan\BrowserPool;
use NextPDF\Artisan\Config\RendererConfig;
use NextPDF\Artisan\ValueObjects\PageFormat;
use NextPDF\Artisan\ValueObjects\PrintMargin;

$renderer = ChromeRenderer::create(
    pool: $pool, // BrowserPool 實例
    config: RendererConfig::create(
        pageFormat: PageFormat::A4,
        margin: PrintMargin::create(top: 15, right: 15, bottom: 15, left: 15),
        printBackground: true,
        preferCssPageSize: false,
        scale: 1.0,
        networkIdleTimeoutMs: 3000,
    ),
);

渲染方法

從 HTML 字串渲染

$pdfBytes = $renderer->renderHtml(
    html: $htmlString,
    pageFormat: 'A4',
    waitForSelector: '.ready', // 可選:等待指定 CSS 選擇器出現
);

從 URL 渲染

$pdfBytes = $renderer->renderUrl(
    url: 'https://internal.example.com/report/42',
    headers: ['Authorization' => 'Bearer ' . $token],
    networkIdlePolicy: 'networkIdle0', // 等待所有網路請求完成
);

從本機檔案渲染

$pdfBytes = $renderer->renderFile(
    path: '/var/www/templates/invoice.html',
    baseUrl: 'file:///var/www/templates/', // 解析相對資源路徑
);

CSP 沙箱安全

處理不受信任的 HTML 內容時,啟用 CSP 沙箱可防止 SSRF 與任意資源載入:

use NextPDF\Artisan\Config\CspPolicy;
use NextPDF\Artisan\Config\SandboxConfig;

$renderer = ChromeRenderer::create(
    pool: $pool,
    config: RendererConfig::create(
        sandbox: SandboxConfig::create(
            allowedOrigins: ['https://cdn.example.com'],
            csp: CspPolicy::strict(), // 阻擋 inline scripts、外部 fetches
            disableJavaScript: true,  // 靜態文件建議停用 JS
            disableExternalImages: false,
        ),
    ),
);

CDP 安全通道

ChromeRenderer 透過 WebSocket 連接 Chrome 的 CDP 端點。在生產環境中,應限制 CDP 監聽位址並設定連線認證:

use NextPDF\Artisan\Config\CdpConnectionConfig;

$pool = BrowserPool::create(
    config: BrowserPoolConfig::create(
        cdpConnection: CdpConnectionConfig::create(
            host: '127.0.0.1',          // 僅本機監聽
            port: 9222,
            connectTimeoutMs: 2000,
            tlsEnabled: false,           // 僅限內部網路使用 TLS 關閉
        ),
    ),
);

安全須知:CDP 端點具備完整瀏覽器控制能力,絕對不可暴露於公開網路。生產部署請使用 Unix domain socket 或 loopback 位址,並以防火牆規則限制存取。

逾時與重試策略

use NextPDF\Artisan\Config\RetryPolicy;

$renderer = ChromeRenderer::create(
    pool: $pool,
    config: RendererConfig::create(
        renderTimeoutMs: 30000,          // 單次渲染最長時間
        retry: RetryPolicy::create(
            maxAttempts: 2,
            backoffMs: 500,
            retryOnCrash: true,          // 瀏覽器崩潰時重試
        ),
    ),
);

例外處理

例外類別 觸發條件
ChromeRenderException CDP 通訊失敗、渲染逾時
BrowserPoolExhaustedException 連線池已滿、取得逾時
SandboxViolationException CSP 規則阻擋資源載入
PageCrashException Chromium 頁面崩潰

參見