Pro 版本
差異比對
NextPDF\Pro\Diff 會比對兩份 PDF 文件並回報變更內容。快速路徑會產生一份逐頁對齊的文字差異;結構化路徑則加入影像與中繼資料變更偵測,並將結果格式化為 JSON 或 HTML。
供應與授權
標題為「供應與授權」的區段此功能隨 NextPDF Pro(nextpdf/pro)出貨,並透過 Pro 層級的授權封套啟用。沒有該授權的部署不會載入此功能的類別。比較各版本並取得授權。
沒有任何執行階段能力旗標會閘控 Diff 類別;只要安裝了 Pro 套件,它們就存在。
composer require nextpdf/pro:^3概念總覽
標題為「概念總覽」的區段PdfDiffer::compare() 會從每份文件逐頁抽取文字、切分成行,並針對每一對頁面執行 Myers 行差異比對,產生新增、移除與修改的區域。文字抽取會剖析 ISO 32000-2:2020 §9.4 的文字顯示運算子(Tj、TJ、')。
StructuredDiffer 在其之上進一步建構:它會將文字區域歸組為段落層級的變更、比對嵌入影像、比對中繼資料,並產生一個帶有彙總摘要的 StructuredDiffResult。DiffFormatter 會將該結果序列化為一個 JSON 字串或一段 HTML 報告片段。
當安裝了選用的 Artisan PDF 讀取器時,文字抽取會使用它來取得逐頁精確的內容;否則會以有界限的位元組層級回退機制直接掃描內容流。
為何如此設計
標題為「為何如此設計」的區段差異比對器比對的是抽取出的文字與結構,而非繪製出的像素。結構化比對具有決定性、成本低廉,並能對應到審查者所在意的編輯性變更。像素差異則會把反鋸齒與字型微調的雜訊誤判為內容。由於 PDF 儲存的是字形與定位,而非可直接閱讀的字元,因此每一次比對都會先從內容流重建文字。這個抽取步驟正是為何 Artisan 讀取器能提升準確度、為何有界限的 FlateDecode 回退機制以涵蓋率換取安全性,以及為何掃描頁面幾乎無法產生差異的原因。頁面對齊維持以索引為基礎以求可預測性,因此插入一頁會清楚地讀作一連串下游位移。
設計背景:為何 PDF 中的文字其實不是文字。
行為合約
標題為「行為合約」的區段- 輸入。 來源與目標的原始 PDF 位元組。不以
%PDF開頭的緩衝區會引發InvalidArgumentException。 - 輸出(快速路徑)。
DiffResult,內含added、removed、modified區域清單,外加isIdentical()、hasDifferences()、totalChanges()。 - 輸出(結構化路徑)。
StructuredDiffResult,內含段落差異、影像差異、中繼資料變更,以及一個DiffSummary。 - 報告輸出。
DiffFormatter會發出一個 JSON 字串或一段 HTML 片段。它不會產生視覺化的並排紅線(redline)PDF。 - 資源界限。 解壓縮後的內容流大小設有上限,以防範解壓縮炸彈;位元組層級掃描器會避免在精心構造的輸入上發生災難性的正則回溯。
- 決定性。 對於相同的輸入,差異區域與格式化後的輸出是穩定的。
公開 API 介面
標題為「公開 API 介面」的區段| 型別 | 種類 | 主要成員 |
|---|---|---|
NextPDF\Pro\Diff\PdfDiffer | final class | static compare(string $sourcePdf, string $targetPdf): DiffResult, static compareTexts(array $sourcePages, array $targetPages): DiffResult, static extractText(string $contentStream): string |
NextPDF\Pro\Diff\StructuredDiffer | final class | __construct(?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = null), compare(string $sourcePdf, string $targetPdf): StructuredDiffResult |
NextPDF\Pro\Diff\DiffFormatter | final class | toJson(StructuredDiffResult $result): string, toHtml(StructuredDiffResult $result): string |
NextPDF\Pro\Diff\DiffResult | final readonly class | array $added, array $removed, array $modified, isIdentical(): bool, hasDifferences(): bool, totalChanges(): int |
NextPDF\Pro\Diff\StructuredDiffResult | final readonly class | text diff, paragraphs, images, metadata changes, summary |
NextPDF\Pro\Diff\DiffType | enum | Added, Removed, Modified, Unchanged |
程式碼範例 —— 快速上手
標題為「程式碼範例 —— 快速上手」的區段<?php
declare(strict_types=1);
use NextPDF\Pro\Diff\PdfDiffer;
$diff = PdfDiffer::compare( file_get_contents('v1.pdf'), file_get_contents('v2.pdf'),);
if ($diff->hasDifferences()) { echo $diff->totalChanges(), " text changes detected\n";}程式碼範例 —— 正式環境
標題為「程式碼範例 —— 正式環境」的區段<?php
declare(strict_types=1);
use NextPDF\Pro\Diff\DiffFormatter;use NextPDF\Pro\Diff\StructuredDiffer;
function reviewReport(string $oldPdf, string $newPdf): string{ $result = (new StructuredDiffer())->compare($oldPdf, $newPdf);
// JSON for machine consumption; toHtml() for a review UI fragment. return (new DiffFormatter())->toJson($result);}邊界案例與陷阱
標題為「邊界案例與陷阱」的區段- 差異是依索引逐頁對齊的。提早插入一頁會讓所有後續頁面位移,並回報大量的下游變更 —— 對於依索引對齊的比對而言,這是預期行為。
- 影像比對會偵測新增、移除與修改的嵌入影像;它不是知覺型視覺差異,也不會以像素繪製頁面。
- 掃描的僅含影像 PDF 因為沒有執行 OCR,會產生很少或沒有文字差異。
- 在沒有選用 Artisan 讀取器的情況下,抽取會使用有界限的回退機制;高度壓縮的文件可能產生較低的文字涵蓋率。
文字抽取與文件位元組數呈線性關係;Myers 差異對相似文件接近線性,最壞情況下每對頁面為二次方。解壓縮上限會限制記憶體用量。請參閱 performance_budget。
安全注意事項
標題為「安全注意事項」的區段位元組層級回退機制使用以 strpos 為基礎的掃描,而非無界限的正則,以避免在精心構造的 PDF 上發生災難性回溯,並限制解壓縮輸出。差異比對不會執行嵌入的指令稿。請參閱 Core 安全模型。
一致性
標題為「一致性」的區段| 聲明 | 規範條款 | 狀態 |
|---|---|---|
為抽取而剖析 Tj 文字運算子 | ISO 32000-2:2020 §9.4 | 已驗證(單元測試套件) |
為抽取而剖析 TJ 陣列文字運算子 | ISO 32000-2:2020 §9.4 | 已驗證(單元測試套件) |
| 視覺化並排紅線 PDF 輸出 | — | 不支援(僅 JSON/HTML) |
Core 回退/替代方案
標題為「Core 回退/替代方案」的區段文件比對沒有任何 Core 對應方案。選用的 Artisan 讀取器在安裝時可提升抽取準確度,但並非必要。
Enterprise 邊界註記
標題為「Enterprise 邊界註記」的區段這是一個內容變更偵測器。它不是鑑識差異分析器,也不會產生舉證性或竄改歸因的報告;那些範疇不在本模組之內。
發布邊界
標題為「發布邊界」的區段本頁僅描述外部可觀察的行為,以及受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表格、維運手冊檔名與工單前綴皆不在範疇之內。