在浏览器中检测PDF文件是否被锁定或加密。

4
在我的应用程序中,用户可以上传PDF文件,其他用户可以随后查看。对于我的用例,我需要确保PDF文件未被锁定或加密,并且可以被任何其他用户查看。
为此,我要求用户上传未锁定的PDF文件,并希望在尝试上传到S3之前,如果PDF文件已被锁定,则抛出错误。
我还没有找到一致的方法来实现这个功能,应该在浏览器中进行吗?我是否应该尝试读取缓冲区并在无法读取时抛出错误?或者是否有另一种高效的方法来检测PDF文件是否被锁定?

1
检测加密应该像在文件中搜索字符串“/Encrypt”一样简单。 - Thomas
那么,在文件缓冲区(或将文件读取为文本后),只需搜索“/Encrypt”?还有什么需要注意的吗? - geoboy
1
我认为“还有什么需要注意的吗?”这个问题最终会要求你更好地了解格式,或者至少是其中可能包含加密/保护标志的部分。考虑一个PDF文档,其中可见内容包括文本“/ Encrypt”。除非您使用文件格式的完整上下文进行解析,否则可能会得到错误的匹配,例如,“/ Encrypt”必须出现在文件开头的特定部分内。 https://en.wikipedia.org/wiki/Portable_Document_Format - Erik Hermansen
3个回答

2

为了用户体验、带宽和性能的考虑,最好在客户端检测状态。您可以在页面上放置一个文件输入元素,并捕获onChange事件。

<input type="file" id="pdfFile" size="50" onChange='processFile' />

在onChange处理函数内部,您可以获取文件字节并加载到缓冲区中。有关代码和更多详细信息,请参见在各种浏览器中使用JavaScript客户端读取文件内容

您需要进行一些PDF解析以了解锁定/加密状态,但我想可能有JS库可以做到这一点。即使您要解析非常大的PDF文件,它始终比将PDF上传到服务器快,因为上传时间将是文件大小的函数。

以下是需要上传文件而不是客户端解析的情况:

  • 您的目标是较低端移动设备,并且希望使用+100mb的PDF。
  • 您将在具有Javascript限制的浏览器上运行
  • 即使PDF受保护,您也总是希望将文件上传到您的服务器,并且您已经确定用户体验更好

这更符合我的想法,但我卡在了如何在使用FileReader对象读取文件时了解其锁定/加密状态。你有什么想法吗? - geoboy
我不是PDF格式的专家,所以在这里不会说太多。我建议你可以通过谷歌搜索“js pdf parser”并开始查看相关库。或者,你也可以获取一组PDF样本,学习一下格式,并自己编写一个快速而简单的解析器。第二种方法更加高效,因为你可以将解析器专门用于查找所需文本,而不是处理所有内容。 - Erik Hermansen

2
您可以尝试使用以下解决方案:
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function () {

var files = new Blob([reader.result], {type: 'application/pdf'});
files.text().then(x=> {
    console.log("isEncrypted", x.includes("Encrypt")) // true, if Encrypted
    console.log("isEncrypted", x.substring(x.lastIndexOf("<<"), x.lastIndexOf(">>")).includes("/Encrypt"));
    console.log(file.name);
});

如果是只读密码保护的文件,它的工作正常,但如果是编辑密码保护的文件,就会显示错误。我们需要区分只读密码保护和编辑密码保护的文件的差异。 - undefined

1
你可以使用pdfjs打开pdf文件并尝试获取页面数量。当文件受密码保护时,会出现PasswordException异常。
请查看此示例: https://jsfiddle.net/fe6jLgr5/15/
document.getElementById("pdfFile").addEventListener("change",
   function(event) {
      let file = event.target.files[0];
      let reader = new FileReader();
      reader.readAsArrayBuffer(file);
      reader.onload = function(e) {
         var docInitParams = {
         data: e.target.result,
         password: ''
      };
      pdfjsLib.getDocument(docInitParams).promise.then((pdfDocument) =>
      {
         // get all the pages from pdf, works if not password protected.
         const numPages = pdfDocument.numPages;
         console.log('Doc not password protected');
      }).catch(err => console.log(err))
   }
},false);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接