Zend_Pdf манипулирует полями форм PDF - PullRequest
4 голосов
/ 28 сентября 2010

У меня сейчас есть проект, есть ряд форм, которые обрабатываются и хранятся в БД.После успешного завершения администратор уведомляется по электронной почте с содержанием этой формы.

Проблема в том, что для одной из этих форм мне нужно, чтобы она выглядела точно так же, как версия почтового заказа, которая у меня есть в формате PDF.

Итак, у меня есть два основных варианта:

  1. Определите все координаты "поля", в которое мне нужно записать, а затем наложите мой нарисованный текст на эти координаты
  2. Превратите PDF в форму PDF с помощью мастера форм Acrobat Pro, а затем установитезначения полей программно

Вариант 1, который я знаю, выполним.Я делал подобные вещи раньше.Проблема в том, что форма довольно сложна, и есть МНОГО координат, которые нужно выяснить ... Более того, в этом процессе много проб и ошибок.

Вариант 2 выглядит так, как будто это будет прощеПока я могу получить доступ к полям с помощью итерации или name / id и просто установить значения.

Итак, мой вопрос: поддерживает ли Zend_Pdf манипулирование полями формы PDF?Я не вижу в API ничего, кроме действий формы Submit и Reset, которые бы обозначали его, поддерживает это.

Кроме того, если есть другие библиотеки PDF OO F / OSS, которые поддерживают опцию 2, мне было бы интересно услышатьо них, а также о любых альтернативных подходах.

Ответы [ 2 ]

4 голосов
/ 03 октября 2013

prodigitalson, я хотел опубликовать это решение для вас, на случай, если вам все еще будет интересно узнать ответ. Он работает только на PDF, оптимизированном для версии 1.5 (Acrobat 6.0), но работает прекрасно. Это неофициальный патч для Zend Framework 1.12.3 для заполнения полей формы PDF. Сайт с обсуждением и патчем

НЕТ УСТАНОВКИ, НЕТ ВНЕШНИХ ПРОГРАММ, НЕТ КООРДИНАТ

Сначала обновите ваш файл php.ini следующим образом (примечание: мне нужно будет изменить мой файл .ini на моем реальном веб-сервере при загрузке этих изменений):

include_path = ".;C:\wamp\www\includes"

Просто примечание: я переместил все содержимое библиотеки из папки 'ZendFramework-1.12.3 \ library' в папку с именем Zend: C:\wamp\www\includes\Zend просто для удобства обращения к библиотеке (это все, что вам нужно в любом случае) ).

Затем в вашем php-файле (я использовал 'DIRECTORY_SEPARATOR', чтобы вы могли использовать его на Win или Unix-сервере, и мне не нужно вносить какие-либо изменения кода в зависимости от того, где находится мой .php-файл, я буду нужно только внести изменения в конфигурацию сервера):

require_once('Zend'.DIRECTORY_SEPARATOR.'Loader'.DIRECTORY_SEPARATOR.'Autoloader.php');
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace('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, чтобы он не забивал мой сервер: attach_mailer_class.php доступно здесь Copyright (c) 2006, Olaf Lederer):

// Write $_POST form data to associative array
foreach ($_POST as $key => $value) { 
    $NameArray[$key] = $value;
}

// Path to PDF application fillable file
$pdf_path = dirname(__FILE__) . "\\docs";
$pdf_filename = 'employment_applicationJBzend.pdf';
$pdf_file_path = $pdf_path . "\\" . $pdf_filename;

// Path to PDF application file save location
$result_path = dirname(__FILE__) . "\\results";
$result_filename = ucfirst($_POST['first_name']) . ucfirst($_POST['last_name']) . $filedatetime . '.pdf';
$result_file_path = $result_path . "\\" . $result_filename;

//Filling PDF fields | Example: $pdf->setTextField('position_applied_for', 'IT Manager');
$pdf = Zend_Pdf::load($pdf_file_path);

foreach ($NameArray as $key1 => $value) {
    foreach($ExceptionArray as $key2 => $value)
    {
        if($key1 == $ExceptionArray[$key2]){
            $boolSetText = false;
            break;
        }else{
            $boolSetText = true;
        }
    }
    if($boolSetText){
        $pdf->setTextField($key1, $NameArray[$key1]); 
    }
}
$pdf->save($result_file_path);

//Create and send message using 'attach_mailer_class.php
$email = new attach_mailer($from_name, $from_mail, $mail_to, $cc = "", $bcc = "", $subject);
$email->text_body = $message;
$email->add_attach_file($result_file_path);
// $email->add_attach_file("ip2nation.zip"); 
$email->process_mail();
unlink($result_file_path);

Если страница больше не существует, это патч для PDF.php (который, если вы не знаете, как запустить реальный патч, в основном вы просматриваете файл PDF.php и заменяете все строки, которые ниже, имеют «+» перед ними. Вы можете найти их местоположение с помощью тега местоположения «@@ -202,6 +202,13 @@», который находится около строки 200, а затем просто скопируйте и вставьте, чтобы заменить старый код на новый):

--- 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.
2 голосов
/ 07 июля 2011

Извините, это немного поздно, но я подумал, что это может быть полезно ...

Если у вас есть доступ для добавления дополнительных компонентов на ваш сервер, вы можете использовать библиотеку PDF Labs PDF Tooklit (pdftk) - этоутилита командной строки, но она, очевидно, может быть доступна с помощью команд system / exec / passthru в PHP.Вы можете увидеть информацию pdftk здесь: http://www.pdflabs.com/docs/pdftk-man-page/ PDFTK позволит вам объединять PDF-файлы, добавлять фоновые PDF-файлы и заполнять поля формы в PDF-файле (плюс загружать больше) - см. Переключатель fill_form.

Если выможете добавить pdftk на ваш сервер, затем вы также можете использовать класс pdftk-php Эндрю Хейсса, чтобы упростить обновление полей формы в вашем pdf из информации, извлеченной из вашей БД - вы можете увидеть больше информации по адресу: https://github.com/andrewheiss/pdftk-php/

Последний комментарий - если вы когда-нибудь захотите создавать PDF-файлы на лету прямо из HTML, то лучшим решением на данный момент является WKHTML2PDF - http://code.google.com/p/wkhtmltopdf/ - он в основном работает как скриншот PDF любого экрана HTML (немного сложнее, чем это, но вы поняли).

Как вы, вероятно, можете сказать, я только что работал над очень похожей проблемой и прошел очень много головных болей, чтобы получить рабочее решение.

...