在 PHP 中从 /Filter /FlateDecode PDF 流中提取数据
Posted
技术标签:
【中文标题】在 PHP 中从 /Filter /FlateDecode PDF 流中提取数据【英文标题】:Data extraction from /Filter /FlateDecode PDF stream in PHP 【发布时间】:2012-07-28 16:57:55 【问题描述】:我无法解密流中的数据,例如:
56 0 obj
<< /Length 1242 /Filter /FlateDecode >>
stream
x]êΩnƒ ÑûbÀKq¬æ\âê¢....(whole binary is omitted)
endstream
endobj
我尝试隔离文件和二进制字符串中的二进制内容 (x]êΩnƒ ÑûbÀKq¬æ\âê¢....
)。解码功能gzinflate($encripted_data)
向我发送解码错误,我认为这是因为编码内容没有“放气”左右。
在 PDF Reference v 1.7,(六版)的第 67 页,我发现 /FlateDecode 过滤器的描述为:...解压缩使用 zlib/deflate 压缩方法编码的数据,再现原始文本或二进制数据
我需要真正的原始解决方案,也就是 php 函数或/和算法,如何处理这个“\FlateDecoded”流。
谢谢!
【问题讨论】:
你需要这个函数只用于选定的对象还是所有压缩流(和所有压缩方案)? 亲爱的库尔特!我很高兴知道如何处理各种过滤器,例如:ASCIIHexDecode、ASCII85Decode、LZWDecode、RunLengthDecode、CCITTFaxDecode、JBIG2Decode、DCTDecode、JPXDecode、Crypt,但在现实生活中,FlateDecode 是 PDF 文件中最常用的,它是由“打印到 PDF...”-s))) 生成,现在我真的需要处理这个单一的过滤器。 你说'我认为这是因为编码的内容没有“放气”左右'。 -- 这就是为什么我在回答中给了你关于qpdf
的提示。您可以(至少)使用它来验证或伪造您自己的努力,即使事实证明它不符合您的直接要求。您的 56 0 obj
-object 也可以是任何东西。如果您不知道它在 PDF 中的哪个位置被引用为 56 0 R
,则无法知道它是 ICC 配置文件、字体、图像、某些页面内容还是其他...
亲爱的库尔特!可能是 qpdf 是 taks 的好解决方案,就像这样,但不幸的是,qpdf 是“shell”或命令行解决方案。不是我的情况。 Bitte verzeih mir! Danke für die Hinweise!
【参考方案1】:
由于您没有告诉您是只需要访问 一个 解压缩流还是需要解压所有流,所以我建议您使用一个简单的命令行工具,它可以一次性完成完整 PDF:Jay Berkenbilt 的 qpdf
。
命令行示例:
qpdf --qdf --object-streams=disable in.pdf out.pdf
然后可以在文本编辑器中检查out.pdf
(只有嵌入的 ICC 配置文件、图像和字体仍然可以是二进制的)。
qpdf
还会自动重新排序对象并以标准化方式显示 PDF 语法(并在评论中告诉您解压缩对象的原始对象 ID 是什么)。
如果您需要重新压缩文件(可能在您编辑后),只需运行以下命令:
qpdf out-edited.pdf out-recompressed.pdf
(您可能会看到一些警告消息,告诉您该实用程序正在尝试修复损坏的文件......)
qpdf
是多平台的,available from Sourceforge。
【讨论】:
如何重新压缩pdf文件,例如修改未压缩文件中的文本后? 谢谢。它重新压缩原始文件。但是,在adobe reader中打开后,出现如下错误:“此文档在Adobe Reader中启用了扩展功能。该文档自创建以来已更改,不再使用扩展功能。请联系作者获取原文本文件的版本。” PDF 表单中有可填写的字段。有没有办法在没有 Adobe Reader 的情况下修改 PDF 文件以引发上述错误?因为 Adobe 在重新压缩后禁用可填写字段。 在解压和解压文件后,输出文件与原始输入不同。两个不应该一样吗? @KemalDağ:使用 QPDF 解压缩和重新压缩所有 PDF 对象不会完全恢复原始 PDF。 QPDF 正在提供 PDF 的“内容保留” 转换。正如我所说,解压缩还“重新排序对象” 和“以标准化方式显示 PDF 语法”。重新压缩后,它不会恢复对象的原始顺序(不同的顺序不会改变页面的可见呈现内容)。 @KemalDağ:不幸的是,Adobe 的 PDF 软件使用了一些专有的“扩展功能”用于可填写的字段(这种类型的文档称为 PDF 表单 )。基本上,这些文档需要 Adobe(私有)签名密钥,因此只能由有权访问该密钥的人处理。破解和重复使用该密钥是违法的。【参考方案2】:header('Content-Type: text'); // I going to download the result of decoding
$n = "binary_file.bin"; // decoded part in file in a directory
$f = @fopen($n, "rb"); // now file is mine
$c = fread($f, filesize($n)); // now I know all about it
$u = @gzuncompress($c); // function, exactly fits for this /FlateDecode filter
$out = fopen("php://output", "wb"); // ready to output anywhere
fwrite($out, $u); // output to downloadable file
铃儿响!叮铃铃!...
gzuncompress()
- 解决方案
【讨论】:
【参考方案3】:姗姗来迟,但有人可能会觉得它有帮助。在这种情况下: > 你所需要的只是将隔离的二进制字符串(基本上是“stream”和“endstream”之间的所有内容)传递给zlib.decompress:
import zlib
stream = b"êΩnƒ ÑûbÀKq¬æ\âê" # binary stream here
data = zlib.decompress(stream) # Here you have your clean decompressed stream
但是,如果您的 PDF 对象中有 /DecodeParms,事情就会变得复杂。您将需要 /Predictor 值和列号。最好使用 PyPDF2。
【讨论】:
问题是要求PHP,这个解决方案建议使用Python。这不是一个很好的选择。无论如何,这对您来说可能是显而易见的,但对其他人来说并非如此:您需要传递stream
和 endstream
之间的所有内容除了前导和尾随 EOL 标记。【参考方案4】:
我刚用过
import de.intarsys.pdf.filter.FlateFilter;
来自 jpod / 源伪造 而且效果很好
FlateFilter filter = new FlateFilter(null);
byte[] decoded = filter.decode(bytes, start, end - start);
字节直接来自 pdf 文件
【讨论】:
以上是关于在 PHP 中从 /Filter /FlateDecode PDF 流中提取数据的主要内容,如果未能解决你的问题,请参考以下文章