PHP直接读取在线PDF失败是因为PDF是含对象、交叉引用表等的二进制格式,非纯文本;用pdftotext(Poppler)提取文字最可靠,需服务器命令行权限并处理加密与扫描件。

PHP 直接读取在线 PDF 文件会失败,原因是什么?
PHP 的 file_get_contents() 或 curl 能拿到 PDF 的二进制流,但直接输出或 echo 只会看到乱码——PDF 不是纯文本格式,而是包含对象、交叉引用表、压缩流和字体映射的结构化二进制文档。试图用 strip_tags() 或正则硬匹配文字,基本无效,还可能触发解析错误或截断内容。
推荐方案:用 Poppler 工具链 + exec() 调用 pdftotext
比纯 PHP 库(如 TCPDF、FPDI)更可靠,也比 smalot/pdfparser 这类纯 PHP 解析器更能处理加密、图片内嵌文字、非标准编码的 PDF。前提是你有服务器命令行权限(Linux/Unix 环境)。
- 安装 Poppler:
apt-get install poppler-utils(Ubuntu/Debian)或yum install poppler-utils(CentOS) - 确保 PHP 的
exec()未被禁用(检查disable_functions配置) - 下载远程 PDF 到临时文件再转换,避免直接管道传输导致编码识别失败:
$pdfUrl = 'https://example.com/doc.pdf'; $tempPdf = sys_get_temp_dir() . '/temp_' . uniqid() . '.pdf'; file_put_contents($tempPdf, file_get_contents($pdfUrl)); $txtPath = $tempPdf . '.txt'; exec("pdftotext -layout -enc UTF-8 {$tempPdf} {$txtPath} 2>&1", $output, $returnCode); if ($returnCode === 0 && file_exists($txtPath)) { $text = file_get_contents($txtPath); } -
-layout保留原始排版空格和换行,对表格/段落识别很关键;不加容易把“姓名:”和后面内容挤成“姓名:张三电话:138…”
遇到加密 PDF 怎么办?
很多在线 PDF 含所有者密码(即使能打开,也不代表可复制文字)。pdftotext 遇到加密会静默失败或报错 PDF password required。不能跳过,必须先解密。
- 用
qpdf尝试无密码解密:qpdf --password='' --decrypt input.pdf output.pdf(部分弱加密有效) - 若已知密码,传给
pdftotext -opw "xxx"(所有者密码)或-upw "xxx"(用户密码) - PHP 中判断是否加密:
exec("pdfinfo {$tempPdf} 2>&1", $info);检查输出中是否含Encrypted: yes
为什么不用 smalot/pdfparser 或 setasign/fpdi?
它们适合「已知结构简单、无加密、无图像OCR文字」的 PDF,比如自动生成的发票。但一旦 PDF 含扫描件(本质是图片)、使用自定义字体嵌入、或用了 JBIG2 压缩,这些库就只能返回空字符串或乱码字符(如 þÿ)。而 pdftotext 底层调用 Poppler 的文本提取引擎,对真实业务 PDF 兼容性高得多。
立即学习“PHP免费学习笔记(深入)”;
真正难的不是“怎么写代码”,而是确认 PDF 是否真含可提取文字——打开它,Ctrl+A 全选,看能否复制出内容。如果不能,说明是扫描件,此时 PHP 层面已无解,必须上 OCR(如 Tesseract),那又是另一套流程了。











