PHP项目怎么实现合同比对?

wen java案例 1

本文目录导读:

PHP项目怎么实现合同比对?

  1. 方案一:基于文本比对库(最推荐,适合大多数场景)
  2. 方案二:调用外部命令行工具(最精确,适合专业文档)
  3. 方案三:使用云服务API(最省心,适合SaaS应用)
  4. 方案四:纯前端处理(减轻服务器压力)
  5. 总结与建议

这是一个非常实用的企业级功能需求,在PHP项目中实现合同比对,核心目标通常是快速找出两个或多个文档(如Word、PDF、纯文本)之间的差异

由于PHP本身不擅长解析Word和PDF的复杂格式,常见的实现思路是:

  1. 提取文本内容:将合同从PDF/Word转为纯文本。
  2. 进行文本比对:使用类似Git Diff的算法(如LCS,最长公共子序列)找出差异。
  3. 展示结果:高亮显示删除、新增、修改的部分。

下面介绍几种具体的实现方案,按技术难度和效果排序。


基于文本比对库(最推荐,适合大多数场景)

该方案利用现成的PHP库,负责从文件中提取文本,再用专门差异算法库进行比对。

核心依赖库

你需要至少两个库:

  • 文本提取库
    • PDFsmalot/pdfparser (稳定,社区广) 或 setasign/fpdi (处理表单)。
    • Wordphpoffice/phpword (可以读取docx)。
  • 差异比对库
    • finediff:一个非常优秀的PHP库,专门用于文本的逐行、逐词甚至逐字符比较,并能输出HTML高亮。

实现步骤

Step 1:安装依赖 (Composer)

composer require smalot/pdfparser
composer require phpoffice/phpword
composer require cogpowered/finediff

Step 2:提取文本

<?php
require 'vendor/autoload.php';
use Smalot\PdfParser\Parser as PdfParser;
use PhpOffice\PhpWord\IOFactory as WordFactory;
function extractText($filePath) {
    $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
    switch ($extension) {
        case 'pdf':
            $parser = new PdfParser();
            $pdf = $parser->parseFile($filePath);
            return $pdf->getText();
        case 'docx':
            $phpWord = WordFactory::load($filePath);
            $text = '';
            foreach ($phpWord->getSections() as $section) {
                $elements = $section->getElements();
                foreach ($elements as $element) {
                    if (method_exists($element, 'getText')) {
                        $text .= $element->getText() . "\n";
                    }
                }
            }
            return $text;
        case 'txt':
            return file_get_contents($filePath);
        default:
            throw new \Exception('Unsupported file type: ' . $extension);
    }
}
// 用法
$oldText = extractText('contract_v1.pdf');
$newText = extractText('contract_v2.docx');

Step 3:比对并输出高亮HTML

<?php
use cogpowered\FineDiff\Diff;
use cogpowered\FineDiff\Render\Html;
function compareContracts($oldText, $newText) {
    // 使用逐词比对,更精细
    $granularity = \cogpowered\FineDiff\Delimiters::paragraphs() . \cogpowered\FineDiff\Delimiters::sentences() . \cogpowered\FineDiff\Delimiters::words();
    $diff = new Diff($granularity);
    $renderer = new Html();
    // 生成HTML,
    // <ins> 表示新增内容
    // <del> 表示删除内容
    $result = $renderer->process($oldText, $newText);
    return $result;
}
$htmlResult = compareContracts($oldText, $newText);
// 在前端显示时,记得给 <ins> 和 <del> 设置CSS样式
// ins { background-color: #d4fcbc; text-decoration: none; } 
// del { background-color: #fbb; }

优点:纯PHP实现,部署简单,不依赖外部服务,效果精细(支持逐词比对)。 缺点:对复杂PDF(扫描件、表格)文本提取效果较差,需结合OCR。


调用外部命令行工具(最精确,适合专业文档)

对于复杂的Word格式(如有表格、页眉页脚)或扫描件PDF,纯PHP库提取文本会丢失格式信息,这时,调用专业工具更可靠。

