跳到內容
getnextpdf.com

團隊為何選擇 NextPDF

Spec: ISO 32000-2Spec: ETSI EN 319 142-1

選擇一套 PDF 引擎是個小決定,卻悄悄地替後續許多決定定下了走向。本頁是支持 NextPDF 的論述,並以一個團隊真正會做的決定為框架:留在 PHP 裡還是另跑一個旁掛服務、擁有自己的程式碼還是租用一個黑盒子、產出真正的簽章還是一個打勾、交付一個能撐過生產環境的原型還是一個非得重寫才能上線的原型。

你產生的那份 PDF,往往不是故事的結局。它會被簽署、被封存、被寄給某個監理機關,或在數年後被某個在你寫程式時根本不在場的人打開。這讓 PDF 引擎成為一項基礎設施選擇,而不是一次工具呼叫。選錯了,日後會以各種形式浮現:一個被驗證器拒絕的簽章、一份檢核工具判定失敗的封存檔,或一張你離不開的廠商帳單——因為你的文件只能透過他們的服務算繪出來。

一個團隊通常沒有機會重新爭論這個決定。他們在第一週選定的引擎,就是第三年仍處於關鍵路徑上的引擎。所以真正值得誠實回答的問題,不是「它能不能做出一份 PDF」——幾乎任何東西都做得到——而是「當這份文件成為一項法律或封存產物時,它撐不撐得住」。

團隊選擇 NextPDF,是因為它一次消除了四項各自獨立的風險:

  • 它是 PHP 原生的。 一套在你的行程內執行的 PDF 2.0 引擎,而不是一個你得在應用程式旁另行維運、擴展、並加以防護的獨立執行環境。
  • 它預設開放。 核心採用 Apache-2.0——可閱讀、可分叉、可內嵌。進階版本增添能力;它們絕不會挾持你的文件。
  • 它的簽署達到標準等級。 PAdES 基準設定檔(Spec: ETSI EN 319 142-1, §6),而不是一套歐洲驗證器從沒見過的自製簽署機制。
  • 它以同一套程式碼擴展。 你在第一天寫下的原型,就是生產環境的程式碼路徑。沒有「現在把它移植到真正的引擎」這一步。

這四項主張各自對應到一項具體屬性,而且每一項都是審查者能親自查證、而非只能信其有的東西。

PHP 原生意味著不需要第二個執行環境。 NextPDF 以格式的版本權威(Spec: ISO 32000-2, §6)所定義的 PDF 2.0 為目標,而且就在你的 PHP 行程內完成這件事。不需要保活一個無頭瀏覽器、不需要部署一個微服務、也不需要跨越語言邊界做封送。對一個技術堆疊已經是 PHP 的團隊來說,維運面的範圍維持得和原本一樣大。當瀏覽器等級的算繪器確實是正確工具時,NextPDF 可以驅動它一個——但那是你做出的選擇,而不是你繼承來的相依。這項取捨正是整合決策指南的主題。

預設開放意味著沒有鎖定。 核心引擎採用 Apache-2.0。你可以閱讀每一行碰觸你位元組的程式碼、把它內嵌進一個私有鏡像、若某次發行走向了你無法跟隨的方向就將它分叉,並繼續交付。核心產出的文件是一份標準 PDF,任何符合規範的閱讀器都能打開——它不是一個只能透過某家廠商服務來回轉換的專有容器。商業版本是加法式的:它們解鎖諸如硬體背書簽署與大量功能之類的能力,但它們產出的文件仍是普通、符合標準、完全由你擁有的 PDF。

