全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

将 Snappy PDF 生成的字符串转换为服务器上的加密 PDF

本文详细介绍了如何在 Symfony 3.4 应用程序中,将 Snappy PDF 生成的原始 PDF 字符串保存为服务器上的文件,并利用 `qpdf` 工具通过 Symfony 的 `Process` 组件对其进行密码保护。教程涵盖了文件写入、外部命令执行、错误处理以及临时文件清理等关键步骤,旨在提供一个将无保护 PDF 转换为安全加密 PDF 的完整解决方案。

背景与挑战

在使用 Snappy PDF(基于 wkhtmltopdf)生成 PDF 文档时,其通常以字符串形式返回生成的 PDF 内容。然而,wkhtmltopdf 本身不直接提供密码保护功能。为了满足对 PDF 文档进行加密的需求,我们需要将这个 PDF 字符串写入服务器上的临时文件,然后借助外部工具(如 qpdf)对其进行加密处理。在 Symfony 应用程序中,执行此类系统级命令的最佳实践是使用其内置的 Process 组件。

解决方案概述

本教程将分步指导您完成以下操作:

  1. 将 Snappy PDF 返回的 PDF 字符串保存到服务器上的一个临时文件。
  2. 使用 Symfony 的 Process 组件执行 qpdf 命令,对临时 PDF 文件进行密码保护。
  3. 读取加密后的 PDF 文件内容,并清理所有临时文件。

步骤一:保存 PDF 字符串到临时文件

首先,您需要将 Snappy PDF 生成的 PDF 内容(一个二进制字符串)写入服务器上的一个临时文件。这可以通过 PHP 的 file_put_contents 函数轻松实现。为了确保文件名的唯一性,可以使用 tempnam 函数生成一个唯一的临时文件名。

>
endobj
2 0 obj
<<
/Type /Catalog
/Pages 3 0 R
...
'; // 实际的 PDF 字符串会更长

// 生成一个唯一的临时文件路径
// sys_get_temp_dir() 获取系统临时目录
$tempDir = sys_get_temp_dir();
$unprotectedPdfPath = tempnam($tempDir, 'unprotected_pdf_');
if ($unprotectedPdfPath === false) {
    throw new \RuntimeException('无法创建临时文件用于未保护的 PDF。');
}

// 将 PDF 字符串写入临时文件
$bytesWritten = file_put_contents($unprotectedPdfPath, $pdfString);
if ($bytesWritten === false) {
    // 尝试清理可能已创建但写入失败的文件
    if (file_exists($unprotectedPdfPath)) {
        unlink($unprotectedPdfPath);
    }
    throw new \RuntimeException('无法将 PDF 字符串写入文件: ' . $unprotectedPdfPath);
}

// 确保文件权限正确,以便 qpdf 可以读取
chmod($unprotectedPdfPath, 0644);

echo "未保护的 PDF 已保存到: " . $unprotectedPdfPath . "\n";

?>

注意事项:

  • tempnam() 函数会创建一个空文件,并返回其路径。
  • sys_get_temp_dir() 确保临时文件存储在系统指定的临时目录中。
  • 务必检查 file_put_contents 的返回值,以确保写入成功。
  • 设置正确的文件权限 (chmod) 对于外部工具访问文件至关重要。

步骤二:使用 qpdf 进行密码保护

接下来,我们将使用 qpdf 工具对刚刚创建的临时 PDF 文件进行密码保护。qpdf 是一个强大的命令行工具,用于转换和检查 PDF 文件。您需要确保 qpdf 已安装在您的服务器上。

我们将使用 Symfony 的 Process 组件来执行 qpdf 命令。

setTimeout(60); // 设置超时时间,根据 PDF 大小调整

