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

Writer: bộ tuần tự hóa PDF 2.0 + xref

Module Writer tuần tự hóa tài liệu thành các byte Portable Document Format (PDF). Module này chọn chiến lược phiên bản, ghi đồ thị đối tượng, rồi phát ra cấu trúc tham chiếu chéo và trailer.

Terminal window
composer require nextpdf/core:^3

Hãy dùng PdfWriter làm điểm vào. Truyền một đối tượng giá trị DocumentData vào write(). Phương thức này trả về PDF hoàn chỉnh dưới dạng một chuỗi byte. Writer lắp ráp đồ thị đối tượng, gán số đối tượng, ghi nhận độ lệch byte, rồi ghi cấu trúc tham chiếu chéo sau cùng.

Trong mỗi lần gọi, writer dùng một chiến lược tuần tự hóa. Interface PdfSerializationStrategy định nghĩa bốn phương thức: writeHeader(), getCatalogVersion(), writeXrefAndTrailer(), và usesXrefStream(). Có ba chiến lược hiện thực hóa interface này. Pdf20StreamStrategy ghi header %PDF-2.0, đặt phiên bản catalog thành /2.0, và phát ra một luồng tham chiếu chéo. Pdf17TableStrategy ghi %PDF-1.7 và một bảng tham chiếu chéo cổ điển. Pdf14TableStrategy ghi %PDF-1.4 và một bảng tham chiếu chéo. PdfWriter chọn chiến lược bằng một match trên DocumentData::$outputProfile. Mặc định là Pdf20StreamStrategy.

Enum PdfOutputProfile chứa ba phiên bản đích: Pdf20, Pdf17, và Pdf14. Enum này cung cấp headerVersion(), catalogVersion(), allowsObjectStreams(), và usesXrefStream(). Chế độ tuân thủ lưu trữ sẽ ghi đè hồ sơ đã chọn trước khi chọn chiến lược. Pdf14FeatureGuard từ chối các tính năng PDF 2.0 khi hồ sơ là Pdf14.

Một luồng tham chiếu chéo ánh xạ mỗi số đối tượng tới độ lệch byte của đối tượng đó, như được định nghĩa trong ISO 32000-2 §7. Các bản cập nhật tăng dần thêm đối tượng mới vào cuối tệp, như được định nghĩa trong ISO 32000-2 §7.5.6. Writer escape mọi chuỗi literal qua đường dẫn chuẩn tắc PdfStringEscaper::escapeLiteral(), tuân theo bảng escape chuẩn mực trong ISO 32000-2 §7.3.4.2 (ADR-015).

Writer hỗ trợ đầu ra tất định. setDeterministicMode() cố định định danh đối tượng và thứ tự khóa từ điển. setReproducibleClock() cố định dấu thời gian của tài liệu. Khi cả hai điểm cố định đều được đặt, cùng một đầu vào sẽ tạo ra đầu ra giống nhau từng byte. Phương thức writeChunked() trả về một generator phát ra PDF theo từng khối có kích thước cố định. Streaming/StreamingPdfWriter ghi lần lượt từng trang vào một luồng do bên gọi cung cấp, dành cho các tài liệu vượt quá ngân sách bộ nhớ.

Linearizer ghi lại một PDF đã hoàn tất thành bố cục tuyến tính hóa. Nó đặt trang đầu tiên ở vị trí sớm để trình xem có thể hiển thị trang đó trước khi tải xuống toàn bộ tệp. shadowValidate() kiểm tra thao tác ghi lại mà không thay đổi đầu vào.

Cẩn trọng. PdfWriter.phpLinearizer.php có vai trò then chốt với độ lệch byte và đồ thị đối tượng (các vùng nguy hiểm trong manifest). Không thay đổi cách đánh số đối tượng hay phép tính độ lệch xref khi chưa có bộ kiểm thử golden của Writer.

