From 655583f7f3d257ecef556883fb3629242bf492bc Mon Sep 17 00:00:00 2001 From: Kevin Kaland <kevin@wizonesolutions.com> Date: Thu, 19 Nov 2015 22:22:46 +0100 Subject: [PATCH] Issue #2359213: Implement other backends. --- lib/JavaBridge | 1 + .../FillPdfBackend/LocalFillPdfBackend.php | 108 +++++++++++++ .../FillPdfBackend/PdftkFillPdfBackend.php | 147 ++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 120000 lib/JavaBridge create mode 100644 src/Plugin/FillPdfBackend/LocalFillPdfBackend.php create mode 100644 src/Plugin/FillPdfBackend/PdftkFillPdfBackend.php diff --git a/lib/JavaBridge b/lib/JavaBridge new file mode 120000 index 0000000..92e195d --- /dev/null +++ b/lib/JavaBridge @@ -0,0 +1 @@ +/var/lib/tomcat6/webapps/JavaBridge \ No newline at end of file diff --git a/src/Plugin/FillPdfBackend/LocalFillPdfBackend.php b/src/Plugin/FillPdfBackend/LocalFillPdfBackend.php new file mode 100644 index 0000000..ae59ef0 --- /dev/null +++ b/src/Plugin/FillPdfBackend/LocalFillPdfBackend.php @@ -0,0 +1,108 @@ +<?php +/** + * @file + * Contains \Drupal\fillpdf\Plugin\FillPdfBackend\LocalFillPdfBackend. + */ + +namespace Drupal\fillpdf\Plugin\FillPdfBackend; + +use Drupal\Component\Annotation\Plugin; +use Drupal\Component\Render\FormattableMarkup; +use Drupal\Core\Annotation\Translation; +use Drupal\Core\File\FileSystem; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\file\Entity\File; +use Drupal\file\FileInterface; +use Drupal\fillpdf\FillPdfBackendPluginInterface; +use Drupal\fillpdf\FillPdfFormInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * @Plugin( + * id = "local", + * label = @Translation("Locally-installed PHP/JavaBridge") + * ) + */ +class LocalFillPdfBackend implements FillPdfBackendPluginInterface, ContainerFactoryPluginInterface { + /** @var array $configuration */ + protected $configuration; + + /** @var \Drupal\Core\File\FileSystem */ + protected $fileSystem; + + public function __construct(FileSystem $file_system, array $configuration, $plugin_id, $plugin_definition) { + $this->configuration = $configuration; + $this->fileSystem = $file_system; + } + + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static($container->get('file_system'), $configuration, $plugin_id, $plugin_definition); + } + + /** + * @inheritdoc + */ + public function parse(FillPdfFormInterface $fillpdf_form) { + /** @var FileInterface $file */ + $file = File::load($fillpdf_form->file->target_id); + $content = file_get_contents($file->getFileUri()); + + $require = drupal_get_path('module', 'fillpdf') . '/lib/JavaBridge/java/Java.inc'; + require_once DRUPAL_ROOT . '/' . $require; + try { + $fillpdf = new \java('com.ocdevel.FillpdfService', base64_encode($content), 'bytes'); + $fields = java_values($fillpdf->parse()); + } + catch (\JavaException $e) { + drupal_set_message(java_truncate((string) $e), 'error'); + } + + return $fields; + } + + /** + * @inheritdoc + */ + public function populateWithFieldData(FillPdfFormInterface $pdf_form, array $field_mapping, array $context) { + /** @var FileInterface $original_file */ + $original_file = File::load($pdf_form->file->target_id); + $pdf_data = file_get_contents($original_file->getFileUri()); + $fields = $field_mapping['fields']; + + $require = drupal_get_path('module', 'fillpdf') . '/lib/JavaBridge/java/Java.inc'; + require_once DRUPAL_ROOT . '/' . $require; + try { + $fillpdf = new \java('com.ocdevel.FillpdfService', base64_encode($pdf_data), 'bytes'); + foreach ($fields as $key => $field) { + if (substr($field, 0, 7) == '{image}') { + // Remove {image} marker. + $image_filepath = substr($field, 7); + $image_realpath = $this->fileSystem->realpath($image_filepath); + $fillpdf->image($key, $image_realpath, 'file'); + } + else { + $fillpdf->text($key, $field); + } + } + } + catch (\JavaException $e) { + drupal_set_message(java_truncate((string) $e), 'error'); + return NULL; + } + try { + if ($context['flatten']) { + $populated_pdf = java_values(base64_decode($fillpdf->toByteArray())); + } + else { + $populated_pdf = java_values(base64_decode($fillpdf->toByteArrayUnflattened())); + } + } + catch (\JavaException $e) { + drupal_set_message(java_truncate((string) $e), 'error'); + return NULL; + } + + return $populated_pdf; + } + +} diff --git a/src/Plugin/FillPdfBackend/PdftkFillPdfBackend.php b/src/Plugin/FillPdfBackend/PdftkFillPdfBackend.php new file mode 100644 index 0000000..e5a7cd9 --- /dev/null +++ b/src/Plugin/FillPdfBackend/PdftkFillPdfBackend.php @@ -0,0 +1,147 @@ +<?php +/** + * @file + * Contains \Drupal\fillpdf\Plugin\FillPdfBackend\PdftkFillPdfBackend. + */ + +namespace Drupal\fillpdf\Plugin\FillPdfBackend; + +use Drupal\Component\Annotation\Plugin; +use Drupal\Component\Render\FormattableMarkup; +use Drupal\Core\Annotation\Translation; +use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\File\FileSystem; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\file\Entity\File; +use Drupal\file\FileInterface; +use Drupal\fillpdf\Component\Utility\FillPdf; +use Drupal\fillpdf\FillPdfBackendPluginInterface; +use Drupal\fillpdf\FillPdfFormInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * @Plugin( + * id = "pdftk", + * label = @Translation("PDFtk"), + * ) + */ +class PdftkFillPdfBackend implements FillPdfBackendPluginInterface, ContainerFactoryPluginInterface { + + use StringTranslationTrait; + + /** @var array $configuration */ + protected $configuration; + + /** @var \Drupal\Core\File\FileSystem */ + protected $fileSystem; + + /** @var \Drupal\Core\Config\ConfigFactoryInterface */ + protected $configFactory; + + public function __construct(FileSystem $file_system, ConfigFactoryInterface $config, array $configuration, $plugin_id, $plugin_definition) { + $this->configuration = $configuration; + $this->fileSystem = $file_system; + $this->configFactory = $config; + } + + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static($container->get('file_system'), $container->get('config.factory'), $configuration, $plugin_id, $plugin_definition); + } + + /** + * @inheritdoc + */ + public function parse(FillPdfFormInterface $fillpdf_form) { + /** @var FileInterface $file */ + $file = File::load($fillpdf_form->file->target_id); + $filename = $file->getFileUri(); + + $path_to_pdftk = $this->getPdftkPath(); + $status = FillPdf::checkPdftkPath($path_to_pdftk); + if ($status === FALSE) { + drupal_set_message($this->t('pdftk not properly installed.'), 'error'); + return []; + } + + // Use exec() to call pdftk (because it will be easier to go line-by-line parsing the output) and pass $content via stdin. Retrieve the fields with dump_data_fields. + $output = []; + exec($path_to_pdftk . ' ' . escapeshellarg($this->fileSystem->realpath($filename)) . ' dump_data_fields', $output, $status); + if (count($output) === 0) { + drupal_set_message($this->t('PDF does not contain fillable fields.'), 'warning'); + return []; + } + + // Build a simple map of dump_data_fields keys to our own array keys + $data_fields_map = [ + 'FieldType' => 'type', + 'FieldName' => 'name', + 'FieldFlags' => 'flags', + 'FieldJustification' => 'justification', + ]; + + // Build the fields array + $fields = []; + $fieldindex = -1; + foreach ($output as $line => $lineitem) { + if ($lineitem == '---') { + $fieldindex++; + continue; + } + // Separate the data key from the data value + $linedata = explode(':', $lineitem); + if (in_array($linedata[0], array_keys($data_fields_map), NULL)) { + $fields[$fieldindex][$data_fields_map[$linedata[0]]] = trim($linedata[1]); + } + } + + return $fields; + } + + /** + * @return array|mixed|null|string + */ + protected function getPdftkPath() { + $path_to_pdftk = $this->configFactory->get('fillpdf.settings') + ->get('pdftk_path'); + + if (empty($path_to_pdftk)) { + $path_to_pdftk = 'pdftk'; + return $path_to_pdftk; + } + return $path_to_pdftk; + } + + /** + * @inheritdoc + */ + public function populateWithFieldData(FillPdfFormInterface $pdf_form, array $field_mapping, array $context) { + /** @var FileInterface $original_file */ + $original_file = File::load($pdf_form->file->target_id); + $filename = $original_file->getFileUri(); + $fields = $field_mapping['fields']; + + module_load_include('inc', 'fillpdf', 'xfdf'); + $xfdfname = $filename . '.xfdf'; + $xfdf = create_xfdf(basename($xfdfname), $fields); + // Generate the file + $xfdffile = file_save_data($xfdf, $xfdfname, FILE_EXISTS_RENAME); + + // Now feed this to pdftk and save the result to a variable + $path_to_pdftk = $this->getPdftkPath(); + ob_start(); + passthru($path_to_pdftk . ' ' . escapeshellarg($this->fileSystem->realpath($filename)) . ' fill_form ' . escapeshellarg($this->fileSystem->realpath($xfdffile->getFileUri())) . ' output - ' . ($context['flatten'] ? 'flatten ' : '') . 'drop_xfa'); + $data = ob_get_clean(); + if ($data === FALSE) { + drupal_set_message($this->t('pdftk not properly installed. No PDF generated.'), 'error'); + } + $xfdffile->delete(); + + if ($data) { + return $data; + } + + return FALSE; + } + +} -- GitLab