工具组合

  • 文档转文本pandoc (瑞士军刀,几乎支持所有格式互转) 或 Apache Tika (内容分析工具包)。
  • 差异比对diff (Linux自带) 或 git diff
  • 可选pdftotext (来自Poppler工具集,专门用于PDF)。

实现步骤

Step 1:服务器安装工具

# Ubuntu
sudo apt-get install pandoc poppler-utils
# macOS
brew install pandoc poppler

Step 2:PHP调用执行

<?php
function extractTextWithPandoc($filePath) {
    $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
    if ($extension === 'pdf') {
        // PDF推荐用pdftotext,更准确
        $output = shell_exec("pdftotext " . escapeshellarg($filePath) . " -");
    } else {
        // Word或其他用pandoc
        $output = shell_exec("pandoc " . escapeshellarg($filePath) . " -t plain --wrap=none");
    }
    return $output;
}
function diffTexts($oldText, $newText) {
    // 将文本写入临时文件
    $tmpOld = tempnam(sys_get_temp_dir(), 'diff_old');
    $tmpNew = tempnam(sys_get_temp_dir(), 'diff_new');
    file_put_contents($tmpOld, $oldText);
    file_put_contents($tmpNew, $newText);
    // 执行系统diff,生成统一格式
    $diffOutput = shell_exec("diff -u " . escapeshellarg($tmpOld) . " " . escapeshellarg($tmpNew));
    unlink($tmpOld);
    unlink($tmpNew);
    return $diffOutput;
}
// 用法
$oldText = extractTextWithPandoc('contract_v1.pdf');
$newText = extractTextWithPandoc('contract_v2.docx');
$diffResult = diffTexts($oldText, $newText);
// 解析 diff 输出,转换为HTML
// 可以自己写一个简单解析器,或者用现成的库(如 PHP-Diff)

优点:文本提取精度最高,能处理复杂版式。 缺点:依赖服务器环境,需要安装外部软件,安全性需注意(防止命令注入)。


使用云服务API(最省心,适合SaaS应用)

如果不想折腾格式解析,可以直接调用云服务商提供的文档比对API。

  • 腾讯云-文档比对:提供专门API,直接上传两份文档,返回JSON格式的差异列表。
  • 钉钉/阿里云-文档服务:也有类似能力。

基本流程(伪代码):

// 1. 上传文件
$response = httpPost('https://api.xxx.com/document/compare', [
    'file1' => new CURLFile('contract_v1.pdf'),
    'file2' => new CURLFile('contract_v2.docx')
]);
// 2. 获取结果(通常包含每个段落的变更类型:新增、删除、修改、无变化)
$result = json_decode($response, true);
// 3. 根据API返回的坐标或文本片段,在前端渲染差异

优点:完全不关心文件格式解析,效果好。 缺点:需要付费、依赖网络、合同内容可能涉及数据隐私。


纯前端处理(减轻服务器压力)

如果合同文本内容不大且均为.txt.md格式,可以在浏览器端用JavaScript完成比对,PHP仅负责提供原始文本。

  • 前端库diff (npm包), jsdiff
  • 效果:用户操作完全在浏览器内完成,服务器只做文件上传和存储。

总结与建议

方案 适用场景 复杂度 效果 推荐指数
PHPPHP库 常规合同,非扫描件,对格式无要求 良好(文本层面) ⭐⭐⭐⭐⭐
命令行工具 复杂格式,需要绝对精确 极佳 ⭐⭐⭐⭐
云API 追求稳定性,有预算,数据不敏感 极佳(带格式) ⭐⭐⭐
纯前端 纯文本,轻量级场景 一般 ⭐⭐⭐

对于大多数PHP 项目,建议采用方案一:FineDiff + smalot/pdfparser + PHPWord 它平衡了效果、部署成本和代码可控性,如果后续发现PDF提取文本不准确(例如扫描件),再为特定文件类型切换到方案二(调用pdftotext)或集成OCR(Tesseract)即可。

抱歉,评论功能暂时关闭!