LớpPhương thức chínhVai trò
PdfWriterwrite(DocumentData): string, writeChunked(DocumentData, int): Generator, setDeterministicMode(), setReproducibleClock(), setOutputColorProfile(), getLastXrefOffset(), getFileId()Bộ tuần tự hóa chính
PdfSerializationStrategy (interface)writeHeader(), getCatalogVersion(), writeXrefAndTrailer(), usesXrefStream()Hợp đồng chiến lược phiên bản
Pdf20StreamStrategywriteHeader()%PDF-2.0, getCatalogVersion()/2.0, usesXrefStream()trueChiến lược xref-stream PDF 2.0
Pdf17TableStrategywriteHeader()%PDF-1.7, bảng xrefChiến lược xref-table PDF 1.7
Pdf14TableStrategywriteHeader()%PDF-1.4, bảng xrefChiến lược xref-table PDF 1.4
PdfOutputProfile (enum)Pdf20, Pdf17, Pdf14; headerVersion(), catalogVersion(), allowsObjectStreams()Bộ chọn phiên bản đích
PdfXrefWritergenerateFileId(), finalizeTrailerAndXref()Hoàn tất File ID + trailer/xref
Linearizerlinearize(string): string, shadowValidate(string): arrayGhi lại để xem nhanh trên web
Streaming\StreamingPdfWriteropen(), newPage(), close()Writer streaming một lượt

Chạy composer docs:generate-api-php -- --module=Writer để tạo bảng PHPDoc đầy đủ.

Nguồn: examples/02-pdf-factory.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Writer\PdfWriter;
$writer = new PdfWriter();
$pdfBytes = $writer->write($documentData);
file_put_contents('out.pdf', $pdfBytes);

Hồ sơ mặc định là PDF 2.0. Đầu ra bắt đầu bằng %PDF-2.0 và kết thúc bằng một luồng tham chiếu chéo.

Ví dụ này cố định tính tất định và một đồng hồ cố định để có đầu ra giống nhau từng byte, rồi stream kết quả theo từng khối cố định.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use DateTimeImmutable;
use NextPDF\Writer\PdfWriter;
use NextPDF\Writer\ReproducibleClock;
$pinned = new DateTimeImmutable('2026-01-01T00:00:00Z');
$writer = new PdfWriter();
$writer->setDeterministicMode($pinned, 'nextpdf-fixed-file-id');
$writer->setReproducibleClock(new ReproducibleClock($pinned));
$out = fopen('php://output', 'wb');
foreach ($writer->writeChunked($documentData, chunkSize: 65536) as $chunk) {
fwrite($out, $chunk);
}
fclose($out);
  • Mỗi lần gọi write() chỉ chạy một chiến lược. Writer đặt lại chiến lược từ hồ sơ trong mỗi lần gọi. Một lần gọi trước đó không làm rò rỉ phiên bản của nó.
  • Chế độ tuân thủ lưu trữ ghi đè hồ sơ được yêu cầu. Bản dựng PDF/A-3 buộc dùng PDF 1.7. Bản dựng PDF/A-4 buộc dùng PDF 2.0.
  • Đầu ra giống nhau từng byte cần cả hai điểm cố định. Đặt chế độ tất định một đồng hồ tái lập được. Chỉ một điểm cố định là không đủ.
  • writeChunked() phát ra một generator. Hãy tiêu thụ nó hoàn toàn. Một lần đọc dang dở sẽ tạo ra một PDF bị cắt cụt và không hợp lệ.
  • Linearizer ghi lại các độ lệch tham chiếu chéo. Trong một pipeline không thể chấp nhận lỗi ghi lại, hãy chạy shadowValidate() trước.
  • Pdf14TableStrategyfinal readonly. Đường dẫn PDF 1.4 từ chối các tính năng PDF 2.0 thông qua Pdf14FeatureGuard; nó không hạ cấp chúng.

