Bỏ qua để đến nội dung

Di chuyển từ Dompdf sang NextPDF

Hướng dẫn này giúp bạn chuyển một codebase dựa trên Dompdf, dùng để tạo tệp Portable Document Format (PDF) từ Hypertext Markup Language (HTML), sang pipeline Html của NextPDF. Có thể chuyển phần lớn các điểm gọi theo quy tắc vì cả hai thư viện đều đi theo cùng một luồng tổng quát: tải HTML, kết xuất rồi xuất ra một tệp PDF. Phần cần xử lý thực sự là bảng ánh xạ tùy chọn và các khác biệt về hỗ trợ Cascading Style Sheets (CSS). NextPDF và Dompdf là hai engine độc lập, nên một bố cục mà Dompdf tạo ra tương thích với kết quả của NextPDF, chứ không giống hệt từng byte. Hướng dẫn này bao gồm ánh xạ động từ, ánh xạ khóa tùy chọn, các khác biệt về hành vi và một trình tự di chuyển an toàn.

Việc NextPDF hỗ trợ một tính năng HTML/CSS không đảm bảo rằng một tài liệu Dompdf sẽ được tái tạo giống hệt từng pixel. Bảng hỗ trợ CSS là nguồn chuẩn cho các tính năng đã được Xác minh. Hướng dẫn này mô tả hành vi; nó không khẳng định sự tương đương về mặt hình ảnh.

Terminal window
composer require nextpdf/core:^3

Giữ dompdf/dompdf trong trạng thái đã cài đặt suốt quá trình chuyển đổi. Trình tự di chuyển an toàn chạy song song cả hai engine cho đến khi từng điểm gọi được chuyển sang hẳn. Hãy gỡ gói này sau khi quá trình chuyển sang hoàn tất.

Đối tượng Dompdf của Dompdf là một facade duy nhất, sở hữu Document Object Model (DOM), bảng kiểu, cây frame và canvas. NextPDF tách riêng các mối quan tâm này: một NextPDF\Core\Document sở hữu mô hình trang và đầu ra, còn writeHtml() điều khiển pipeline HTML. Không có giai đoạn hai bước tách biệt kiểu “kết xuất, rồi xuất ra”. writeHtml() dàn trang nội dung ngay khi ghi, và bạn xuất tài liệu bằng save(), output() hoặc getPdfData().

