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

Vận hành compat-legacy trong môi trường sản xuất

Adapter này an toàn khi chạy trong các trình xử lý Hypertext Transfer Protocol (HTTP), worker hàng đợi và tiến trình chạy lâu dài. Nó an toàn hơn TCPDF 6.2.13 đời cũ vì loại bỏ hai nguy cơ thường gặp nhất trong môi trường sản xuất: ghi đầu ra trực tiếp vào bộ đệm và gọi die() khi có lỗi. Hãy dùng trang này để vận hành adapter đúng cách.

Trước khi đưa vào sản xuất, hãy hoàn tất kiểm toán chế độ nghiêm ngặt trong /integrations/tcpdf-compat/migration/ rồi triển khai với chế độ nghiêm ngặt tắt.

Xử lý đầu ra trong worker và trình xử lý

Phần tiêu đề “Xử lý đầu ra trong worker và trình xử lý”

Hàm Output() của TCPDF đời cũ ghi trực tiếp vào bộ đệm đầu ra đang hoạt động. Điều này có thể làm hỏng phản hồi trong các framework HTTP và khiến worker hàng đợi bị lỗi. Thay vào đó, adapter định tuyến đầu ra qua một cầu nối đích an toàn.

Hãy chọn đích phù hợp với bên gọi:

Bối cảnhĐích đếnLý do
Worker hàng đợi ghi vào bộ lưu trữOutput($path, 'F')Ghi tệp và trả về chuỗi rỗng. Nó không tương tác với bộ đệm.
Tạo rồi attach/uploadOutput($name, 'S')Trả về các byte Portable Document Format (PDF); bạn kiểm soát nơi chuyển các byte đó đến.
Tệp đính kèm emailOutput($name, 'E')Trả về một phần thân Multipurpose Internet Mail Extensions (MIME) dạng base64 với Content-Type: application/pdf.
Phản hồi HTTP do bạn kiểm soátOutput($name, 'S')Lấy các byte, rồi bạn tự đặt header và phần thân của riêng mình.
examples/production-worker.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;
use NextPDF\Compat\Tcpdf\TCPDF;
/**
* Render an invoice in a queue worker. Returns the storage path.
*
* @throws \RuntimeException on a render failure (Error() throws, not die()).
*/
function renderInvoiceJob(array $invoice, string $storageDir): string
{
$pdf = new TCPDF('P', 'mm', 'A4');
$pdf->SetFont('helvetica', '', 12);
$pdf->AddPage();
$pdf->Cell(0, 10, 'Invoice ' . $invoice['number'], 0, 1);
$path = $storageDir . '/invoice-' . $invoice['number'] . '.pdf';
try {
$pdf->Output($path, 'F'); // writes file, no buffer pollution
} catch (TcpdfNotImplementedException $e) {
// Only reachable if strict mode is on — it must NOT be in production.
throw new \RuntimeException('Adapter strict-mode gap in production: ' . $e->getMessage(), 0, $e);
} catch (\RuntimeException $e) {
// Error() throws RuntimeException instead of die().
throw new \RuntimeException('PDF render failed: ' . $e->getMessage(), 0, $e);
}
return $path;
}

Trong một trình xử lý HTTP, hãy ưu tiên 'S' và tự đặt header:

examples/production-http.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Report');
$bytes = $pdf->Output('report.pdf', 'S');
header('Content-Type: application/pdf');
header('Content-Length: ' . strlen($bytes));
header('Content-Disposition: inline; filename="report.pdf"');
echo $bytes;

Error() ném ra RuntimeException; nó không bao giờ gọi die(). Đây là thay đổi vận hành quan trọng nhất so với TCPDF đời cũ.

  • Hãy bọc mọi điểm vào của quá trình kết xuất trong try/catch.
  • Hãy ánh xạ ngoại lệ sang hợp đồng lỗi của ứng dụng, chẳng hạn như HTTP 5xx, job thất bại, thử lại, hoặc dead-letter.
  • Đừng cho rằng tiến trình kết thúc khi kết xuất thất bại; nó không kết thúc.

