我接手过一个烂摊子:一个客户要批量导出三百份带表格的PDF数据,而他们手头的工具只能输出纯文本,表格全乱了。那会儿我就想,PHP解析PDF这事儿,真不是装个库就能糊弄过去的。
PHP生态里处理PDF的库不少,但真正能扛住复杂版式的没几个。TCPDF和FPDF是生成PDF的老牌工具,可解析这事儿,它们帮不上忙。解析的核心难点在于——PDF文件本身是一堆对象和坐标的堆砌,页面上的文字、线条、图片都被拆成独立的指令,没有“段落”和“表格”这种抽象概念。你要做的,是把这些散落的坐标点重新拼成人能看懂的结构。
我试过用`pdfparser`这类纯PHP库,轻量是轻量,但遇到带复杂字体编码的PDF,中文直接乱码。后来换用`smalot/pdfparser`,它内部用了正则去匹配内容流,效率不算高,可对付中小型文件还行。真正让我头疼的是扫描件——那种整页就是一张图片的PDF,PHP这边再折腾也是白搭,只能丢给OCR服务,比如Tesseract或者云厂商的接口。
说个具体例子。有个PDF里嵌了表格,但表格线是用矢量图形画的,文字是单独放的。用pdfparser读出来,文字顺序是乱的——先读到右下角的单元格,再读到左上角的。我当时的解法很笨:把每个文字块的位置信息(x,y坐标)取出来,按y轴分组,再按x轴排序。这招对付规整的表格还行,一旦遇到单元格跨行或者合并单元格,排序逻辑就崩了。
后来我学聪明了,直接用命令行工具打底。`pdftotext -layout`能把版式保留得差不多,`pdf2htmlEX`能转成带坐标的HTML,然后PHP再用DOM解析。这组合拳比纯PHP库稳得多,就是部署环境得装一堆外部依赖。你要是只跑在共享主机上,那就没辙了,只能回归纯PHP方案。
对了,编码问题也得提一嘴。很多PDF用的不是标准Unicode,而是自定义的CID字体映射。你得先解析字体文件里的ToUnicode CMap表,才能把内部编码转成人话。这一步不做,你抽出来的内容就是天书。有个取巧的办法:用`setasign/fpdi`配合`FPDI`的`importPage`,把PDF转成图片再识别——但那是下下策,性能太差。
我的建议是,动手前先花十分钟摸摸底:PDF是文本型的还是扫描型的?有没有加密?表格是规则还是不规则?这决定了你选哪条路。别一上来就写代码,不然你会像我一样,在调试乱码和坐标错位上浪费一整个下午。PHP解析PDF没有银弹,组合工具、理解文件结构、接受偶尔的脏数据,这才是常态。