将跟踪代码嵌入PDF或PostScript文件中

9

有没有一种方法可以跟踪PDF何时被打开?也许通过将一些脚本嵌入到PDF中?

我看到下面的问题,我想javascript的答案是“不可能”,但我想知道这是否有可能。

在PDF文件中插入Google分析跟踪代码

3个回答

17

PDF标准包含对JavaScript的支持,但正如@Wes Hardaker所指出的那样,并非每个PDF阅读器都支持它。然而,有时候一些支持总比没有好。

这里是Adobe官方的Acrobat JavaScript Scripting Guide。对你来说可能最有趣的是doc对象,它具有一个名为getURL()的方法。要使用它,只需调用:

app.doc.getURL('http://www.google.com/');

将该事件绑定到文档的打开事件,就可以获得跟踪器。我不太熟悉如何在Adobe Acrobat中创建事件,但从代码方面来说很容易。下面的代码是一个完整的工作中的VS2010 C# WinForms应用程序,它使用开源库iTextSharp(5.1.1.0)创建PDF,并将JavaScript添加到打开事件中。

一些注意事项:Adobe Acrobat 和 Reader 在文档访问外部资源时都会警告用户。大多数其他PDF阅读器可能也会这样做。这非常令人恼火,因此至少出于这个原因不应该这样做。个人来说,我不介意别人跟踪我的文档打开情况,我只是不想每次都弹出提示窗口。其次,再次强调,此代码适用于 Adobe Acrobat 和 Adobe Reader,可能可以追溯到至少V6,但在其他PDF阅读器中可能有效也可能无效。第三,没有安全的方法来唯一地识别用户。这将需要您创建和存储某种等效的“cookie”,这需要将数据写入用户的文件系统,这被认为是不安全的。这意味着您只能检测打开次数,而不是唯一打开次数。第四,这可能在某些地方是非法的。一些司法管辖区要求您在跟踪用户时通知他们,并提供一种查看您收集了什么信息的方式。

但是,尽管我不喜欢它,我不能不给出答案。

using System;
using System.Text;
using System.Windows.Forms;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //File that we will create
            string OutputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Events.pdf");

            //Standard PDF creation setup
            using (FileStream fs = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                using (Document doc = new Document(PageSize.LETTER))
                {
                    using (PdfWriter writer = PdfWriter.GetInstance(doc, fs))
                    {
                        //Open our document for writing
                        doc.Open();

                        //Create an action that points to the built-in app.doc object and calls the getURL method on it
                        PdfAction act = PdfAction.JavaScript("app.doc.getURL('http://www.google.com/');", writer);

                        //Set that action as the documents open action
                        writer.SetOpenAction(act);

                        //We need to add some content to this PDF to be valid
                        doc.Add(new Paragraph("Hello"));

                        //Close the document
                        doc.Close();
                    }
                }
            }

            this.Close();
        }
    }
}

1
哇,这就是我期望的答案却没想到的。谢谢! - speedplane

2
像这样的技术问题是无法完全解决的。首先,触发外部事件是一种安全漏洞,软件编写者可能不会支持它(或者,至少我希望不会)。其次,它依赖于网络等事物。例如,当有人在飞机上离线下载并阅读时,会发生什么?你将无法收到通知。第三,有多种方法可以阅读PDF文件。有些人使用你可能从未听说过的阅读器(我的最爱是一个Linux应用程序,我比Adobe的AcroRead更喜欢它)。所以即使您能够做到这一点(我认为您不应该这样做,但这并没有回答您的问题),真正的答案是“不行”,即使软件支持它,它仍然不可靠。

1
显然,任何类型的跟踪都存在隐私和可靠性方面的问题。我不会争辩这一点。但是你为什么说“真正的答案是否定的”呢?新的PDF文件不是具有动态内容吗?我认为它们具有某种脚本功能,可能支持这样的操作。 - speedplane
1
并非所有的阅读器都支持PDF文件的所有内容。正如Wes所指出的那样,仅仅因为你可以在Acrobat中做某些事情,并不意味着它会在Foxit、Ghostscript、MuPDF等其他阅读器中起作用。 - KenS
“不支持”是因为,尽管我承认我不是真正的PDF或PS专家,但当前PDF语言的支持提供查询外部实体的支持(即,您不能说“从这个远程网站获取此像素图像,以便我可以跟踪您”)。 PDF文件应该是自包含的设计。 - Wes Hardaker

0

鉴于PostScript是一种完全有能力的编程语言,没有任何理由不可能跟踪它何时被查看/运行。

我认为其中困难的部分在于找到库(或自己制作函数)来执行日志记录的网络部分。

然而,关于这样的功能,有一个快速的提示,最好让失败后仍然可以访问;原因是当媒体突然变得不可用时,人们往往会感到沮丧,这正是如果强制终止失败会发生的情况。(您能保证您的日志域永远不会改变吗?它将始终可用吗?如果用户的网络不可用怎么办?)


问题是关于PDF的,而你的回答是关于PostScript的。PostScript实际上可以在PDF中运行吗?你有没有更多关于它们关系的信息来源? - Sjoerd
1
(a) 标题明确提到了PostScript,(b) PostScript和PDF之间的关系本质上是PDF是通过其处理/程序运行的PS的结果;这个在stackexchange上的帖子真的很有启发性:https://tex.stackexchange.com/questions/217511/why-do-people-still-use-postscript - Shark8

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