Nội dung trang mà NextPDF ghi là content-stream được vẽ theo ISO 32000-2 (ISO 32000-2 §8, iso32000_2_sec8#x1.x3.p14). Hình học trang, do tùy chọn kích thước giấy kiểm soát, được ánh xạ vào MediaBox của đối tượng trang (ISO 32000-2 §7, iso32000_2_sec7#x1.x104.p10). Đây là các nền tảng của engine mà mọi trình ghi tuân thủ chuẩn đều chia sẻ. Thuật toán dàn trang biến CSS thành nội dung đó là của riêng NextPDF, và nó khác với của Dompdf; xem Các khác biệt về hành vi.

Application programming interface (API) Html của NextPDF được tài liệu hóa trong tài liệu tham khảo mô-đun Html, vốn được tạo tự động từ PHPDoc. Các điểm vào API được dùng bên dưới là Document::createStandalone(), Document::writeHtml(string $html): static, Document::writeHtmlCell(...), Document::output(?string, OutputDestination), Document::save(string $path): void, Document::getPdfData(): string, và value object NextPDF\Core\Config (pageSize, margins, fontsDirectory).

Các tên API công khai của Dompdf bên dưới được xác nhận đối chiếu với kho lưu trữ công khai thượng nguồn (dompdf/dompdf, master); xem tệp đính kèm xuất xứ _source-sidecar-upstream-api.md trong kho. Không có văn bản tài liệu thượng nguồn nào được sao chép lại.

DompdfNextPDFGhi chú
new Dompdf($options)Document::createStandalone($config)Dompdf nhận một đối tượng Options; NextPDF nhận một NextPDF\Core\Config. Dùng DocumentFactory cho các worker chạy lâu dài thay vì createStandalone().
$dompdf->loadHtml($html, $encoding)$doc->writeHtml($html)NextPDF coi đầu vào là UTF-8. Hãy chuyển mã đầu vào không phải UTF-8 trước khi gọi thay vì truyền một đối số mã hóa.
$dompdf->loadHtmlFile($file)$doc->writeHtml(file_get_contents($file))NextPDF không có biến thể tải tệp. Hãy tự đọc tệp để chính sách tài nguyên nằm trong mã của bạn.
$dompdf->setPaper($size, $orientation)ConfigpageSize (một value object PageSize)Xem bảng ánh xạ tùy chọn.
$dompdf->render()(ngầm định)NextPDF dàn trang trong lúc writeHtml(); không có giai đoạn kết xuất riêng. Hãy gỡ lệnh gọi render().
$dompdf->output()$doc->getPdfData()Trả về các byte PDF.
$dompdf->stream($name, $opts)$doc->output($name, OutputDestination::Download)NextPDF chọn đích đến bằng enum OutputDestination.
$dompdf->setBasePath($p) / setProtocol() / setBaseHost()(việc phân giải tài nguyên khác nhau)NextPDF phân giải tài nguyên tương đối dựa trên tập làm việc của tài liệu, không dựa trên bộ ba path/protocol; xem Các khác biệt về hành vi.
$dompdf->addInfo($label, $value)$doc->setTitle() / setAuthor() / metadata APICác cặp thông tin tự do của Dompdf được ánh xạ sang các bộ thiết lập metadata có kiểu (ISO 32000-2 §14 thông tin tài liệu, iso32000_2_sec14#x1.x5.p5).
$dompdf->setHttpContext($ctx)(không có tương đương)NextPDF không tải tài nguyên từ xa qua một stream context; xem Không hỗ trợ / không có tương đương trực tiếp.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// Dompdf:
// $dompdf = new Dompdf();
// $dompdf->loadHtml('<h1>Invoice</h1>');
// $dompdf->setPaper('A4', 'portrait');
// $dompdf->render();
// file_put_contents('out.pdf', $dompdf->output());
// NextPDF — the createStandalone() default page size is A4 portrait:
$doc = Document::createStandalone();
$doc->setTitle('Invoice');
$doc->addPage();
$doc->writeHtml('<h1>Invoice</h1>');
$doc->save(__DIR__ . '/out.pdf');
echo "Wrote out.pdf\n";

Mẫu này phản ánh examples/08-html-basic.php, phần mã chạy được đi kèm hướng dẫn này, với kích thước giấy và lề không mặc định được chỉ định rõ. Nó tương ứng với một lệnh gọi setPaper() của Dompdf cộng với một cấu hình lề Options.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\OutputDestination;
use NextPDF\Core\Config;
use NextPDF\Core\Document;
use NextPDF\ValueObjects\Margin;
use NextPDF\ValueObjects\PageSize;
// Equivalent of: $dompdf->setPaper('letter','portrait') + margin options.
// US Letter portrait = 612 x 792 pt.
// Margin constructor order is (top, right, bottom, left) — all 0.5in here.
$config = new Config(
pageSize: new PageSize(612.0, 792.0, 'Letter'),
margins: new Margin(36.0, 36.0, 36.0, 36.0), // top,right,bottom,left; 0.5in in points
);
$doc = Document::createStandalone($config);
$doc->setTitle('Quarterly Report');
$doc->setAuthor('Finance');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color:#1E3A8A;">Quarterly Report</h1>
<p>This report renders through the NextPDF Html pipeline. The CSS subset that
is <strong>Verified</strong> for production is the support-matrix authority,
not this page.</p>
<table border="1">
<tr><th>Region</th><th>Total</th></tr>
<tr><td>EMEA</td><td>1,204</td></tr>
</table>
HTML;
$doc->writeHtml($html);
// Equivalent of $dompdf->stream('report.pdf'):
$doc->output('report.pdf', OutputDestination::Download);

Trường hợp đặc biệt & điểm cần lưu ý

Phần tiêu đề “Trường hợp đặc biệt & điểm cần lưu ý”
  • Không kết xuất hai giai đoạn. Mã Dompdf kiểm tra trạng thái giữa render()output(), chẳng hạn như đọc số trang, không có điểm tương đương trong NextPDF tại đúng ranh giới đó. Thay vào đó, hãy truy vấn tài liệu sau khi writeHtml().
  • Mã hóa. NextPDF bỏ tham số $encoding của Dompdf. Hãy chuyển đầu vào sang UTF-8 trước khi gọi writeHtml(). Truyền các byte Latin-1 sẽ tạo ra mojibake, chứ không phải lỗi.
  • Để sót render(). Một lệnh gọi kiểu $dompdf->render() còn sót lại không có phương thức NextPDF tương ứng và sẽ thất bại với lỗi nghiêm trọng “undefined method”. Hãy xóa nó khi di chuyển; đừng tạo stub cho nó.
  • PHP nội dòng. enable_php của Dompdf thực thi <script type="text/php">. NextPDF không thực thi PHP trong tài liệu, theo thiết kế, vì đó là một bề mặt tấn công dạng injection. Hãy chuyển logic đó vào mã PHP của bạn trước khi writeHtml().
  • Phân giải tài nguyên tương đối. Dompdf phân giải <img src> dựa trên bộ ba path/protocol/host cơ sở. NextPDF phân giải dựa trên tập làm việc của tài liệu. Trong lúc di chuyển, hãy truyền đường dẫn tuyệt đối hoặc data URI đã phân giải sẵn để loại bỏ biến số đó.

writeHtml() dàn trang trong một lượt streaming duy nhất, như được mô tả trong bản ghi quyết định kiến trúc ADR-001. Không có đối tượng cây frame trung gian nào được giữ lại sau khi dàn trang, nên bộ nhớ đỉnh phụ thuộc vào kích thước tài liệu chứ không phải số nút DOM. Ngân sách hiệu năng cho ví dụ của hướng dẫn này là wall_ms: 2000, peak_mb: 128. Với tài liệu lớn, hãy chia HTML thành từng khối tại các ranh giới addPage() thay vì dựng một chuỗi nhiều megabyte.

  • Không tải từ xa qua stream context. NextPDF không hiện thực cơ chế tải từ xa setHttpContext() / enable_remote của Dompdf. Hãy phân giải và xác thực các tài nguyên từ xa trong ứng dụng của bạn, rồi truyền vào các byte hoặc data URI. Việc này loại bỏ bề mặt server-side request forgery (SSRF) mà enable_remote mang theo.
  • Không thực thi mã trong tài liệu. Việc không có một tương đương cho enable_php là một biện pháp gia cố bảo mật có chủ đích, không phải một khiếm khuyết.
  • Metadata tài liệu mà bạn đặt qua các bộ thiết lập có kiểu được ghi vào từ điển thông tin ISO 32000-2 §14 / Extensible Metadata Platform (XMP) (iso32000_2_sec14#x1.x5.p5). Đừng đặt thông tin bí mật ở đó.
Phát biểuĐặc tảĐiều khoảnreference_id
Nội dung trang là content-stream được vẽ trong mô hình opaque/transparent.ISO 32000-2§8
Kích thước giấy được ánh xạ vào hộp ranh giới của đối tượng trang.ISO 32000-2§7
Các phông chữ HTML được ghi dưới dạng chương trình phông embedded/subset.ISO 32000-2§9
Việc xử lý khoảng trắng / ngắt dòng tùy thuộc từng engine.CSS Text 3§6.5

NextPDF tạo nội dung ISO 32000-2. Nó không khẳng định rằng một tài liệu Dompdf đã di chuyển sẽ giống hệt về mặt hình ảnh. Hãy xem xét lại đầu ra mỗi khi bạn đổi trình kết xuất.

Không áp dụng. Core đã bao phủ lộ trình di chuyển HTML thành PDF này.


Chi tiết di chuyển (các phần bắt buộc R6)

Phần tiêu đề “Chi tiết di chuyển (các phần bắt buộc R6)”

Hãy dùng hướng dẫn này nếu nhóm của bạn chạy dompdf/dompdf để chuyển HTML thành PDF phía máy chủ và muốn dùng engine NextPDF. Nếu bạn chỉ gọi loadHtml / setPaper / render / output, thì ánh xạ động từ bao phủ toàn bộ bề mặt của bạn.

Trong phạm vi: các động từ facade Dompdf, các khóa Options, kỳ vọng về mức tương đương tính năng CSS, việc phân giải tài nguyên và metadata. Ngoài phạm vi: các đối tượng nội bộ FrameTree/Canvas/Stylesheet của Dompdf. NextPDF không có các thành phần công khai tương đương, nên đừng di chuyển mã chạm vào chúng; hãy thay bằng API công khai.

Bao phủ nghĩa là tương thích về hành vi, không phải một shim cắm-vào-là-chạy. NextPDF không có shim lớp Dompdf (khác với lộ trình TCPDF; xem /migration/tcpdf-compat/). Hãy viết lại từng điểm gọi bằng ánh xạ động từ. Các hàng đã Xác minh trong bảng hỗ trợ CSS chi phối hoàn toàn các kỳ vọng về tính năng CSS. Hướng dẫn này không nhắc lại trạng thái của từng thuộc tính.

Tùy chọn Dompdf (khóa / bộ thiết lập)NextPDFGhi chú
default_paper_size / setDefaultPaperSize() ; setPaper($size,...)Config->pageSize (VO PageSize)Các kích thước có tên trở thành các kích thước điểm tường minh. new PageSize(595.276, 841.890, 'A4') là mặc định của createStandalone().
default_paper_orientation / setDefaultPaperOrientation()hoán đổi PageSize width/heightNextPDF không có cờ hướng giấy. Một trang nằm ngang là một PageSize có chiều rộng > chiều cao.
dpi / setDpi()(không phải một nút chỉnh toàn cục)NextPDF làm việc theo điểm PDF (1/72 in). Việc định cỡ ảnh là theo từng ảnh, không phải một hệ số nhân dots per inch (DPI) toàn tài liệu. Hãy tính lại các kích thước pixel cố định thành điểm.
enable_remote / setIsRemoteEnabled()(không có tương đương — theo thiết kế)Hãy phân giải các tài nguyên từ xa trong mã của bạn; xem Lưu ý bảo mật.
enable_html5_parser / setIsHtml5ParserEnabled()(luôn phân tích cú pháp HTML)Không có công tắc; bộ phân tích cú pháp là một phần của pipeline.
enable_php / setIsPhpEnabled()(không có tương đương — theo thiết kế)PHP trong tài liệu không được hỗ trợ. Hãy chuyển logic ra khỏi template.
font_dir / setFontDir()Config->fontsDirectoryMột chuỗi thư mục phông chữ duy nhất.
chroot(phân giải trong ứng dụng)NextPDF không chấp nhận một tùy chọn giam hệ thống tệp. Hãy xác thực đường dẫn trước khi truyền các byte.
default_font / setDefaultFont()CSS font-family / phông chữ đã đăng kýHãy đặt mặc định trong bảng kiểu cơ sở hoặc trong việc đăng ký phông chữ của bạn, không phải bằng một tùy chọn toàn cục.
enable_font_subsetting / setIsFontSubsettingEnabled()(luôn tạo subset)NextPDF luôn tạo subset cho các phông chữ nhúng (ISO 32000-2 §9, iso32000_2_sec9#x1.x45.p7). Không có lựa chọn “tắt”; một luồng Dompdf có tắt cờ này không có tương đương và cũng không cần thiết.
  • Engine dàn trang. Dompdf và NextPDF dùng các hiện thực dàn trang CSS độc lập. Việc gộp khoảng trắng và ngắt dòng có quy định, nhưng vẫn phụ thuộc từng engine (CSS Text 3 §6.5, css_text_3#x1.x6.x5.p20). Hãy lường trước các khác biệt về ngắt dòng và phân trang trong văn bản dày đặc. Hãy thiết lập lại baseline cho các so sánh hình ảnh sau khi di chuyển.
  • Luồng kết xuất. Không có ranh giới hai giai đoạn render()/output() (xem Trường hợp đặc biệt).
  • Phân giải tài nguyên. Việc xử lý base-path/protocol/host khác với cách xử lý tập làm việc của tài liệu.
  • Mô hình DPI. Điểm PDF khác với hệ số nhân DPI của Dompdf.
  • Metadata. Các cặp addInfo() tự do khác với các bộ thiết lập có kiểu (ISO 32000-2 §14, iso32000_2_sec14#x1.x5.p5).

Đây là các khác biệt về hành vi đã được ghi nhận, không phải khiếm khuyết của bất kỳ engine nào.

Không hỗ trợ / không có tương đương trực tiếp

Phần tiêu đề “Không hỗ trợ / không có tương đương trực tiếp”
  • enable_php (PHP trong tài liệu) — vắng mặt có chủ đích.
  • setHttpContext() / enable_remote tải từ xa — vắng mặt có chủ đích.
  • Truy cập công khai vào FrameTree / Canvas / Stylesheet — không có thành phần công khai tương đương.
  • dpi như một hệ số nhân toàn tài liệu — không được mô hình hóa.

Mã phụ thuộc vào các khả năng này không thể “di chuyển” nguyên trạng. Hãy gỡ bỏ hoặc viết lại trong mã ứng dụng bằng các hàng ở trên.

  1. Thêm nextpdf/core bên cạnh dompdf/dompdf. Đừng gỡ Dompdf ngay.
  2. Chọn một tài liệu ít rủi ro. Viết lại điểm gọi của nó bằng ánh xạ động từ, và xóa lệnh gọi render().
  3. Tạo cả hai tệp PDF từ cùng một đầu vào và so sánh chúng bằng mắt. Hãy coi các khác biệt là điều dự kiến vì hai engine độc lập, rồi quyết định ngưỡng chấp nhận theo từng tài liệu.
  4. Chuyển đổi cách dùng tùy chọn bằng bảng ánh xạ tùy chọn; tính lại các kích thước suy ra từ DPI thành điểm.
  5. Phân giải sẵn các tài nguyên từ xa và tương đối thành đường dẫn tuyệt đối hoặc data URI để loại bỏ biến số phân giải.
  6. Lặp lại theo từng tài liệu, từ rủi ro thấp nhất đến cao nhất. Giữ cả hai engine được cài đặt cho đến khi điểm gọi cuối cùng được chuyển sang hẳn.
  7. Chỉ gỡ dompdf/dompdf khỏi composer.json sau khi hoàn tất lần chuyển cuối cùng.
  • Hãy lưu ảnh chụp đầu ra Dompdf của các tài liệu tiêu biểu trước khi thay đổi mã. Dùng đầu vào làm chuẩn, không dùng byte làm chuẩn, vì các byte sẽ khác nhau.
  • Với mỗi tài liệu đã di chuyển, hãy đưa đầu ra NextPDF qua bước kiểm tra chấp nhận của riêng bạn, chẳng hạn so sánh hình ảnh hoặc kiểm chứng trích xuất văn bản. Hành vi pipeline HTML của riêng NextPDF được bao phủ bởi examples/08-html-basic.php và bộ kiểm thử Html tests/ của core. Tiêu chí chấp nhận khi di chuyển tùy theo từng tài liệu, và bạn chịu trách nhiệm kiểm chứng nó.
  • Hãy thêm một bài kiểm thử hồi quy cho mỗi tài liệu đã di chuyển để phát hiện các thay đổi do một bản cập nhật engine trong tương lai gây ra.

Mọi phát biểu về hành vi của NextPDF trên trang này đều được hậu thuẫn bởi một bài kiểm thử, ví dụ chạy được, chữ ký nguồn hoặc bản ghi quyết định kiến trúc (ADR) trong kho, hoặc, với các thuộc tính định dạng PDF, bởi các điều khoản ISO 32000-2 / CSS được ghim bằng Retrieval-Augmented Generation (RAG) trong citations: của frontmatter và bảng Tuân thủ. Hành vi của Dompdf chỉ được khẳng định là “engine độc lập — hãy lường trước các khác biệt đã ghi nhận”. Trang này không khẳng định bất kỳ mức tương đương nào trừ khi một thành phần trong kho chứng minh điều đó.

Phát biểu về hành vi của NextPDFBằng chứng trong kho (đường dẫn)
createStandalone() mặc định dùng trang A4 dọc (595.276 × 841.890 pt).src/Core/Config.php (default PageSize(595.276, 841.890, 'A4')); tests/Unit/Core/DocumentCreateStandaloneAndConfigWithersEdgeCaseTest.php (createStandaloneWithNullConfigBuildsDocumentWithA4Defaults).
writeHtml() dàn trang trong một lượt streaming duy nhất; không giữ lại DOM sau khi dàn trang.docs/architecture/adr/ADR-001-stream-based-rendering-pipeline.md; src/Core/Concerns/HasTextOutput.php (writeHtml()).
writeHtml() tự động tạo trang đầu tiên khi chưa có trang nào.tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php (writeHtmlAutoCreatesFirstPageWhenNoPagesExist).
output() / save() / getPdfData() là các động từ xuất (không có hai giai đoạn render/output).src/Core/Concerns/HasOutput.php (output(), save(), getPdfData()); tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php.
Đích đầu ra là enum NextPDF\Contracts\OutputDestination (Inline/Download/File/String).src/Contracts/OutputDestination.php; tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php.
Các phông chữ HTML luôn được ghi dưới dạng chương trình embedded/subset.tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php (recordUsedCharactersAffectsFontSubsetting); ISO 32000-2 §9 (citations: của frontmatter).
Các bộ thiết lập metadata có kiểu (setTitle/setAuthor) thay thế cho addInfo() tự do.src/Core/Concerns/HasMetadata.php (setTitle(), setAuthor()); tests/Unit/Core/Concerns/DocumentInfoMetadataSetterBaselineTest.php.
Pipeline HTML đầu cuối (phần mã chạy được đứng sau hướng dẫn này).examples/08-html-basic.php; bộ kiểm thử tests/Unit/Html/ của core.
Việc xử lý khoảng trắng / ngắt dòng tùy thuộc từng engine (độ lệch dàn trang).CSS Text 3 §6.5 (citations: của frontmatter + Tuân thủ).

Vì cả hai gói vẫn được cài đặt cho đến lần chuyển sang cuối cùng, việc quay lui một điểm gọi chưa chuyển đổi nghĩa là hoàn nguyên điểm gọi đó về luồng Dompdf. Sau lần chuyển sang cuối cùng, việc quay lui nghĩa là khôi phục dompdf/dompdf và điểm gọi trước đó từ kiểm soát phiên bản. Không có việc di chuyển dữ liệu nào; chỉ có thay đổi mã.

Xem Hiệu năng. Mô hình một lượt nghĩa là việc di chuyển không gây thêm chi phí giữ lại cây frame. Thay đổi chi phí chính theo từng tài liệu là việc phân giải tài nguyên sớm từ bước 5, mà bạn có thể cache.

  • Để sót render(), gây ra lỗi nghiêm trọng phương thức không xác định.
  • Truyền các byte không phải UTF-8 sau khi bỏ $encoding, gây ra mojibake âm thầm.
  • Kỳ vọng đầu ra giống hệt từng byte hoặc từng pixel từ các engine độc lập. Hướng dẫn này không bao giờ khẳng định việc cắm-vào-là-chạy hay tương thích (không phải byte-identical).
  • Dựa vào các template enable_php, vốn phải được tái cấu trúc bỏ đi.
  • Coi bảng hỗ trợ CSS chỉ là tham khảo. Nó là nguồn chuẩn về tính năng đã Xác minh cho những gì cần lường trước.