合同生成之 word 文档转 pdf
写在前面
业务场景:需要动态数据填充,生成合同 pdf 文件。
- 配置合同
word模板 - 替换模板变量
${var} - 生成
pdf合同
# 依赖包
composer require phpoffice/phpword
composer require dompdf/dompdf
composer require dompdf/php-font-lib
# 注册字体,脚本 load_font.php(获取 github -> dompdf-utils),字体:simhei.ttf
php load_font.php simhei storage/fonts/simhei.ttf
参考代码
<?php
namespace App\Service;
use PhpOffice\PhpWord\Exception\CopyFileException;
use PhpOffice\PhpWord\Exception\CreateTemporaryFileException;
use PhpOffice\PhpWord\TemplateProcessor;
class WordPdfService
{
/**
* 根据 word 模板生成 pdf
*
* @throws CopyFileException
* @throws CreateTemporaryFileException
*/
public function word2Pdf(string $templateFilePath): array
{
$templateProcessor = new TemplateProcessor($templateFilePath);
// 替换基本变量
$templateData = $this->prepareTemplateData();
$this->replaceBasicVariables($templateProcessor, $templateData);
// 处理表格数据
$this->replaceTableData($templateProcessor);
// 保存临时Word文件
$tempDir = storage_path('app');
if (!is_dir($tempDir)) {
mkdir($tempDir, 0755, true);
}
$tempWordName = uniqid('contract_') . '.docx';
$tempWordPath = $tempDir . '/' . $tempWordName;
$templateProcessor->saveAs($tempWordPath);
// 转换为PDF
$pdfPath = $this->convertWordToPdf($tempWordPath, $tempDir);
// 清理临时Word文件
unlink($tempWordPath);
// 返回PDF文件路径(或直接下载)
return ['ok' => true, 'pdfPath' => $pdfPath];
}
/**
* 准备模板数据
*
* @return array
*/
private function prepareTemplateData(): array
{
return [
'name' => '张三',
'projectName' => '测试项目',
'date' => now()->format('Y年m月d日'),
];
}
/**
* 替换基本变量
*
* @param $templateProcessor | 模板对象
* @param $data | 数据
* @return void
*/
public function replaceBasicVariables($templateProcessor, $data): void
{
foreach ($data as $key => $value) {
$templateProcessor->setValue($key, $value ?? '');
}
}
/**
* 处理表格数据
*
* @param $templateProcessor | 模板对象
* @return void
*/
public function replaceTableData($templateProcessor): void
{
// 获取数据
$goodsLists = [
['name' => '数据1', 'number' => 10, 'price' => '200.00', 'tax_rate' => '0.03'],
['name' => '数据2', 'number' => 210, 'price' => '20000.21', 'tax_rate' => '0.13'],
['name' => '数据4', 'number' => 320, 'price' => '30000.9987', 'tax_rate' => '0.11'],
];
if (count($goodsLists) > 0) {
// 使用cloneRow方法克隆表格行
$templateProcessor->cloneRow('idx', count($goodsLists));
// 行数据赋值
foreach ($goodsLists as $index => $goods) {
$idxNum = $index + 1;
$taxRate = $goods['tax_rate'] * 100 . '%';
$taxRate = str_replace('.00', '', $taxRate);
// 设置克隆行的变量
$templateProcessor->setValue("idx#{$idxNum}", $idxNum);
$templateProcessor->setValue("name#{$idxNum}", $goods['name']);
$templateProcessor->setValue("number#{$idxNum}", $goods['number']);
$templateProcessor->setValue("price#{$idxNum}", $goods['price']);
$templateProcessor->setValue("tax_rate#{$idxNum}", $taxRate);
}
}
}
/**
* 将 Word 转换为 PDF (注意中文乱码)
*/
public function convertWordToPdf($wordPath, $outputDir): string
{
// 配置PDF渲染器路径和名称
\PhpOffice\PhpWord\Settings::setPdfRendererPath(base_path('vendor/dompdf/dompdf'));
\PhpOffice\PhpWord\Settings::setPdfRendererName('DomPDF');
// 创建Dompdf选项,设置默认字体 'simhei' 必须与注册字体时使用的名称一致
$options = new \Dompdf\Options();
$options->set('defaultFont', 'simhei');
$options->set('isHtml5ParserEnabled', true);
$options->set('isPhpEnabled', true);
// 加载Word文档并转换为HTML
$dompdf = new \Dompdf\Dompdf($options);
$phpWord = \PhpOffice\PhpWord\IOFactory::load($wordPath);
// 创建一个临时HTML文件来传递内容
$tempHtml = $outputDir . DIRECTORY_SEPARATOR . 'temp_' . uniqid() . '.html';
$htmlWriter = new \PhpOffice\PhpWord\Writer\HTML($phpWord);
file_put_contents($tempHtml, $htmlWriter->getContent());
// 加载HTML内容,明确指定UTF-8编码
$htmlContent = file_get_contents($tempHtml);
$dompdf->loadHtml($htmlContent, 'UTF-8');
// 设置纸张和渲染
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
// 保存PDF文件
$pdfFilename = uniqid('contract_') . '.pdf';
$pdfPath = $outputDir . DIRECTORY_SEPARATOR . $pdfFilename;
file_put_contents($pdfPath, $dompdf->output());
// 清理临时HTML文件
unlink($tempHtml);
return $pdfPath;
}
}
参考代码,替换对应的:模板文件 $templateFilePath,模板填充数据prepareTemplateData()、 replaceTableData().$goodsList
注意事项
- 脚本
load_font.php注册配置宋体,微软雅黑等字体,避免pdf文件中文乱码; - 创建合同模板并标记变量
- 建议
html模板(更好控制布局样式)生成pdf文件;
本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu
推荐文章: