如何在php中填写PDF表单

30

我有许多PDF表格,我需要使用已有的数据在php中填写每一个表格。

这是一个样例PDF表格,我想使用php填写这个表格。我已经在数据库中拥有所需的数据,只需要填写并保存该表格。

我正在使用PHP Zend框架。

我的目标是在从网站上下载这些表格时,让所有字段都预先填充为我已有的信息。

请帮助我。

4个回答

41

调用 pdftk 是一个不错的方法来实现这个。我假设你知道如何 执行外部程序 并略过此步骤。

首先,从你的PDF文件创建一个 FDF 文件。

pdftk form.pdf generate_fdf output data.fdf

你现在可以将其用作模板。您提供的示例如下所示:
%FDF-1.2
%<E2><E3><CF><D3>
1 0 obj 
<<
/FDF 
<<
/Fields [
<<
/V ()
/T (Date)
>> 
<<
/V /
/T (CheckBox2)
>> 
<<
/V /
/T (CheckBox3)
>> 
<<
/V /
/T (CheckBox4)
>> 
<<
/V /
/T (CheckBox5)
>> 
<<
/V ()
/T (Your_Last_Name)
>> 
<<
/V ()
/T (Your_First_Name)
>> 
<<
/V /
/T (CheckBox1)
>>]
>>
>>
endobj 
trailer

<<
/Root 1 0 R
>>
%%EOF

这些字段是以/V ()开头的行。在这些字段中输入您想要的值。例如:

%FDF-1.2
%<E2><E3><CF><D3>
1 0 obj 
<<
/FDF 
<<
/Fields [
<<
/V (February 4, 2012)
/T (Date)
...

最后,将FDF与PDF合并。执行如下命令:
pdftk form.pdf fill_form data.fdf output form_with_data.pdf

如果您不需要保留FDF和生成的PDF文件,您可以通过标准输入和输出来传输数据,而不是使用临时文件。

@RichardAyotte 这是个好发现 :) 我需要做完全相同的事情,但有一个小变化。我还需要在其中一个表单字段中包含一张图片。我该怎么做呢? - David Sarmiento
我还没有处理图片,但是找到了这个解释它的帖子。http://forums.adobe.com/thread/1156035。我现在没有时间更新答案。 - Richard Ayotte
如果您要从头开始生成FDF,请注意要从输入中转义括号()和反斜杠\\。有很多PHP库可以为您处理,比如这个https://github.com/admonkey/php-fdf。 - Jeff Puckett
你能给一个关于如何处理 .pdf.fdf 文件的例子吗? 目前我使用 passthru('pdftk file.pdf fill_form file.xdfd output - flatten');,但是我想要避免在磁盘上留下这两个文件。 - luckydonald
1
在 FDF 格式中“勾选”复选框,请使用 /V /Yes - Jay Dadhania
显示剩余5条评论

19

我找到了这个方法并且对我有用。它是一个非官方的修补程序,可以填充FDF表单字段的Zend。讨论和修补程序的网站

无需安装、无需外部程序、无需坐标。

使用方法:

$pdf = Zend_Pdf::load('input-file-containing-form.pdf');
$pdf->setTextField('name', 'Someone');
$pdf->setTextField('address', '1 Main Street');
$pdf->setTextField('city', 'Cyberspace');
$pdf->save('outputfile.pdf');

如果页面不存在,这里是PDF.php的补丁(如果有人遇到问题,请私信联系我):
--- Pdf.php.orig    2009-11-15 17:52:57.000000000 +0100
+++ Pdf.php 2010-01-07 04:05:23.000000000 +0100
@@ -202,6 +202,13 @@
      * @var array
      */
     protected static $_inheritableAttributes = array('Resources', 'MediaBox', 'CropBox', 'Rotate');