try {
    $process->run();

    // 检查命令是否成功执行
    if (!$process->isSuccessful()) {
        throw new ProcessFailedException($process);
    }

    echo "PDF 已成功加密并保存到: " . $protectedPdfPath . "\n";

    // 确保加密后的文件权限正确
    chmod($protectedPdfPath, 0644);

} catch (ProcessFailedException $exception) {
    // 处理命令执行失败的情况
    echo "加密 PDF 失败。\n";
    echo "错误输出: " . $exception->getMessage() . "\n";
    echo "标准输出: " . $process->getOutput() . "\n";
    echo "错误输出: " . $process->getErrorOutput() . "\n";

    // 清理可能已创建的文件
    if (file_exists($unprotectedPdfPath)) {
        unlink($unprotectedPdfPath);
    }
    if (file_exists($protectedPdfPath)) {
        unlink($protectedPdfPath);
    }
    throw $exception; // 重新抛出异常
} finally {
    // 无论成功与否,都尝试删除未保护的临时文件
    if (file_exists($unprotectedPdfPath)) {
        unlink($unprotectedPdfPath);
        echo "已清理未保护的临时文件: " . $unprotectedPdfPath . "\n";
    }
}

?>

注意事项:

  • qpdf 安装:确保您的服务器上已安装 qpdf。在 Debian/Ubuntu 系统上,可以使用 sudo apt-get install qpdf 安装。
  • 命令参数:qpdf --encrypt 命令的参数顺序和含义非常重要。
    • --encrypt word> :设置用户密码、所有者密码和加密密钥长度。
    • 权限选项(如 --print=full)控制用户可以对文档执行的操作。
    • -- 是一个重要的分隔符,用于区分 qpdf 的选项和文件路径参数。
  • 错误处理:ProcessFailedException 是处理命令执行失败的关键。通过 getOutput() 和 getErrorOutput() 可以获取命令的标准输出和错误输出,这对于调试非常有帮助。
  • 超时设置:setTimeout() 方法可以防止长时间运行的命令导致脚本挂起。

步骤三:读取加密后的 PDF 并清理

加密完成后,您可以读取加密后的 PDF 文件内容,以便进行后续处理(例如将其作为 HTTP 响应返回给用户,或上传到云存储)。最后,务必清理所有临时文件,以避免服务器磁盘空间被占用。

 'application/pdf',
//     'Content-Disposition' => 'attachment; filename="protected_document.pdf"',
// ]);

?>

综合示例代码

将上述所有步骤整合到一个完整的 PHP 脚本中,您可以在 Symfony 控制器或服务中调用此逻辑。

setTimeout(120); // 增加超时时间以适应大型 PDF

            $process->run();

            if (!$process->isSuccessful()) {
                throw new ProcessFailedException($process);
            }
            chmod($protectedPdfPath, 0644);

            // 3. 读取加密后的 PDF 内容
            $protectedPdfContent = file_get_contents($protectedPdfPath);
            if ($protectedPdfContent === false) {
                throw new \RuntimeException('无法读取加密后的 PDF 文件: ' . $protectedPdfPath);
            }

            return $protectedPdfContent;

        } catch (\Exception $e) {
            // 记录错误或进行其他错误处理
            error_log("PDF 加密失败: " . $e->getMessage());
            if ($e instanceof ProcessFailedException) {
                error_log("QPDF 错误输出: " . $e->getProcess()->getErrorOutput());
                error_log("QPDF 标准输出: " . $e->getProcess()->getOutput());
            }
            return null; // 或者抛出自定义异常
        } finally {
            // 清理所有临时文件
            if ($unprotectedPdfPath && file_exists($unprotectedPdfPath)) {
                unlink($unprotectedPdfPath);
            }
            if ($protectedPdfPath && file_exists($protectedPdfPath)) {
                unlink($protectedPdfPath);
            }
        }
    }
}

// 如何在控制器中使用:
// class MyController extends Controller
// {
//     public function generateProtectedPdfAction()
//     {
//         // 假设您已经从 Snappy PDF 获取了 $originalPdfString
//         $originalPdfString = $this->get('snappy.pdf')->getOutputFromHtml('

Hello World