Việc tuần tự hóa tuyến tính theo số lượng đối tượng và tổng kích thước byte. Luồng tham chiếu chéo thêm một lượt duyệt qua bảng đối tượng. writeChunked() giữ tài liệu đã lắp ráp nhưng phát ra theo các lát có giới hạn, nên bộ nhớ đỉnh bằng kích thước tài liệu cộng thêm một khối. Streaming\StreamingPdfWriter không giữ toàn bộ tài liệu; hãy dùng nó cho các đầu vào lớn hơn ngân sách bộ nhớ. Ngân sách khối lượng công việc tham chiếu là 1500 ms thời gian thực và 64 MB đỉnh. Việc tuyến tính hóa thêm một lượt duyệt đầy đủ thứ hai và một lượt đo. Hãy dự trù ngân sách rõ ràng cho phần này.

Writer tuần tự hóa một đồ thị đối tượng đáng tin cậy trong bộ nhớ. Đầu vào của nó là ranh giới mối đe dọa chính. Mọi chuỗi literal đều đi qua PdfStringEscaper::escapeLiteral() chuẩn tắc (ADR-015), nên các byte điều khiển nhúng không thể thoát ra khỏi một token chuỗi. Mã hóa được nối qua PdfEncryptionWriter và mục trailer /Encrypt. Mã hóa khóa công khai bị từ chối bằng một ngoại lệ rõ ràng thay vì bị hạ cấp âm thầm. Chế độ tất định và đồng hồ tái lập được loại bỏ các kênh phụ về dấu thời gian và thứ tự khỏi đầu ra. Xem /modules/core/security/ để biết mô hình mối đe dọa của tài liệu và ranh giới tin cậy của mã hóa.

Writer tạo ra các cấu trúc tệp PDF 2.0: header %PDF-2.0, một phiên bản catalog /2.0, một luồng tham chiếu chéo, và việc escape chuỗi literal theo bảng escape của ISO 32000-2 §7.3.4.2. Đây là các sự thật về cách hiện thực. Bằng chứng nằm trong src/Writer/Pdf20StreamStrategy.php, src/Writer/PdfSerializationStrategy.php, và việc chọn chiến lược trong src/Writer/PdfWriter.php. Hành vi này được kiểm chứng bởi tests/Unit/Writer/ (192 bài kiểm thử, bao gồm các bộ Pdf20StreamStrategy, PdfXrefWriter, và Linearizer*) và đường cơ sở tests/Golden/PdfWriter/PdfWriterGoldenBaselineSmokeTest.

Đây không phải là tuyên bố tuân thủ PDF 2.0 đầy đủ. Tuân thủ ISO 32000-2 đầy đủ là thuộc tính của một tài liệu hoàn chỉnh được kiểm định bởi một oracle bên ngoài, không phải của riêng bộ tuần tự hóa. Tuân thủ đầu-cuối chỉ được khẳng định ở nơi có oracle xác nhận: tests/Integration/Accessibility/VeraPdfUa2GoldenTest kiểm định một fixture được tạo ra với veraPDF cho PDF/UA-2, và tests/Standards/Profile/PdfRConformanceTest bao phủ hồ sơ PDF/R. Bài kiểm thử golden veraPDF bỏ qua khi binary veraPDF vắng mặt trên runner, nên đây là một cổng oracle opt-in, không phải cổng vô điều kiện. Đặt VERAPDF_BINARY để chạy nó. Việc chọn hồ sơ lưu trữ (PDF/A-3 → PDF 1.7, PDF/A-4 → PDF 2.0) được quyết định bởi ADR-011 và chế độ tuân thủ, đồng thời được kiểm định bởi các bộ kiểm thử tuân thủ trong /modules/core/conformance/. Ngoài những hồ sơ được oracle hậu thuẫn đó, hãy nêu rằng Writer “tạo ra các cấu trúc PDF 2.0; việc tuân thủ được kiểm định bởi veraPDF cho hồ sơ PDF/UA-2” thay vì khẳng định tuân thủ không kèm điều kiện.