Pipeline kết xuất HTML
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Khi bạn gọi writeHtml(), nó chạy một lượt tiến duy nhất trên HyperText Markup Language (HTML): token hóa đầu vào, phân giải @page cùng các kiểu, dàn nội dung và vẽ các toán tử Portable Document Format (PDF). Nó không giữ lại cây phần tử giữa các giai đoạn.
Cài đặt
Phần tiêu đề “Cài đặt”composer require nextpdf/core:^3Tổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”Pipeline kết xuất HTML chuyển HTML+CSS, tức HTML kết hợp với Cascading Style Sheets (CSS), thành các toán tử content-stream của PDF trong một lượt tiến duy nhất. Nó không dựng cây tài liệu để lưu giữ. Các giai đoạn dưới đây phản ánh HtmlParser::parse() trên main.
Giai đoạn 1 — Làm sạch và chuẩn hóa. HtmlParser::parse() từ chối đầu vào vượt quá 10 MB, loại bỏ ký tự điều khiển và chuẩn hóa ký tự xuống dòng: cả CRLF lẫn CR đơn đều trở thành LF, khớp với cách nguồn HTML được chuẩn hóa ký tự xuống dòng. Sau đó, nó đặt lại mọi trường thực thể, nên trạng thái từ lần gọi trước không thể bị mang sang.
Giai đoạn 2 — Trích xuất @page và các khối kiểu. Trình phân tích trước tiên trích xuất các khối <style>, rồi áp dụng các quy tắc @page đã phát hiện để cấu hình lại hình học trang. Việc này diễn ra trước khi xử lý bất kỳ token nào, vì kích thước trang ảnh hưởng đến mọi quyết định bố cục về sau.
Giai đoạn 3 — Token hóa. HtmlTokenizer::cleanHtml() chuẩn hóa khoảng trắng nhưng vẫn giữ nguyên nội dung <pre>. Sau đó, tokenize() tạo ra một list<HtmlToken> phẳng. Đây là danh sách token, không phải đồ thị node. Pipeline loại bỏ ngay các token văn bản chỉ chứa khoảng trắng. HtmlChildScanner::scan() dựng các bản đồ chỉ mục (số lượng phần tử con, số lượng thẻ, tính rỗng) trên danh sách phẳng, nên các bộ chọn cấu trúc không cần đến cây.
Giai đoạn 4 — Tiền quét :has() tùy chọn. Khi bạn bật tính năng thử nghiệm css.has, CssResolver::resolveHasSelectors() chạy một lượt tiền quét có giới hạn trên danh sách token để phân giải bộ chọn quan hệ. Bước có giới hạn và đã được ghi chép này là ngoại lệ đối với quy tắc một lượt.
Giai đoạn 5 — Xử lý token (kiểu, bố cục, vẽ). HtmlParser::processTokens() duyệt qua danh sách token một lần. Với mỗi phần tử, nó phân giải dòng kế thừa kiểu (các applicator của Layer 1 ghi HtmlStyleState), tính hình học (bố cục Layer 3) và phát ra các toán tử PDF (vẽ Layer 4). Việc kế thừa kiểu dùng một ngăn xếp HtmlStyleState theo cơ chế đẩy-và-lấy. Con trỏ (x, y, lề, độ dời luồng) di chuyển giữa các handler thông qua các snapshot HtmlBlockCursor.
Giai đoạn 6 — Trả về kết quả. parse() trả về một HtmlRenderResult bất biến, gồm luồng nội dung đã phát ra, vị trí con trỏ kết thúc và các khóa phông chữ đã dùng. Phía gọi (writeHtml()) chuyển con trỏ trở lại khung tọa độ của trang.
Để tìm hiểu cách phân tách bốn lớp bên trong Giai đoạn 5, hãy xem trang các giao kèo lớp. Để biết thuộc tính không lưu giữ cây và các giới hạn của nó, hãy xem trang các ràng buộc streaming.
Bề mặt API
Phần tiêu đề “Bề mặt API”| Ký hiệu | Vị trí | Giai đoạn |
|---|---|---|
Document::writeHtml(string $html): static | src/Core/Concerns/HasTextOutput.php | Điểm vào công khai |
HtmlParser::parse(string $html): HtmlRenderResult | src/Html/HtmlParser.php | Điều phối tất cả các giai đoạn |
HtmlTokenizer::cleanHtml() / tokenize() | src/Html/HtmlTokenizer.php | Giai đoạn 3 |
HtmlChildScanner::scan() | src/Html/HtmlChildScanner.php | Bản đồ chỉ mục của Giai đoạn 3 |
CssResolver::resolveHasSelectors() | src/Html/CssResolver.php | Giai đoạn 4 (có cổng kiểm soát) |
HtmlRenderResult (stream, endX, endY, usedFontKeys) | src/Html/HtmlRenderResult.php | Giai đoạn 6 |
Mã ví dụ — bắt đầu nhanh
Phần tiêu đề “Mã ví dụ — bắt đầu nhanh”Lấy nguồn từ examples/08-html-basic.php.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('HTML Basic');$doc->addPage();$doc->writeHtml('<h1 style="color:#1E3A8A;">HTML Rendering</h1><p>One pass.</p>');$doc->save(__DIR__ . '/output/08-html-basic.pdf');Mã ví dụ — bản dùng cho sản xuất
Phần tiêu đề “Mã ví dụ — bản dùng cho sản xuất”Kết xuất một báo cáo đã được định kiểu bằng một khối <style> nhúng. Pipeline trích xuất và áp dụng khối kiểu trước khi xử lý bất kỳ token nào.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\HtmlParsingException;
function renderInvoice(string $bodyHtml, string $out): void{ $doc = Document::createStandalone(); $doc->setTitle('Invoice'); $doc->addPage();
$html = '<style>@page { margin: 20mm; } ' . 'h1 { color: #1E3A8A; } ' . 'table { width: 100%; }</style>' . $bodyHtml;
try { $doc->writeHtml($html); } catch (HtmlParsingException $e) { // Sanitize/cap failures surface here. Do not retry. throw $e; }
$doc->save($out);}Trường hợp biên & những điểm cần lưu ý
Phần tiêu đề “Trường hợp biên & những điểm cần lưu ý”@pageđược đọc trước token. Một quy tắc@pageđặt sau nội dung vẫn được áp dụng, vì việc trích xuất kiểu diễn ra trước khi token hóa. Hình học trang được cố định trước Giai đoạn 5.- Khoảng trắng
<pre>được giữ nguyên.cleanHtml()bảo vệ nội dung<pre>; pipeline gộp khoảng trắng ở những chỗ khác. :has()có cổng kiểm soát. Nếu bạn không bật tính năng thử nghiệmcss.has, Giai đoạn 4 sẽ không chạy và các bộ chọn:has()sẽ không khớp.- Một bộ đệm luồng duy nhất. Pipeline ghi vào một bộ đệm chuỗi duy nhất. Nó không bao giờ di chuyển nội dung đã ghi. Không có bước dàn lại bố cục.
- Các giới hạn áp dụng giữa lượt. Các giới hạn về số phần tử và độ lồng nhau ném lỗi trong Giai đoạn 5, không phải trước đó. Một tài liệu có thể thất bại giữa chừng.
Hiệu năng
Phần tiêu đề “Hiệu năng”Pipeline duyệt với độ phức tạp O(số lượng token). Việc định kích thước cột bảng thêm một lượt quét hàng có giới hạn cho từng bảng (Giai đoạn 5, TableParser). Khi được bật, lượt tiền quét :has() thêm một lượt duyệt danh sách token có giới hạn (Giai đoạn 4). Bộ nhớ là O(độ sâu lồng nhau) cho ngăn xếp kiểu, không phải O(số lượng phần tử); xem các ràng buộc streaming. Phép đo chuẩn hiệu năng của pipeline kết xuất HTML dùng một cổng 5% để phòng ngừa suy giảm (công việc đã hợp nhất, PR #564). performance_budget theo từng trang (wall_ms: 1500, peak_mb: 64) là trần vận hành.
Ghi chú bảo mật
Phần tiêu đề “Ghi chú bảo mật”Giai đoạn 1 là ranh giới bảo mật đầu tiên: giới hạn đầu vào 10 MB, loại bỏ ký tự điều khiển và chuẩn hóa ký tự xuống dòng đều chạy trước khi token hóa. Trong Giai đoạn 5, DefaultHtmlSecurityPolicy kiểm soát các thẻ, thuộc tính, thuộc tính CSS và lược đồ URL được cho phép. Xem mô hình bảo mật của mô-đun HTML.
Tính tuân thủ
Phần tiêu đề “Tính tuân thủ”Việc chuẩn hóa ký tự xuống dòng tuân theo cách tiêu chuẩn HTML xử lý ký tự xuống dòng: CRLF và CR đơn trở thành LF. Tính tuân thủ CSS theo từng thuộc tính được ghi chép trong ma trận hỗ trợ CSS, còn hành vi dòng kế thừa được ghi chép trên css-resolver. Trang này không trình bày lại mức hỗ trợ theo từng thuộc tính.
Bối cảnh thương mại
Phần tiêu đề “Bối cảnh thương mại”Khả năng dành cho doanh nghiệp. Premium mở rộng phạm vi hỗ trợ CSS trên cùng pipeline. Trình tự sáu giai đoạn không thay đổi giữa các phiên bản. Xem ma trận hỗ trợ CSS.