標準等級簽署意味著一個能撐過審查的簽章。 這正是一套「夠用就好」的 PDF 函式庫悄悄變成負債之處。一個驗證器不認得的簽章,就其本該達成的目的而言,根本不是簽章。NextPDF 以 ETSI 所定義的 PAdES 基準遞進——B-B、B-T、B-LT、B-LTA——為目標,這些正是歐洲驗證器與稽核員預期會看到的層級。這道邊界是分層的:Apache-2.0 核心提供一個軟體 CMS/PAdES 簽署器,使用本機或外部提供的金鑰,支援 B-B 與 B-T 層級,而長期驗證層級(B-LT、B-LTA)以及 HSM 或雲端 KMS 背書的金鑰,則屬於進階版本的能力。PAdES 是 PDF 的 ETSI 簽章設定檔;eIDAS——這項歐盟法規(Spec: Regulation (EU) No 910/2014 (eIDAS), Art. 25)——則是賦予電子簽章法律效力的依據,而 PAdES 正是一項 eIDAS 義務所對應到的 PDF 實現,這也正是引擎之所以瞄準整個設定檔系列、而非一個近似品的原因。PAdES 基準設定檔一頁會走過這段遞進,並說明如何挑選你的義務實際所需的層級。

  1. Stay in your stackA PHP-native PDF 2.0 engine runs in-process — no second runtime to deploy, scale, or secure.
  2. Own what you shipApache-2.0 core: readable, forkable, vendorable. The documents are standard PDFs you keep, not a proprietary container.
  3. Sign for realPAdES baseline profiles (ETSI EN 319 142-1), the levels a validator and an auditor recognise — not a homegrown scheme.
  4. Grow without a rewriteThe prototype is the production path. Fail-fast typed inputs catch mistakes in development, where they are cheap.
團隊在採用一套 PDF 引擎時所面對的決定,以及化解每一步的 NextPDF 屬性:維持原生而非維運一個旁掛服務;以 Apache-2.0 擁有程式碼而非租用一個黑盒子;產出一個被認可的 PAdES 設定檔而非一個量身打造的簽章;並從原型到生產維持同一條程式碼路徑。

從原型到生產意味著不必重寫。 第四項風險最為安靜:一個展示時美輪美奐、上線前卻得被替換掉的工具。NextPDF 的設計,讓你寫下的第一支程式,就是你維運的那同一支程式。輸入會被嚴格賦予型別、並在邊界處驗證,所以你在生產環境會看見的失效模式,正是你在開發階段就已看過的那些——在呼叫點被具名指出,早在任何一個位元組被寫下之前。這個立場正是設計哲學一套拒絕臆測的 API的主題;在這裡它之所以重要,是因為它正是讓同一條程式碼路徑得以帶著一個團隊,從週末的衝刺一路走到受監理工作負載的關鍵。

「以同一套程式碼從原型走到生產」的樣貌,在呼叫點看得最清楚。一個團隊為了評估引擎而寫的程式,逐行逐句,就是在生產環境執行的那支程式——只有簽署材料會改變。

<?php
declare(strict_types=1);
use NextPDF\Contracts\Orientation;
use NextPDF\Contracts\OutputDestination;
use NextPDF\Core\Document;
use NextPDF\Signature\SignatureLevel;
use NextPDF\ValueObjects\PageSize;
$document = Document::createStandalone();
$document->setTitle('Service Agreement');
// Typed page geometry and an enum orientation — intent is explicit,
// so a typo is a type error in development, not a silent default in production.
$document->addPage(PageSize::a4(), Orientation::Portrait);
$document->setFont('helvetica', 'B', 16);
$document->cell(0, 12, 'Service Agreement', newLine: true);
// The signature level is a recognised PAdES baseline profile, named as an
// enum case — never a string the engine has to interpret. B-T is a core
// software-signing level; the long-term levels (B-LT, B-LTA) are an
// advanced-edition capability selected the same way.
$document->setSignature(certInfo: $certInfo, level: SignatureLevel::PAdES_B_T);
// The output destination is stated, not inferred from whether a filename
// was passed. The same call shape serves a spike and a production endpoint.
$bytes = $document->output(dest: OutputDestination::String);

這支程式裡,沒有任何東西會在原型與部署之間改變。團隊用真實的簽署材料換掉佔位符,並把輸出指向一個回應而非一個緩衝區。引擎、API 與失效模式在兩處完全相同——這正是全部的重點。