+    
+    /**
+     * List of form fields
+     *
+     * @var array - Associative array, key: name of form field, value: Zend_Pdf_Element
+     */
+    protected $_formFields = array();

     /**
      * Request used memory manager
@@ -315,6 +322,7 @@

             $this->_loadNamedDestinations($this->_trailer->Root, $this->_parser->getPDFVersion());
             $this->_loadOutlines($this->_trailer->Root);
+            $this->_loadFormfields($this->_trailer->Root);

             if ($this->_trailer->Info !== null) {
                 $this->properties = $this->_trailer->Info->toPhp();
@@ -557,6 +565,61 @@
             $this->_originalOpenOutlinesCount = $root->Outlines->Count->value;
         }
     }
+    
+    /**
+     * Load form fields
+     * Populates the _formFields array, for later lookup of fields by name
+     *
+     * @param Zend_Pdf_Element_Reference $root Document catalog entry
+     */
+    protected function _loadFormFields(Zend_Pdf_Element_Reference $root)
+    {
+      if ($root->AcroForm === null || $root->AcroForm->Fields === null) {
+        return;
+      }
+      
+      foreach ($root->AcroForm->Fields->items as $field)
+      {
+          if ( $field->FT->value == 'Tx' && $field->T !== null ) /* We only support fields that are textfields and have a name */
+          {
+              $this->_formFields[$field->T->value] = $field;
+          }
+      }
+      
+      if ( !$root->AcroForm->NeedAppearances || !$root->AcroForm->NeedAppearances->value )
+      {
+        /* Ask the .pdf viewer to generate its own appearance data, so we do not have to */
+        $root->AcroForm->add(new Zend_Pdf_Element_Name('NeedAppearances'), new Zend_Pdf_Element_Boolean(true) );
+        $root->AcroForm->touch();
+      }
+    }
+    
+    /**
+     * Retrieves a list with the names of the AcroForm textfields in the PDF
+     *
+     * @return array of strings
+     */
+    public function getTextFieldNames()
+    {
+      return array_keys($this->_formFields);
+    }
+    
+    /**
+     * Sets the value of an AcroForm text field
+     *
+     * @param string $name Name of textfield
+     * @param string $value Value
+     * @throws Zend_Pdf_Exception if the textfield does not exist in the pdf
+     */
+    public function setTextField($name, $value)
+    {
+      if ( !isset($this->_formFields[$name]))
+        throw new Zend_Pdf_Exception("Field '$name' does not exist or is not a textfield");
+      
+      $field = $this->_formFields[$name];
+      $field->add(new Zend_Pdf_Element_Name('V'), new Zend_Pdf_Element_String($value) );
+      $field->touch();      
+    }

     /**
      * Orginize pages to tha pages tree structure.

4
谢谢,这比安装额外的软件好多了。不过我还是有点难以相信这个补丁从未被纳入Zend Framework。 - Steve Hill
我刚刚下载了Zend框架,补丁已经在里面了...所以现在不需要打补丁了。 - Gonzalo Brusco
1
@GonzaloBrusco 这是在完整的包中还是只有来自Github的Zend PDF库?我希望仅使用zend pdf来完成一个项目,但看起来有太多的zend依赖关系,它几乎无法单独使用。从我所看到的情况来看,绝对没有任何这方面的代码。 - Jestep
6
我在这里找到了它:https://github.com/zf1/zend-pdf。它可以直接使用,修补程序已经包含在代码中。只需使用Composer安装它和4个必需的Zend依赖项即可轻松安装-运行 composer require zf1/zend-pdf 并将 require_once '<path to Composer's vendor dir>/autoload.php'; 添加到需要使用PDF功能的文件中。 - Jan Żankowski

14
我在网上搜索时发现了fpdf库。 http://www.fpdf.org/en/script/script93.php 代码看起来整洁简单,易于使用和记忆,并且适用于带有表单(可填写)的PDF。
<?php

/***************************
  Sample using a PHP array
****************************/

require('fpdm.php');

$fields = array(
    'name'    => 'My name',
    'address' => 'My address',
    'city'    => 'My city',
    'phone'   => 'My phone number'
);

$pdf = new FPDM('template.pdf');
$pdf->Load($fields, false); // second parameter: false if field values are in ISO-8859-1, true if UTF-8
$pdf->Merge();
$pdf->Output();
?>

这个例子可以直接使用,希望它能够对你有所帮助。


1
我甚至使用它来仅使用from_template函数连接pdf页面,并能够打印150页文档而不是150个1页文件。有些系统不允许您选择150个文件然后打印它们。上次我在ie: Windows中看到这种情况时,我注意到我只能选择最多15个...很奇怪。我曾经使用宏记录器打印它们所有,但最终使用fpdf连接它们更加高效、干净且不容易出错。问候。 - m3nda
3
请确认这种方法可行。根据网站的说明,如果你的PDF是较新版本,只需执行“pdftk modele.pdf output modele2.pdf”就可以了。 - Ivan
6
有人接手了这个项目,现在正在这里进行更新:https://github.com/codeshell/fpdm - cesAR
@cesAR Fpdm允许您使用可填写表单,但不是fpdf的替代品,并且不会公开pdf的所有功能(例如Cell等)。它仅适用于具有表单的pdf。要在fpdf中使用模板,您需要fpdi。我发现较新版本的fpdi无法使用,因此在我的项目中仍在使用旧版本。 - m3nda
它不支持PDF中相当常见的ObjStm对象流。 - Sumit Wadhwa
显示剩余2条评论

2

Zend_Pdf组件可以在您的pdf中绘制文本,但是它有些笨拙,因为您必须指定pdf页面上的x和y坐标。就像这样:

// This is the pdf-file you want to fill out...
$pdf = Zend_Pdf::load('/path/to/pdf-template.pdf')
$page = $pdf->pages[0]; // Use first page
$page->drawText("firstname lastname", 200, 600);
...
$pdf->pages[0] = $page;
// be sure to write to a new file, not the original empty  form.
$pdf->save('/path/to/pdf-output.pdf');

我不知道是否有简单的方法来找到精确的坐标,通常我会试着调整直到它符合要求。


但是这并不适用于填充PDF表单,这肯定适用于扁平的PDF,但不适用于可填写的PDF表单。 - Sohail
我知道,应该提到这一点。但据我所知,这是使用Zend_Pdf将文本放入pdf的唯一方法。 - dbrumann

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