如何在 PHP 中正确实现 PEM 文件的浏览器下载

本文介绍如何在 PHP 中安全、干净地触发 PEM 文件下载,避免 HTML 内容混入文件,核心在于清除输出缓冲并终止后续脚本执行。

本文介绍如何在 PHP 中安全、干净地触发 PEM 文件下载,避免 HTML 内容混入文件,核心在于清除输出缓冲并终止后续脚本执行。

在 Web 应用中,常需将动态生成的密钥(如 RSA 公钥)以 PEM 格式提供给用户下载。虽然使用 file_put_contents() 保存密钥、再通过 readfile() 输出文件看似简单,但若该逻辑嵌入在常规 HTML 页面(如 Laravel Blade 模板、WordPress 主题或普通 PHP 脚本)中,极易因输出缓冲未清理而导致 HTML 结构意外追加到 PEM 文件末尾——正如问题中所示:下载的 download.pem 文件开头是标准 PEM 头,结尾却混入了 <html>、<body> 和 jQuery 脚本等无关内容,导致文件无法被 OpenSSL 或其他工具正确解析。

根本原因在于:PHP 的输出缓冲(output buffering)可能已开启(例如由框架、CMS 或 php.ini 中的 output_buffering 配置启用),而 readfile() 仅输出文件内容,并未阻止后续 PHP 脚本继续执行或输出模板中的 HTML。因此,必须显式清空缓冲区,并立即终止脚本运行。

✅ 正确做法如下:

// 确保 PEM 内容已写入文件(示例)
$pubKey = "-----BEGIN PUBLIC KEY-----\n" .
          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu..." .
          "\n-----END PUBLIC KEY-----";
file_put_contents('pubKey.pem', $pubKey);

// 清理所有已缓存的输出(关键!)
ob_clean();

// 设置标准下载响应头
header('Content-Description: File Transfer');
header('Content-Type: application/x-pem-file'); // 或更通用的 'application/octet-stream'
header('Content-Disposition: attachment; filename="download.pem"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');

// 输出文件并立即退出,防止后续任何输出
exit(readfile('pubKey.pem'));

⚠️ 注意事项:

通过以上步骤,用户下载的 download.pem 将严格只包含纯净的 PEM 块(含 -----BEGIN... 和 -----END... 行及中间 Base64 数据),完全符合 RFC 7468 规范,可被 OpenSSL、Java KeyStore、OpenSSH 等各类工具无缝识别与使用。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。