Một TcpdfNotImplementedException trong job continuous integration (CI) chạy định kỳ ở chế độ nghiêm ngặt (khuyến nghị) là một phát hiện thực sự. Điều đó có nghĩa là một nhánh mã đang dựa vào một tham số TCPDF không được hỗ trợ. Hãy xem đây là một hạng mục di chuyển cần xử lý, không phải một bài kiểm thử chập chờn.

  • Tài liệu dựng các byte PDF của nó theo cách trì hoãn (lazy) trong lần gọi đầu ra đầu tiên. Close() là tùy chọn; khi được gọi, nó sẽ lưu các byte vào bộ đệm. Open() là một thao tác rỗng (no-op) an toàn.
  • endPage() không làm gì vì NextPDF quản lý vòng đời trang. Hãy loại bỏ nó khỏi các vòng lặp nóng; nó không mang lại giá trị.
  • Hãy để PHP thu gom rác adapter giữa các job. _destroy() đặt lại dữ liệu đã lưu vào bộ đệm của adapter, nhưng bạn không cần gọi nó tường minh trong các vòng lặp worker thông thường.
  • Hãy tạo adapter mới cho mỗi tài liệu. Đừng tái sử dụng một thực thể adapter cho các tài liệu không liên quan trong một worker chạy lâu dài; trạng thái tài liệu là riêng cho từng thực thể.
  • Adapter là một lớp ủy quyền mỏng; engine mới là phần chiếm phần lớn chi phí, chứ không phải adapter.
  • Hãy định nghĩa các hằng số đời cũ một lần lúc khởi động. LegacyDefaults::register()LegacyBootstrap::enableAliases() có tính idempotent và được bảo vệ, nên các lần gọi lặp lại có chi phí thấp. Định nghĩa hằng số cho từng yêu cầu là lãng phí.
  • Hãy ưu tiên Output(..., 'S') hoặc 'F' thay vì 'I'/'D' trong các bối cảnh không phải trình duyệt. Các đường dẫn inline/download tạo ra đầu ra độc lập với framework mà bạn thường không muốn có trong worker.
  • Với quy trình tạo tài liệu khối lượng lớn, hãy phân tích hiệu năng (profile) engine, không phải adapter. Ngân sách trên mỗi trang cho phần chi phí phụ trội riêng của adapter là nhỏ so với chi phí kết xuất.
  • Mỗi thực thể adapter độc lập và giữ trạng thái tài liệu của riêng nó. Tính đồng thời ở cấp tiến trình hoặc worker là an toàn khi mỗi đơn vị công việc dùng thực thể adapter riêng.
  • Các cơ chế bảo vệ tính idempotent trong LegacyBootstrapLegacyDefaults dùng trạng thái static cục bộ trong tiến trình; chúng an toàn trong các mô hình PHP per-request/per-worker thông thường. Chúng không được thiết kế để chia sẻ trạng thái có thể thay đổi giữa các luồng.

Danh sách kiểm tra trước khi đưa vào sản xuất

Phần tiêu đề “Danh sách kiểm tra trước khi đưa vào sản xuất”
  • Đã hoàn tất kiểm toán chế độ nghiêm ngặt; môi trường sản xuất chạy với chế độ nghiêm ngặt đã tắt.
  • Tất cả điểm vào của quá trình kết xuất đều được bọc trong try/catch cho RuntimeException (không dựa vào die()).
  • Các worker dùng Output(..., 'F') hoặc 'S', không bao giờ dùng đường dẫn inline.
  • Các hằng số đời cũ được định nghĩa một lần lúc khởi động, trước lần khởi tạo đầu tiên.
  • Đã có một job CI chạy ở chế độ nghiêm ngặt theo định kỳ để phát hiện hồi quy.
  • Các khẳng định kiểm thử ở cấp byte được tái thiết lập baseline (xem /integrations/tcpdf-compat/migration/).
  • /integrations/tcpdf-compat/security-and-operations/ — mã hóa, định hướng ký và gia cố bảo mật
  • /integrations/tcpdf-compat/troubleshooting/ — các mẫu lỗi trong sản xuất và cách khắc phục
  • /integrations/tcpdf-compat/configuration/ — chế độ nghiêm ngặt và vệ sinh hằng số
  • /integrations/tcpdf-compat/migration/ — cuộc kiểm toán phải tiến hành trước khi đưa vào sản xuất