PHP拆分重组pdf,php拆分pdf指定页数,并合并成新pdf
在ThinkPHP5中实现PDF拆分与合并功能,主要使用FPDI库来处理PDF页面操作。以下是完整的实现流程和代码示例。
环境准备与依赖安装
首先通过Composer安装必要的依赖包
composer require setasign/fpdi
composer require setasign/fpdf
核心功能实现
以下是完整的PDF处理类,包含拆分指定页面和合并多个PDF的功能:
<?php
namespace app\common\util;use setasign\Fpdi\Tcpdf\Fpdi;class PdfHandler
{/*** 拆分PDF指定页面并合并为新PDF* @param array $pdfFiles PDF文件路径数组* @param array $pageRules 页面规则 ['file1.pdf' => '1,3,5', 'file2.pdf' => '2-4']* @param string $outputName 输出文件名* @param string $outputMode 输出模式 D-下载 I-预览 F-保存* @return mixed*/public function splitAndMergePdf($pdfFiles, $pageRules, $outputName = 'merged.pdf', $outputMode = 'D'){try {$pdf = new Fpdi();foreach ($pdfFiles as $index => $pdfFile) {$fileKey = basename($pdfFile);if (!isset($pageRules[$fileKey])) {continue;}$pageCount = $pdf->setSourceFile($pdfFile);$selectedPages = $this->parsePageRules($pageRules[$fileKey], $pageCount);foreach ($selectedPages as $pageNo) {$templateId = $pdf->importPage($pageNo);$size = $pdf->getTemplateSize($templateId);$pdf->AddPage($size['orientation'], $size);$pdf->useTemplate($templateId);}}$pdf->Output($outputName, $outputMode);$pdf->closeParsers();return true;} catch (\Exception $e) {throw new \Exception("PDF处理失败: " . $e->getMessage());}}/*** 解析页面规则* @param string $rule 页面规则 '1,3,5' 或 '2-4' 或 'all'* @param int $totalPages 总页数* @return array*/private function parsePageRules($rule, $totalPages){$pages = [];if ($rule === 'all') {for ($i = 1; $i <= $totalPages; $i++) {$pages[] = $i;}return $pages;}if (strpos($rule, '-') !== false) {list($start, $end) = explode('-', $rule);$start = max(1, intval(trim($start)));$end = min($totalPages, intval(trim($end)));for ($i = $start; $i <= $end; $i++) {$pages[] = $i;}return $pages;}if (strpos($rule, ',') !== false) {$pageArray = explode(',', $rule);foreach ($pageArray as $page) {$page = intval(trim($page));if ($page >= 1 && $page <= $totalPages) {$pages[] = $page;}}return $pages;}$page = intval(trim($rule));if ($page >= 1 && $page <= $totalPages) {$pages[] = $page;}return $pages;}/*** 简单合并多个PDF(全部页面)* @param array $pdfFiles PDF文件路径数组* @param string $outputName 输出文件名* @param string $outputMode 输出模式* @return mixed*/public function simpleMergePdf($pdfFiles, $outputName = 'merged.pdf', $outputMode = 'D'){try {$pdf = new Fpdi();foreach ($pdfFiles as $pdfFile) {$pageCount = $pdf->setSourceFile($pdfFile);for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {$templateId = $pdf->importPage($pageNo);$size = $pdf->getTemplateSize($templateId);$pdf->AddPage($size['orientation'], $size);$pdf->useTemplate($templateId);}}$pdf->Output($outputName, $outputMode);$pdf->closeParsers();return true;} catch (\Exception $e) {throw new \Exception("PDF合并失败: " . $e->getMessage());}}
}
控制器调用示例
<?php
namespace app\index\controller;use think\Controller;
use think\Request;
use app\common\util\PdfHandler;class Pdf extends Controller
{/*** 拆分合并PDF页面*/public function splitMerge(){if (Request::instance()->isPost()) {try {$pdfHandler = new PdfHandler();// PDF文件路径$pdfFiles = [ROOT_PATH . 'public/uploads/employee_agreement.pdf',ROOT_PATH . 'public/uploads/work_summary.pdf',ROOT_PATH . 'public/uploads/rental_agreement.pdf'];// 页面规则:指定每个PDF要提取的页面$pageRules = ['employee_agreement.pdf' => '1,3', // 第1页和第3页'work_summary.pdf' => '2-4', // 第2页到第4页'rental_agreement.pdf' => 'all' // 所有页面];$result = $pdfHandler->splitAndMergePdf($pdfFiles, $pageRules, 'custom_merged.pdf', 'D');if ($result) {return json(['code' => 1, 'msg' => 'PDF处理成功']);}} catch (\Exception $e) {return json(['code' => 0, 'msg' => $e->getMessage()]);}}return $this->fetch();}/*** 简单合并多个PDF*/public function simpleMerge(){try {$pdfHandler = new PdfHandler();$pdfFiles = [ROOT_PATH . 'public/uploads/doc1.pdf',ROOT_PATH . 'public/uploads/doc2.pdf',ROOT_PATH . 'public/uploads/doc3.pdf'];$result = $pdfHandler->simpleMergePdf($pdfFiles,'simple_merged.pdf','D');if ($result) {return json(['code' => 1, 'msg' => 'PDF合并成功']);}} catch (\Exception $e) {return json(['code' => 0, 'msg' => $e->getMessage()]);}}
}
前端表单页面
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>PDF拆分合并工具</title><style>.container { max-width: 800px; margin: 50px auto; padding: 20px; }.form-group { margin-bottom: 20px; }label { display: block; margin-bottom: 5px; font-weight: bold; }input, select { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }.btn { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }.btn:hover { background: #0056b3; }.file-item { background: #f8f9fa; padding: 15px; margin-bottom: 10px; border-radius: 4px; }</style>
</head>
<body><div class="container"><h2>PDF拆分重组工具</h2><form id="pdfForm" action="{:url('index/pdf/splitMerge')}" method="post"><div class="form-group"><label>选择PDF文件:</label><input type="file" id="pdfFiles" multiple accept=".pdf"><div id="fileList"></div></div><div class="form-group"><label>输出文件名:</label><input type="text" name="output_name" value="custom_merged.pdf" required></div><button type="submit" class="btn">生成新PDF</button></form></div><script>document.getElementById('pdfFiles').addEventListener('change', function(e) {const fileList = document.getElementById('fileList');fileList.innerHTML = '';Array.from(e.target.files).forEach((file, index) => {const fileItem = document.createElement('div');fileItem.className = 'file-item';fileItem.innerHTML = `<strong>${file.name}</strong><div style="margin-top: 10px;"><label>页面选择:</label><input type="text" name="page_rules[${file.name}]" placeholder="例如: 1,3,5 或 2-4 或 all"></div>`;fileList.appendChild(fileItem);});});</script>
</body>
</html>
功能特点说明
- 灵活的页面选择:支持单个页面、页面范围、多个指定页面以及全部页面的选择方式
- 多种输出模式:支持下载(D)、浏览器预览(I)、服务器保存(F)等输出方式
- 异常处理完善:包含完整的错误捕获和处理机制
- 内存管理优化:使用closeParsers()方法及时释放资源
- 自动尺寸适配:根据原PDF页面尺寸自动设置新页面大小
该方案适用于文档管理系统、在线PDF处理服务等场景,能够高效地完成PDF页面的拆分和重组任务。