'); // // $pdfProtectorService = $this->get('app.pdf_protector_service'); // 假设服务已注册 // $protectedPdfContent = $pdfProtectorService->protectPdfString( // $originalPdfString, // 'my_user_password', // 'my_owner_password' // ); // // if ($protectedPdfContent) { // return new Response($protectedPdfContent, 200, [ // 'Content-Type' => 'application/pdf', // 'Content-Disposition' => 'attachment; filename="protected_document.pdf"', // ]); // } else { // // 处理加密失败的情况 // return new Response('PDF 加密失败。', 500); // } // } // } ?>

总结

通过利用 Symfony 的 Process 组件,我们能够有效地在 PHP 应用程序中执行外部命令行工具(如 qpdf),从而实现了将 Snappy PDF 生成的原始 PDF 字符串转换为密码保护的 PDF 文件。这个过程涉及临时文件管理、外部命令的构建与执行、以及健壮的错误处理。遵循这些步骤和最佳实践,可以确保您的应用程序能够安全、可靠地处理 PDF 加密需求。


# php  # word  # html  # 浏览器  # app  # access  # ubuntu  # 工具  # ai  # pdf  # 云存储  # symfony  # print  # 字符串  # Length  # http  # debian  # PDF 文档  # 临时文件  # 您的  # 器上  # 您可以  # 应用程序  # 是一个  # 将其  # 对其  # 可以使用  # 文档 


相关文章: 建站主机系统SEO优化与智能配置核心关键词操作指南  宁波自助建站系统如何快速打造专业企业网站?  如何配置支付宝与微信支付功能?  相亲简历制作网站推荐大全,新相亲大会主持人小萍萍资料?  如何通过虚拟主机快速搭建个人网站?  电影网站制作价格表,那些提供免费电影的网站,他们是怎么盈利的?  如何选择适配移动端的WAP自助建站平台?  如何挑选高效建站主机与优质域名?  如何用VPS主机快速搭建个人网站?  韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南  在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?  建站之星后台密码遗忘如何找回?  淘宝制作网站有哪些,淘宝网官网主页?  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  东莞专业网站制作公司有哪些,东莞招聘网站哪个好?  昆明网站制作哪家好,昆明公租房申请网上登录入口?  宝塔面板如何快速创建新站点?  小捣蛋自助建站系统:数据分析与安全设置双核驱动网站优化  如何用美橙互联一键搭建多站合一网站?  免费视频制作网站,更新又快又好的免费电影网站?  如何用5美元大硬盘VPS安全高效搭建个人网站?  在线制作视频的网站有哪些,电脑如何制作视频短片?  C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)  如何在沈阳梯子盘古建站优化SEO排名与功能模块?  制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?  建站之星×万网:智能建站系统+自助建站平台一键生成  广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?  b2c电商网站制作流程,b2c水平综合的电商平台?  香港服务器建站指南:免备案优势与SEO优化技巧全解析  常州自助建站:操作简便模板丰富,企业个人快速搭建网站  制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?  南京做网站制作公司,南京哈发网络有限公司,公司怎么样,做网页美工DIV+CSS待遇怎么样?  网站制作专业公司有哪些,如何制作一个企业网站,建设网站的基本步骤有哪些?  香港服务器如何优化才能显著提升网站加载速度?  C++如何编写函数模板?(泛型编程入门)  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  如何在阿里云虚拟服务器快速搭建网站?  安徽网站建设与外贸建站服务专业定制方案  长沙企业网站制作哪家好,长沙水业集团官方网站?  广州网站制作的公司,现在专门做网站的公司有没有哪几家是比较好的,性价比高,模板也多的?  如何通过商城免费建站系统源码自定义网站主题?  深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?  建站之星IIS配置教程:代码生成技巧与站点搭建指南  最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?  公司网站的制作公司,企业网站制作基本流程有哪些?  如何在IIS中配置站点IP、端口及主机头?  建站之星安装失败:服务器环境不兼容?  如何通过主机屋免费建站教程十分钟搭建网站?  建站之星如何优化SEO以实现高效排名?  如何快速搭建高效服务器建站系统? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。