PostgreSQL存储的大体积PDF无法显示,如何处理大容量base64数据
大体积PDF无法显示问题修复方案
问题根因
你遇到的问题主要来自两个核心限制和逻辑错误:
- 浏览器Data URI长度限制:绝大多数主流浏览器对
data:协议的URI长度支持上限仅为2~5MB,超过该阈值的内嵌资源会被浏览器直接拦截,无法正常加载,这是大PDF无法显示的核心原因。 - 编码逻辑错误:你存储前已经将PDF转为base64格式再写入bytea字段,读取时调用
pg_unescape_bytea得到的是base64格式的文本,直接放到data:application/pdf;base64,后缀后,相当于给浏览器传递了二次base64编码的内容,大文件场景下解析必然失败。 - 额外风险:你的代码直接拼接
$_GET['id']到SQL语句,存在严重的SQL注入漏洞。
最优解决方案(推荐)
放弃Data URI内嵌PDF的方案,单独做PDF流输出接口,完全绕过长度限制,同时支持流式加载:
步骤1:修正存储逻辑
不要再将PDF转为base64后存储,直接把PDF原始二进制内容写入bytea字段,可减少33%的存储体积浪费。
步骤2:新增PDF流输出接口
新建get_pdf.php文件,代码如下:
<?php // 参数校验,避免非法请求 $id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT); if (!$id) { http_response_code(400); exit('非法参数'); } // 数据库连接 $cn = pg_connect('host=localhost port=5432 dbname=sampledb user=postgres password=xxxx'); if (!$cn) { http_response_code(500); exit('数据库连接失败'); } // 参数化查询,避免SQL注入 $query = pg_query_params($cn, "SELECT book_pdf FROM books WHERE id = $1", [$id]); $row = pg_fetch_assoc($query); if (!$row || empty($row['book_pdf'])) { http_response_code(404); exit('文件不存在'); } // 输出PDF头信息 header('Content-Type: application/pdf'); header('Content-Disposition: inline; filename="book_' . $id . '.pdf"'); // 禁用缓存可按需开启 // header('Cache-Control: no-cache, no-store, must-revalidate'); // 直接输出PDF原始二进制 echo pg_unescape_bytea($row['book_pdf']); exit; ?>
步骤3:修改原展示页面代码
把原页面中object标签的data属性指向新增的流接口即可:
<object data="get_pdf.php?id=<?php echo (int)$_GET['id']; ?>" type="application/pdf" style="height:1000px;width:100%"> </object>
备选方案(仅坚持内嵌场景使用)
如果你必须保留内嵌base64的实现方式,需要做以下调整:
- 调整PHP配置:修改php.ini中的
memory_limit(建议调整为最大PDF体积的2倍以上)、output_buffering(调大到最大PDF体积以上或设置为Off)。 - 修正编码逻辑:存储时直接存PDF原始二进制到bytea字段,读取时调用
base64_encode(pg_unescape_bytea($row['book_pdf']))得到base64内容后再嵌入到Data URI中。 - 注意:该方案仅适用于10MB以下的PDF,超过10MB依然大概率出现浏览器兼容性问题。
额外优化建议
超过10MB的PDF不建议存储在数据库中,可将PDF文件存储在磁盘静态目录,数据库仅存储文件路径,读写性能、备份迁移成本都会远优于数据库存储二进制的方案。
内容的提问来源于stack exchange,提问作者Srinath Raghavan
相关产品推荐
相关产品推荐

