在Web应用开发中,经常需要在服务器端处理用户上传或生成的PDF文件,为其添加密码保护是防止文件内容泄露的常用手段。Symfony Process组件提供了简洁的接口来执行系统命令,我们可以借助它调用成熟的PDF处理工具qpdf,完成对PDF字符串的加密操作。

环境准备
要实现该功能,需要先完成以下环境配置:
- 安装PHP的Symfony Process组件,可通过Composer执行安装命令
- 在服务器系统中安装qpdf工具,它是开源的PDF转换和处理工具,支持PDF加密功能
- 确保PHP进程有执行系统命令的权限,并且qpdf的可执行路径已加入系统环境变量
安装依赖
首先通过Composer安装Symfony Process组件,执行以下命令:
composer require symfony/process
核心实现逻辑
整个流程分为三个步骤:首先将PDF字符串写入临时文件,然后通过Symfony Process组件调用qpdf命令对临时文件进行加密,最后读取加密后的文件内容并返回,同时清理临时文件。
临时文件处理
由于qpdf是命令行工具,需要操作文件形式的PDF,因此我们需要先将内存中的PDF字符串写入临时文件。PHP的tmpfile函数可以创建临时文件,使用完毕后自动清理,也可以手动指定临时路径。
调用qpdf加密
qpdf的加密命令格式为qpdf --encrypt 用户密码 所有者密码 密钥长度 -- 输入文件 输出文件,我们可以通过Symfony Process组件拼接并执行该命令。
完整代码示例
以下是完整的实现代码,包含异常处理和临时文件清理逻辑:
<?php
require_once 'vendor/autoload.php';
use SymfonyComponentProcessProcess;
use SymfonyComponentProcessExceptionProcessFailedException;
class PdfEncryptor
{
/**
* 为PDF字符串添加密码保护
* @param string $pdfString 原始PDF字符串
* @param string $userPassword 用户密码,打开PDF时需要输入
* @param string $ownerPassword 所有者密码,用于修改PDF权限
* @param int $keyLength 加密密钥长度,可选40、128、256,默认256
* @return string 加密后的PDF字符串
* @throws ProcessFailedException
*/
public function encryptPdfString(string $pdfString, string $userPassword, string $ownerPassword, int $keyLength = 256): string
{
// 创建临时输入文件
$inputTempFile = tempnam(sys_get_temp_dir(), 'pdf_input_');
// 创建临时输出文件
$outputTempFile = tempnam(sys_get_temp_dir(), 'pdf_output_');
try {
// 将PDF字符串写入输入临时文件
file_put_contents($inputTempFile, $pdfString);
// 构建qpdf加密命令
$command = [
'qpdf',
'--encrypt',
$userPassword,
$ownerPassword,
(string)$keyLength,
'--',
$inputTempFile,
$outputTempFile
];
// 创建Process实例并执行命令
$process = new Process($command);
$process->run();
// 检查命令是否执行成功
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
// 读取加密后的PDF内容
$encryptedPdf = file_get_contents($outputTempFile);
if ($encryptedPdf === false) {
throw new RuntimeException('读取加密后的PDF文件失败');
}
return $encryptedPdf;
} finally {
// 清理临时文件
if (file_exists($inputTempFile)) {
unlink($inputTempFile);
}
if (file_exists($outputTempFile)) {
unlink($outputTempFile);
}
}
}
}
// 示例使用
$originalPdf = file_get_contents('test.pdf'); // 假设已有原始PDF字符串
$encryptor = new PdfEncryptor();
try {
$encryptedPdf = $encryptor->encryptPdfString($originalPdf, 'user123', 'owner456', 256);
// 可以将加密后的PDF保存到文件或输出到浏览器
file_put_contents('encrypted_test.pdf', $encryptedPdf);
echo 'PDF加密成功';
} catch (Exception $e) {
echo 'PDF加密失败:' . $e->getMessage();
}
常见问题排查
- 如果执行时报错提示qpdf命令不存在,需要检查qpdf是否安装以及是否加入系统环境变量
- 若临时文件写入失败,需要检查PHP进程对临时目录的写入权限
- 加密后的PDF无法正常打开,可检查密码是否正确,或者尝试降低密钥长度测试兼容性
- 如果PDF字符串本身格式损坏,qpdf处理时会报错,需要先确保原始PDF字符串是合法的PDF内容
注意事项
使用Symfony Process组件执行系统命令时,需要注意命令参数的转义,避免命令注入风险。本示例中密码参数直接传入,若密码包含特殊字符,建议先对密码进行安全处理。另外,临时文件的清理逻辑必须放在finally块中,避免因异常导致临时文件残留占用服务器空间。
Symfony_ProcessPDF密码保护服务器端PDF处理PDF加密qpdf修改时间:2026-06-25 10:15:22