最常見的反對意見是「開放原始碼的核心意味著真正的產品被付費牆擋住,所以免費的部分只是個誘餌」。這把關係看反了。核心是一套採用 Apache-2.0 的生產級 PDF 2.0 引擎——文件產生、符合標準的輸出,以及 B-B 與 B-T 層級的軟體 CMS/PAdES 簽署;團隊會原封不動地在生產環境執行它。進階版本則為需要它們的團隊增添特化能力——長期驗證簽署(B-LT、B-LTA)、HSM 與雲端 KMS 背書的金鑰、規模化功能。檢驗方式既簡單又可查證:核心產出的文件是一份標準 PDF,能在任何符合規範的閱讀器中打開,回讀時不相依於任何 NextPDF 服務。沒有任何人質可供贖回。

第二個誤解是「PHP 原生」意味著「比瀏覽器引擎能力更弱」。它意味著不同,而那些瀏覽器等級的算繪器確實是更佳選擇的誠實情境,都被整理在何時不該使用 NextPDF裡——而不是被埋藏起來。

本頁是一篇支持採用的論述,而不是一項普遍適用的主張。NextPDF 是在 PHP 堆疊中進行程式化、標準等級文件產生的正確工具。它不是一個逐像素重現網頁瀏覽器的再實作,也不是每一個文件問題的答案;這道邊界在何時不該使用 NextPDF裡有明白的陳述。

Hardware-backed (HSM) signing — edition availability
EditionAvailability
CoreNot in this edition — software signing only (B-B, B-T).
ProAvailable — HSM and qualified-device signing.
EnterpriseAvailable — HSM and qualified-device signing.

有兩道邊界值得強調。第一,簽署能力是分層的:Apache-2.0 核心使用本機或外部提供的金鑰,提供 B-B 與 B-T 層級的軟體 CMS/PAdES 簽署,而長期驗證層級(B-LT、B-LTA)以及透過 HSM、合格裝置或雲端 KMS 取得的硬體背書金鑰,則屬於進階版本的能力。第二——而這是每一項符合性主張上都成立的誠實限制——符合性是由獨立的檢核工具判定的,絕不由產生者判定。PAdES 是 PDF 的 ETSI 簽章設定檔;PDF/A-4(Spec: ISO 19005-4, §6),由 ISO 19005-4 所定義,則是一個獨立的封存符合性層級。NextPDF 兩者皆可瞄準,但瞄準一個設定檔並不等於保證符合:權威裁定來自一個 PDF/A 驗證器或一個簽章驗證器,而非寫出這份檔案的引擎。把引擎當成讓你抵達「應該會通過」的工具,把檢核工具當成判定「確實通過」的工具。

  • PDF 2.0——PDF 格式的當前版本,規範於 ISO 32000-2。NextPDF 以它作為版本權威為目標,因此它的輸出是以當前的 ISO 標準、而非某個廠商方言來衡量。
  • PAdES——PDF Advanced Electronic Signatures,用於簽署 PDF 的 ETSI 設定檔系列(EN 319 142-1)。它的基準層級——B-B、B-T、B-LT、B-LTA——正是歐洲驗證器與稽核員預期會看到的。
  • eIDAS——Regulation (EU) No 910/2014,賦予電子與合格簽章法律效力的歐盟框架;PAdES 是一項 eIDAS 義務所對應到的 PDF 實現。
  • PDF/A——封存符合性系列(此處為 ISO 19005-4 下的 PDF/A-4),用於那些必須長期維持自我完備且可讀的文件。
  • Apache-2.0——NextPDF 核心的寬鬆開放原始碼授權:你可以使用、修改、內嵌並再散布這套引擎,且沒有開放你自己應用程式的義務。
  • 無鎖定(No lock-in)——一項屬性,意指一套引擎產出的文件是標準、廠商中立、完全由你擁有的產物,無須相依於產生者的服務即可閱讀。