從舊式函式庫遷移:TCPDF、FPDF 及其同類
Spec: ISO 32000-2ISO 32000-2Spec: ISO 19005-4ISO 19005-4Spec: ETSI EN 319 142-1ETSI EN 319 142-1
如果你的 PDF 是由 TCPDF、FPDF、mPDF 或 dompdf 產生的,那些程式碼大概還能用。這正是麻煩之所以容易被忽略的原因。函式庫照常執行,檔案照常打開,而那道落差只會在某天有人要一份已簽署、可封存或無障礙的文件、而答案是「我們從這裡做不出來」時,才會浮現。
本頁是那則遷移故事:那些牆是什麼、為什麼它們是結構性的而非偶發性的,以及 NextPDF 如何給你一條分階段、避開它們的路徑——包括一個 TCPDF 相容層,它是一項遷移輔助,而非一個位元組逐一相同、可直接替換的承諾。
為什麼這很重要
標題為「為什麼這很重要」的區段一個 PDF 函式庫不是你呼叫一次的算繪呼叫。它是你的文件只要還存在、就會一直繼承下去的相依套件。當那個相依套件停止前進時,你的文件就無法再做新的事情——而你會在最糟糕的時刻發現這件事,也就是某個客戶、某位稽核員或某個監理機關把門檻設下來的那一刻。
那些牆長這個樣子。格式向前走了:PDF 2.0 是這項標準的現行版本(Spec: ISO 32000-2ISO 32000-2),而一個卡在 1.x 結構上的寫入器,已落後於你工具鏈其餘部分所預設的格式。簽署能力薄弱或是事後硬接上去的,遠遠搆不上那些讓簽章站得住腳的 PAdES 基準設定檔(Spec: ETSI EN 319 142-1, §4ETSI EN 319 142-1 §4)。輸出至 PDF/A 系列的封存格式,以及為無障礙而設的標記結構,不是缺席就是脆弱。而 API 本身缺乏型別——字串式的方向、位置式的布林值、靠意外才發現的預設值——所以編譯器幫不了你,審查者也幫不了你。
這些都不是你能繞過去修補的臭蟲。它們是一個為更早年代而打造的工具所具有的形狀,而其中好幾個工具,如今已不再積極地朝你文件現在必須符合的那些標準前進。
簡短版本
標題為「簡短版本」的區段- 舊式 PHP PDF 函式庫多半仍能執行。問題在於它們通常無法以完整的現代一致性產出什麼:PDF 2.0、符合基準的簽章、經驗證的 PDF/A、已標記的無障礙結構——這些在那幾個指名的函式庫之間,支援程度有限或付之闕如。
- NextPDF 是一個預設寫入 PDF 2.0 的 PHP 8.4 引擎,並把嚴格型別、封存設定檔,以及 PAdES 簽署作為第一級的輸出。
- 你不必在第一天就把一切重寫。TCPDF 相容層讓熟悉的呼叫繼續運作,而你同時去搬動那些真正重要的文件邏輯。
- 那一層與 TCPDF 相容,但並非位元組逐一相同。它是一座跨越遷移過程的橋,附帶已載明的行為差異——而非主張每個指令稿都能原封不動地執行。
- 誠實的檢驗是:那些新能力是否值得這趟搬遷。對某些工作負載而言並不值得,而我們會直白地這麼說。
NextPDF 的處理方式
標題為「NextPDF 的處理方式」的區段這套做法是把遷移變成一個序列,而非一次飛躍。你一路上都持續產出文件,並且一次只換掉一項舊有的限制,而不是把一次發行押注在一場一次到位的大改寫上。
- InventoryCatalogue what your documents actually need to emit — signatures, archival profiles, tagged structure, fonts — not just which calls you make today.
- BridgeAdopt the TCPDF-compatibility surface so the existing call sites keep producing files while the engine underneath becomes NextPDF.
- PortMove the document logic that matters onto the native typed API, where intent is explicit and the compiler checks it.
- UpgradeTurn on the outputs many legacy libraries cannot reach with full modern conformance: PDF 2.0 structure, validated PDF/A, PAdES signatures, tagged accessibility.
- VerifyConfirm the result against a real validator, so 'archival' or 'signed' means a tool agrees, not just that the file opened.
PDF 2.0 是基準,不是一個功能旗標。 NextPDF 預設寫入這個格式的現行版本(Spec: ISO 32000-2ISO 32000-2),並能在某個設定檔有此要求時序列化較舊的結構。一個凍結在 1.x 結構上的函式庫無法在這裡與你會合;那不是它漏掉的一項設定,而是一個它早於其問世的年代。
封存與無障礙是寫入器的性質。 產出一個驗證器會接受為 PDF/A 的檔案,是引擎在寫入過程中就必須做到的事——它無法在事後被硬釘上去(Spec: ISO 19005-4ISO 19005-4)。讓 PDF 變得無障礙的那套標記結構也是如此。NextPDF 在產生過程中就建構這些,而那恰恰是許多舊式工具無法踏出的那一步——或者只能部分做到,搆不上驗證器所接受的程度。
簽署搆得上基準的門檻。 PDF 中的進階電子簽章遵循 PAdES 設定檔(Spec: ETSI EN 319 142-1, §4ETSI EN 319 142-1 §4),其中摘要涵蓋一段所宣告的位元組範圍,而簽章攜帶了驗證器會檢查的中繼資料。一個硬接上去的簽署輔助工具鮮少搆得上那道門檻。NextPDF 把它當成一項第一級的輸出,而非事後才想到的東西。
相容層就是那座橋,而且被誠實地陳述。 TCPDF 相容層之所以存在,是為了讓你既有的呼叫處在你遷移那些重要部分的同時,繼續產出文件。它遵循與每一份 NextPDF 遷移指南相同的模型:與來源函式庫相容、但並非位元組逐一相同,並把行為差異寫下來。那份誠實正是重點所在——一句無聲的「99% 可直接替換」宣稱,正是這個引擎天生就要拒絕的那種猜測。
實際範例
標題為「實際範例」的區段在呼叫處上,一次遷移的形狀很小。舊程式碼透過相容層繼續產出一個檔案;新程式碼透過具型別的原生 API 陳述意圖,並要求一個舊式函式庫搆不上、或只能以有限一致性搆上的輸出。
<?php
declare(strict_types=1);
use NextPDF\Compat\Tcpdf\TCPDF;use NextPDF\Contracts\Orientation;use NextPDF\Contracts\OutputDestination;use NextPDF\Core\Document;use NextPDF\ValueObjects\PageSize;
// 1) The bridge: a familiar TCPDF-shaped call keeps producing a file// while the engine underneath is already NextPDF. Behaviour is// compatible, not byte-identical — differences are documented.$legacy = new TCPDF();$legacy->AddPage();$legacy->SetFont('helvetica', 'B', 16);$legacy->Cell(0, 12, 'Migrated invoice', ln: 1);$bridgedBytes = $legacy->Output('', 'S');
// 2) The destination: the same document expressed natively, where intent// is typed and the engine can emit what many legacy tools cannot.$document = Document::createStandalone();$document->setTitle('Migrated invoice');$document->addPage(PageSize::a4(), Orientation::Portrait);$document->setFont('helvetica', 'B', 16);$document->cell(0, 12, 'Migrated invoice', newLine: true);
// Bytes only, no HTTP headers, no file side effect — stated, not inferred.$nativeBytes = $document->output(dest: OutputDestination::String);第一個區塊是那個立足點:你的應用程式裡沒有任何東西需要改變,文件就能持續流動。第二個是目的地:一個具型別的呼叫,其中「直向」、「字串輸出」與字型都是明確的,而封存、簽署與無障礙都成為你可以切換開啟的輸出,而非你會撞上的牆。
常見的誤解
標題為「常見的誤解」的區段人們常抱的期望是「一定有個旗標,能讓我的舊函式庫做出 PDF 2.0 與簽章。」並沒有。這些不是一個成熟函式庫忘了暴露的選項;它們是它的架構從一開始就不曾圍繞著去建構的能力。你無法靠設定,就搆到一個寫入器並未實作的格式版本或簽章設定檔。
與之相對的誤解是,NextPDF 是一個 100% 的 TCPDF 直接替換品,所以遷移是免費的。並不是,而我們不會假裝是這樣。相容層涵蓋了 API 中一個真實、已載明的切片,好載你跨過這趟搬遷;有些呼叫的行為不同,而少數幾個不在範圍內。把它當成一座附有公開地圖的橋,而不是每個舊式指令稿都能原封不動執行的保證。
限制與邊界
標題為「限制與邊界」的區段| Edition | Availability |
|---|---|
| Core | 相容層與 TCPDF 相容,但並非位元組逐一相同。它涵蓋了 API 中一個已載明的子集,好讓既有的呼叫處在遷移過程中持續產出檔案。它是一座橋,而非可直接替換品:有些行為不同,有些呼叫不受支援,而這些全都列在方法涵蓋與遷移頁面中。目的地是具型別的原生 API,而符合標準等級的輸出就住在那裡。 |
| Pro | Available |
| Enterprise | Available |
遷移是一種手段,而非一種美德。如果你的文件很單純、你的函式庫仍有維護、而你永遠不會需要 PDF 2.0、簽署、PDF/A 或無障礙,那麼誠實的答案也許是留在原地——切換成本是真實的,而一趟你不需要的搬遷是一趟你不該動的搬遷。何時不該使用 NextPDF那一頁毫不退縮地畫出那條界線。
本頁說明的是遷移路徑與引擎的目標。確切的 API 涵蓋範圍、行為差異,以及一步步的程序,都住在相容性文件裡,而那份文件才是每個呼叫做什麼的權威。此處沒有任何東西承諾一個任意的舊式指令稿能原封不動執行。
相關文件
標題為「相關文件」的區段- What PDF 2.0 changed——許多舊式函式庫無法發出的那個格式版本,以及它為何重要。
- The TCPDF compatibility surface——關於這座橋涵蓋了什麼、又在哪裡有所不同的權威指南。
- When not to use NextPDF——那條誠實的邊界,好讓一趟你不需要的遷移成為一趟你可以略過的遷移。
- One engine, every framework——你遷移過去的那個引擎,會接進你早已運行的那套技術堆疊的哪個位置。
詞彙表
標題為「詞彙表」的區段- PDF 2.0——可攜式文件格式標準的現行版本(ISO 32000-2)。於首次出現時展開;NextPDF 預設寫入的格式。
- PDF/A——封存一致性系列(ISO 19005 系列),它定義了什麼讓一個 PDF 能安全地長期保存。這是寫入器必須產出的性質,而非呼叫端事後能加上的東西。
- PAdES——PDF Advanced Electronic Signatures(PDF 進階電子簽章),用於在 PDF 中內嵌符合標準等級簽章的 ETSI 設定檔系列(EN 319 142)。於首次出現時展開;在簽署相關頁面中有深入涵蓋。
- 相容層——一個形狀仿照來源函式庫(此處為 TCPDF)的 API 層,讓既有的呼叫處在遷移過程中持續運作。與原版相容、但並非位元組逐一相同——是一座橋,而非可直接替換品。
- 直接替換品——一個能讓既有程式碼原封不動執行的替代物。TCPDF 相容層刻意不以這種方式來描述;它是一項帶有已知行為差異、已載明的遷移輔助。