From 3355da2fa912daea81d78ab7956052b6e8212913 Mon Sep 17 00:00:00 2001 From: WizOne Solutions <wizonesolutions@739994.no-reply.drupal.org> Date: Thu, 13 Jan 2011 21:19:23 +0000 Subject: [PATCH] [#841502 wizonesolutions] Initial Drupal 7 port. Thanks Coder Upgrade. --- README.txt | 61 ++- fillpdf.admin.inc | 695 ++++++++++++++++++++++++++++++++ fillpdf.info | 22 +- fillpdf.module | 960 +++++++++++++++++++++++---------------------- webform_tokens.inc | 147 +++++++ xfdf.inc | 50 +-- 6 files changed, 1432 insertions(+), 503 deletions(-) create mode 100644 fillpdf.admin.inc create mode 100644 webform_tokens.inc diff --git a/README.txt b/README.txt index 1b21d86..2ceb688 100644 --- a/README.txt +++ b/README.txt @@ -1 +1,60 @@ -http://drupal.org/node/369990 \ No newline at end of file +Installation +------------ + +This module requires one of several external PDF manipulation tools. You can: + + 1. Deploy locally -- You'll need VPS or a dedicated server so you can deploy PHP/JavaBridge on Tomcat (see later section), or + 2. Sign up for Fillpdf as-a-service [1], and plug your API key into /admin/settings/fillpdf + 3. Install pdftk on your server and have that be used for PDF manipulation + +Usage +----- + +There are three steps to setting up a form with Fill PDF: (1) creating the webform/content-type, (2) mapping it to the PDF, (3) using a URL to merge the two. + + 1. To create the webform/content-type wherein users will enter data. Options: + * Use CCK + * Use webform (see #374121: Webform Support) + + 2. To map the webform to a PDF, do the following: + 1. Go to /admin/content/fillpdf + 2. Upload a PDF template, a form mapping will be generated [2] + 3. When editing fields, note the following: + * "Label" is for your own use in identifying fields + * "PDF Key" is the field-name from the original PDF Form (such as text_field_1) and is the piece that maps the form-field to the PDF field + * "Value" is where you either enter static data to populate the field, or token-data to pull information form the users' forms. For example, if I created a CCK form with a text-field called field_first_name, then I would enter [field-field_first_name-raw] here. There is a list of tokens you can use at the bottom of that page. + + 3. Once your user fills a form, they'll need a link to download their PDF. You can place this link in a block, .tpl.php, or anywhere. + The link will need (1) The form-id (you can see an example URL on your form's edit-page), (2) the node-id, and/or (3) the webform's node-id and optionally its submission-id (defaults to latest-submission if none provided) + Here are some ways to generate the link: + * Add the link in PHP (recommended). Examples: + * One-node link: <?php echo l("PDF", fillpdf_pdf_link($form_id = 1, $node_id = 2)); ?> + * One-webform link (common): <?php echo l("PDF", fillpdf_pdf_link($form_id = 1, null, $webform = array('nid'=>3,'sid'=>4))); ?> + * Multiple nodes & webforms, later nids override conflicting fields (note: webforms without 'sid' default to latest submission) + <?php echo l("PDF", fillpdf_pdf_link($form_id = 1, $nids = array(1,2), $webforms = array( array('nid'=>3,'sid'=>1), array('nid'=>3))); ?> + * Add the link manually in HTML. Examples: + * One-node link: <a href="/fillpdf&fid=1&nid=2">PDF</a> [3] + * One-webform link: <a href="/fillpdf&fid=1&webform[nid]=3&webform[sid]=4">PDF</a> + * Multiple nodes & webforms, later nids override conflicting fields (note: webforms without 'sid' default to latest submission) + <a href="/fillpdf&fid=1&nids[]=1&nids[]=2&webforms[0][nid]=3&webforms[0][sid]=1&webforms[1][nid]=3">PDF</a> + +Notes: + [1] http://fillpdf-service.com + [2] Make sure the PDF document isn't encrypted. If it is encrypted and non copy-righted (typical of government PDFs), then try a decrypting tool like "Advanced PDF Password Recovery". If you upload an encrypted PDF, you will have empty PDFs when you attempt to download your submissions. + [3] If clean URLs is not enabled, the URL will be in the format: /?q=fillpdf&fid=10&nid=10 + + +Local Tomcat setup (optional) +----------------------------- +If you have a VPS or dedicated server and you'd rather install the iText service locally than use Fillpdf as-a-service, follow these instructions: + + 1. Install Tomcat (or any Java Servlet Container). Some pointers, if installing Tomcat on Ubuntu 9.10, webapps seem to not deploy without setting TOMCAT6_SECURITY=no in /etc/default/tomcat6. Tell me if you find an alternative. + 2. Install PHP/Java-bridge on your same Drupal server by deploying the JavaBridge.war on Tomcat: http://php-java-bridge.sourceforge.net/pjb/installation.php. Click the "Download" link, which downloads the documentation/examples -- just extract JavaBridge.war + 3. Download latest iText.jar from http://itextpdf.com/, and move it to $TOMCAT_DIRECTORY/webapps/JavaBridge/WEB-INF/lib + 4. Do the same for FillpdfService.jar, from http://github.com/downloads/lefnire/fillpdf-service/FillpdfService.jar + 5. Symlink or copy your JavaBridge webapp directory into fillpdf/lib. (eg, ln -s $TOMCAT_DIR/webapps/JavaBridge $DRUPAL_SITE/sites/all/modules/fillpdf/lib/JavaBridge) + 6. Start Tomcat, then go to /admin/settings/fillpdf & tick the "Use Local Service" checkbox + +Local pdftk installation (optional) +----------------------------- +As an alternative to using Tomcat and JavaBridge, you can use the pdftk program, which is installable on most servers via their package managers (e.g. yum install pdftk, apt-get install pdftk, etc.). You may also be able to find tutorials on the Internet to enable you to install this on shared hosting; additional steps may be required in that case. Once you have installed pdftk, make sure it is in your PATH, and you should then find it works automatically. diff --git a/fillpdf.admin.inc b/fillpdf.admin.inc new file mode 100644 index 0000000..3ea83fc --- /dev/null +++ b/fillpdf.admin.inc @@ -0,0 +1,695 @@ +<?php +// $Id$ + +/** + * @file + * Allows mappings of PDFs to site content + */ + +/* ---------------- Configuration --------------------*/ + +/** + * Settings form for user to place API Key + */ +function fillpdf_settings($form, &$form_state) { + $form['settings_help'] = array( + '#type' => 'markup', + '#value' => t(" + This module requires one of several external PDF manipulation tools -- you can:<ul> + <li>Sign up for <a href='http://fillpdf-service.com'>Fillpdf as-a-service</a>, and plug your API key in here; <strong>or</strong> + <li>Deploy locally -- You'll need a VPS or dedicated server so you can deploy PHP/JavaBridge on Tomcat (see README.txt), then select \"Use Local Service\" + <li>Use a local installation of the pdftk program - you'll need a VPS or a dedicated server so you can install pdftk (see README.txt), then select \"Use locally-installed pdftk\" + </ul> + "), + ); + $form['remote'] = array( + '#type' => 'fieldset', + '#title' => t('Use Remote Service'), + ); + $form['remote']['fillpdf_remote_service'] = array( + '#type' => 'checkbox', + '#title' => t('Use fillpdf-service.com'), + '#default_value' => variable_get('fillpdf_remote_service', true), + ); + $form['remote']['fillpdf_api_key'] = array( + '#type' => 'textfield', + '#title' => t('API Key'), + '#default_value' => variable_get('fillpdf_api_key', ''), + '#description' => t(''), + ); + if (variable_get('fillpdf_api_key', '') == '') { + $form['remote']['warning'] = array( + '#type' => 'markup', + '#prefix' => "<div class='warning'>", + '#suffix' => "</div>", + '#value' => t("You need to sign up for an API key at <a href='http://fillpdf-service.com'>fillpdf-service.com</a>"), + ); + } + + $form['local'] = array( + '#type' => 'fieldset', + '#title' => t('Use Local Service'), + ); + $form['local']['fillpdf_local_service'] = array( + '#type' => 'checkbox', + '#title' => t('Use locally-installed PHP/JavaBridge'), + '#default_value' => (variable_get('fillpdf_local_service', true)), + ); + if (!(file_exists(drupal_get_path('module', 'fillpdf') . '/lib/JavaBridge/java/Java.inc'))) { + $form['local']['warning'] = array( + '#type' => 'markup', + '#prefix' => "<div class='warning'>", + '#suffix' => "</div>", + '#value' => t("JavaBridge isn't installed locally. See README.txt for setting it up."), + ); + } + + $form['local_php'] = array( + '#type' => 'fieldset', + '#title' => t('Use Local pdftk'), + ); + $form['local_php']['fillpdf_local_php'] = array( + '#type' => 'checkbox', + '#title' => t('Use locally-installed pdftk'), + '#default_value' => (variable_get('fillpdf_local_php', true)), + ); + //TODO: Modify to add check for pdftk installed + + $js = <<<JS +Drupal.behaviors.fillpdfSettingsCheckboxes = function (context) { + $("input#edit-fillpdf-remote-service").click(function(){ + $("input#edit-fillpdf-local-service").attr('checked', false); + $("input#edit-fillpdf-local-php").attr('checked', false); + }); + $("input#edit-fillpdf-local-service").change(function(){ + $("input#edit-fillpdf-remote-service").attr('checked', false); + $("input#edit-fillpdf-local-php").attr('checked', false); + }); + $("input#edit-fillpdf-local-php").change(function(){ + $("input#edit-fillpdf-local-service").attr('checked', false); + $("input#edit-fillpdf-remote-service").attr('checked', false); + }); +}; +JS; + drupal_add_js($js, array('type' => 'inline', 'scope' => JS_DEFAULT)); + + return system_settings_form($form); +} + + +/* ---------------- Form Create --------------------*/ + +/** + * Manage your existing forms, or upload a new one + */ +function fillpdf_forms($form, &$form_state) { + $result = db_query("SELECT title, fid FROM {fillpdf_forms} ORDER BY title"); + $header = array(t('Title'), array( + 'data' => t('Operations'), + 'colspan' => '4', + )); + while ($pdf_form = db_fetch_object($result)) { + $row = array( + check_plain($pdf_form->title), + l(t('Edit'), "admin/content/fillpdf/$pdf_form->fid"), + l(t('Delete'), "admin/content/fillpdf/$pdf_form->fid/delete"), + l(t('Export field mappings'), "admin/content/fillpdf/$pdf_form->fid/export"), + l(t('Import field mappings'), "admin/content/fillpdf/$pdf_form->fid/import"), + ); + $rows[] = $row; + } + + $form['existing_forms'] = array( + '#type' => 'markup', + '#value' => theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'fillpdf'))), + ); + + $form['#attributes'] = array('enctype' => "multipart/form-data"); + $form['upload_pdf'] = array( + '#type' => 'file', + '#title' => 'Upload', + '#description' => 'Upload a PDF template to create a new form', + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + '#weight' => 15, + ); + + return $form; +} + +/** + * Makes sure the Upload was provided (want to validate .pdf here too) + */ +function fillpdf_forms_validate($form, &$form_state) { + + // uploading anything? + $file = $_FILES['files']['name']['upload_pdf']; + if (!$file) { + form_set_error('url', t('A PDF must be provided.')); + } + + //from includes/file.inc, line 634, but can't use that function because file not an object yet + if (!preg_match('/\.pdf$/i', $file)) { + form_set_error('url', t('Only PDF files are allowed')); + } + + // directory exist or writeable? + $dir = file_directory_path() . "/fillpdf"; + file_prepare_directory($dir, FILE_CREATE_DIRECTORY, 'url'); + +} + +/** + * Creates a new Form from the uploaded PDF, including parsed fields + */ +function fillpdf_forms_submit($form, &$form_state) { + $dir = file_directory_path() . "/fillpdf"; + // $validators not working, so I just checked manually in fillpdf_forms_validate() + $validators = array('file_validate_extensions' => array('pdf')); + if ($file = file_save_upload('upload_pdf', $validators, $dir, FILE_EXISTS_REPLACE)) { + drupal_set_message('<strong>' . $file->filename . '</strong> was successfully uploaded'); + $file->status &= FILE_STATUS_PERMANENT; + $file = file_save($file); + } + else { + //commented out because even though error if file doesn't upload right, not error if they dont' upload a file (& this is still triggered) + drupal_set_message('Error saving file to ' . $dir, 'error'); + } + + $fid = db_insert('fillpdf_forms') + ->fields(array( + 'fid' => $fid, + 'title' => $file->filename, + 'url' => $file->filepath, + )) + ->execute(); + fillpdf_parse_pdf($fid); + $form_state['redirect'] = "admin/content/fillpdf/$fid"; +} + + +/* ---------------- Form Edit --------------------*/ + +/** + * Edit existing PDF form + */ +function fillpdf_form_edit($form, &$form_state, $fid) { + $pdf_form = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $fid))); + + $form['title'] = array( + '#type' => 'textfield', + '#title' => t('Title'), + '#maxlength' => 127, + '#default_value' => $pdf_form->title, + '#required' => TRUE, + ); + + // @@TODO: + // They can upload a PDF any time, but fields will only be generated on add. Don't want to purge existing fields, + // however a user might have accidently uploaded an old template and discover much later (if it's substantially different, just + // create a new Form + $form['pdf_info'] = array( + '#type' => 'fieldset', + '#title' => 'PDF Form information', + '#collapsed' => true, + ); + $form['pdf_info']['submitted_pdf'] = array( + '#type' => 'item', + '#title' => t('Uploaded PDF'), + '#value' => $pdf_form->url, + ); + $form['pdf_info']['sample_populate'] = array( + '#type' => 'item', + '#title' => 'Sample PDF', + '#value' => l("See which fields are which in this PDF", fillpdf_pdf_link($fid, null, null, true)), + ); + $form['pdf_info']['form_id'] = array( + '#type' => 'item', + '#title' => 'Form Info', + '#value' => "Form ID: [$fid]. Populate this form with node IDs, such as /fillpdf?fid=$fid&nid=10<br/>", + ); + + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + $form['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete'), + ); + //$form['#pdf_form'] = &$pdf_form; + $form['#pdf_form'] = $pdf_form; + + // @@TODO: order by weight, and add dragable ala http://www.computerminds.co.uk/quick-guide-using-drupal-add-tabledrag-and-enjoying-jquery-drag-and-drop-loveliness + $q = db_query('SELECT * FROM {fillpdf_fields} WHERE fid = :fid', array(':fid' => $fid)); + $header = array(t('Label'), t('PDF-field key'), t('Value'), array( + 'data' => t('Operations'), + 'colspan' => 2, + )); + while ($field = db_fetch_object($q)) { + $row = array( + check_plain($field->label), //editable + check_plain($field->pdf_key), + $field->value, //editable, expandable + l(t('Edit'), "admin/content/fillpdf/$fid/edit/{$field->pdf_key}"), + l(t('Delete'), "admin/content/fillpdf/$fid/delete/{$field->pdf_key}"), + ); + $rows[] = $row; + } + + $form['existing_fields'] = array( + '#type' => 'markup', + '#value' => '<br/><br/>' . theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'fillpdf_fields'))), + ); + + // $form['tokens_fieldset'] = array( + // '#type' => 'fieldset', + // '#title' => 'Tokens', + // '#collapsible' => TRUE, + // '#collapsed' => TRUE, + // '#weight' => 1, + // ); + // $form['tokens_fieldset']['tokens'] = array( + // '#value' => theme('token_help'), + // ); + + + return $form; +} + +/** + * Submit Edit or Delete for existing PDF form + */ +function fillpdf_form_edit_submit($form, &$form_state) { + if ($form_state['values']['op'] == t('Delete')) { + $form_state['redirect'] = "admin/content/fillpdf/{$form['#pdf_form']->fid}/delete"; + return; + } + else { + db_update('fillpdf_forms') + ->fields(array( + 'title' => $form_state['values']['title'], + )) + ->condition('fid', $form['#pdf_form']->fid) + ->execute(); + $form_state['redirect'] = "admin/content/fillpdf/{$form['#pdf_form']->fid}"; + drupal_set_message('Successfully updated form'); + //$form_state['nid'] = $node->nid; + } +} + +/** + * Delete form confirmation + */ +function fillpdf_form_delete_confirm($form, &$form_state, $pdf_form) { + if (is_numeric(arg(3))) { + $pdf_form = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => arg(3)))); + } + if (!$pdf_form) { + drupal_not_found(); + exit; + } + + $form['#pdf_form'] = $pdf_form; + return confirm_form($form, + t('Are you sure you want to delete the form %title?', array('%title' => $pdf_form->title)), + 'admin/content/fillpdf', + t('Deleting a form will delete all the fields you created in it. This action cannot be undone.'), + t('Delete'), t('Cancel') + ); +} + +/** + * Delete form submit + */ +function fillpdf_form_delete_confirm_submit($form, &$form_state) { + db_delete('fillpdf_fields') + ->condition('fid', $form['#pdf_form']->fid) + ->execute(); + db_delete('fillpdf_forms') + ->condition('fid', $form['#pdf_form']->fid) + ->execute(); + drupal_set_message('Your form has been deleted.'); + $form_state['redirect'] = 'admin/content/fillpdf'; +} + +/** + * Export an importable array of PDF field key -> Label, Value mappings. + * The array key is the PDF field key and the value is another array containing the label and + * the value (properly keyed). + * + * @param mixed $pdf_form The FillPDF form ID. + */ +function fillpdf_form_export($pdf_form) { + if (is_numeric($pdf_form)) { + $fid = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $pdf_form))); + } + if (!$fid) { + drupal_not_found(); + exit; + } + $fields = db_query('SELECT * FROM {fillpdf_fields} WHERE fid = :fid', array(':fid' => $fid->fid)); + $export_array = array(); + while ($field = db_fetch_object($fields)) { + $export_array[$field->pdf_key] = array( + 'label' => $field->label, + 'value' => $field->value, + ); + } + $fillpdf_code = fillpdf_form_export_encode($export_array); + return drupal_get_form('fillpdf_export_form', $fillpdf_code); +} + +/** + * Form for exporting Fill PDF field mappings + */ +function fillpdf_export_form($form, $form_state, $code) { + $form = array(); + $form['export'] = array( + '#type' => 'textarea', + '#title' => t('Fill PDF Form Mappings'), + '#default_value' => $code, + '#rows' => 30, + '#description' => t('Copy this code and then on the site you want to import to, go to the Edit page for the Fill PDF form for which you want to import these mappings, and paste it in there.'), + '#attributes' => array( + 'style' => 'width: 97%;', + ), + ); + return $form; +} + +/** + * Build Fill PDF configuration code string recursively + * Code borrowed from Node Export (http://drupal.org/project/node_export). Thanks, Node Export! + */ +function fillpdf_form_export_encode($var, $iteration = 0) { + $tab = ''; + for ($i = 0; $i < $iteration; $i++) { + $tab = $tab . " "; + } + $iteration++; + if (is_object($var)) { + $var = (array) $var; + $var['#_export_fillpdf_form_encode_object'] = '1'; + } + if (is_array($var)) { + $empty = empty($var); + $code = "array(" . ($empty ? '' : "\n"); + foreach ($var as $key => $value) { + $out = $tab . " '" . $key . "' => " . fillpdf_form_export_encode($value, $iteration) . ",\n"; + drupal_alter('fillpdf_form_export_encode', $out, $tab, $key, $value, $iteration); + $code .= $out; + } + $code .= ($empty ? '' : $tab) . ")"; + return $code; + } + else { + if (is_string($var)) { + return "'" . addslashes($var) . "'"; + } + elseif (is_numeric($var)) { + return $var; + } + elseif (is_bool($var)) { + return ($var ? 'TRUE' : 'FALSE'); + } + else { + return 'NULL'; + } + } +} + +/** + * Based loosely on Node Export's import form. Import the code and configure the DB settings. + * + * @param mixed $form_state + * @param mixed $pdf_form + */ +function fillpdf_form_import_form($form, &$form_state, $pdf_form) { + if (is_numeric($pdf_form)) { + $fid = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $pdf_form))); + } + if (!$fid) { + drupal_not_found(); + exit; + } + $form['fid'] = array( + '#type' => 'value', + '#value' => $fid->fid, + ); + $form['paste'] = array( + '#type' => 'fieldset', + '#title' => t('Paste code'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + $form['paste']['code'] = array( + '#type' => 'textarea', + '#default_value' => '', + '#rows' => 30, + '#description' => t('Cut and paste the results of a <em>Fill PDF Field Mappings export</em> here.'), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Import'), + '#suffix' => l(t('Reset the form'), $_GET['q']), + ); + return $form; +} + +/** + * Check the syntax of the code the user is trying to import + */ +function fillpdf_form_import_form_validate($form, &$form_state) { + $mappings = fillpdf_form_export_decode($form_state['values']['code']); + if (!is_array($mappings) || empty($mappings)) { + form_set_error('code', t('There was a problem processing your Fill PDF Field Mappings code. Please do a fresh export from the source and try pasting it again.')); + } + else { + $form_state['values']['mappings'] = $mappings; + } +} + +/** + * Perform the import. + */ +function fillpdf_form_import_form_submit($form, &$form_state) { + $pdf_form = new stdClass(); + $pdf_form->fid = $form_state['values']['fid']; + $mappings = $form_state['values']['mappings']; + $fields = fillpdf_get_fields($pdf_form->fid); + $field_keys = array_keys($fields); + // Process the mappings + foreach ($mappings as $pdf_key => $field_settings) { + if (in_array($pdf_key, $field_keys)) { + $field_settings = (object) $field_settings; + $field_settings->pdf_key = $pdf_key; + fillpdf_update_field($pdf_form, $field_settings, $pdf_key); + } + else { + drupal_set_message(t('Your code contained field mappings for the PDF field key <em>@pdf_key</em>, but it does not exist on this form. Therefore, it was ignored.', array('@pdf_key' => $pdf_key)), 'warning'); + } + } + drupal_set_message(t('Successfully imported matching PDF field keys. If any field mappings failed to import, they are listed above.')); + $form_state['redirect'] = "admin/content/fillpdf/{$pdf_form->fid}"; +} + +/** + * Evaluate and return decoded string. Borrowed from Node Export module. + */ +function fillpdf_form_export_decode($string) { + $array = eval('return ' . $string . ';'); + // $return = fillpdf_form_export_decode_objects($array); // (wizonesolutions) Not needed since we simply process an array upon import. + $return = $array; + return $return; +} + +/* ---------------- Fields Edit --------------------*/ + + +/** + * Retrieve a field from a PDF for use in editing form. + */ +function fillpdf_field($op, $fid, $pdf_key = NULL) { + if (is_numeric($fid)) { + $pdf_form = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $fid))); + } + if (!$pdf_form) { + drupal_not_found(); + exit; + } + + if ($op == 'add') { + drupal_set_title($pdf_form->title); + } + else if ($op != 'edit') { + return fillpdf_form_overview($pdf_form); + } + else if ($pdf_key) { + $field = db_fetch_object(db_query("SELECT * FROM {fillpdf_fields} WHERE pdf_key = :pdf_key AND fid = :fid", array(':pdf_key' => $pdf_key, ':fid' => $fid))); + if (!$field) { + drupal_not_found(); + exit; + } + drupal_set_title($field->label); + } + + return drupal_get_form('fillpdf_field_edit', $pdf_form, $field); +} + +/** + * Edit a single field. + */ +function fillpdf_field_edit($form, &$form_state, $pdf_form, $field) { + $form['label'] = array( + '#type' => 'textfield', + '#title' => t('Label'), + '#maxlength' => 255, + '#default_value' => $field->label, + '#description' => t('An optional label to help you identify the field.'), + '#weight' => 0, + ); + $form['pdf_key'] = array( + '#type' => 'textfield', + '#title' => t('PDF Key'), + '#maxlength' => 255, + '#default_value' => $field->pdf_key, + '#required' => TRUE, + '#description' => t('The field key from the original PDF form. You likely need Acrobat Pro to discover this.'), + '#weight' => 1, + ); + $form['value'] = array( + '#type' => 'textarea', + '#title' => t('Value'), + '#default_value' => $field->value, + '#description' => t('The content that will populate this field when the PDF is printed/saved. This content pulls data via tokens, see below for available tokens.'), + '#weight' => 4, + ); + $form['tokens_fieldset'] = array( + '#type' => 'fieldset', + '#title' => 'Tokens', + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#weight' => 5, + ); + // TODO Please change this theme call to use an associative array for the $variables parameter. + $form['tokens_fieldset']['tokens'] = array( + '#value' => theme('token_help'), + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + '#weight' => 9, + ); + + if ($field) { + $form['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete'), + '#weight' => 10, + ); + } + + $form['#pdf_field'] = $field; + $form['#pdf_form'] = $pdf_form; + + return $form; +} + +/** + * Validate the edited field. + */ +function fillpdf_field_edit_validate($form, &$form_state) { + if (db_query("SELECT * FROM {fillpdf_fields} WHERE fid = :fid AND pdf_key = :pdf_key", array(':fid' => $form['#pdf_form']->fid, ':pdf_key' => $form_state['values']['pdf_key']))->fetchField()) { + if ($form['#pdf_field'] && $form['#pdf_field']->pdf_key == $form_state['values']['pdf_key'] ) { + return; + } + else { + form_set_error('pdf_key', t('A field with this pdf_key already exists. Choose another pdf_key.')); + } + } +} + +/** + * Save changes to the database. + */ +function fillpdf_field_edit_submit($form, &$form_state) { + if ($form['#pdf_field']) { + if ($form_state['values']['op'] == t('Delete')) { + $form_state['redirect'] = 'admin/content/fillpdf/' . $form['#pdf_form']->fid . '/delete/' . $form['#pdf_field']->pdf_key; + return; + } + $edit_field = (object) $form_state['values']; + fillpdf_update_field($form['#pdf_form'], $edit_field, $form['#pdf_field']->pdf_key); + } + else { + //add a new field + $edit_field = (object) $form_state['values']; + db_insert('fillpdf_fields') + ->fields(array( + 'fid' => $form_state['values']['#pdf_form']->fid, + 'label' => $form_state['values']['label'], + 'pdf_key' => $form_state['values']['pdf_key'], + 'value' => $form_state['values']['value'], + )) + ->execute(); + } + $form_state['redirect'] = 'admin/content/fillpdf/' . $form['#pdf_form']->fid; +} + + +/** + * Delete form. + */ +function fillpdf_field_delete_confirm($form, &$form_state, $fid, $pdf_key) { + $pdf_form = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $fid))); + + if ($pdf_key) { + $field = db_fetch_object(db_query("SELECT * FROM {fillpdf_fields} WHERE pdf_key = :pdf_key AND fid = :fid", array(':pdf_key' => $pdf_key, ':fid' => $fid))); + } + if (!$field) { + drupal_not_found(); + exit; + } + + $form['#pdf_field'] = $field; + $form['#pdf_form'] = $pdf_form; + + return confirm_form($form, + t('Are you sure you want to delete the field %pdf_key?', array('%pdf_key' => $field->pdf_key)), + 'admin/content/fillpdf/' . $pdf_form->fid, + t('This action cannot be undone.'), t('Delete'), t('Cancel') + ); +} + +/** + * Process the deletion. + */ +function fillpdf_field_delete_confirm_submit($form, &$form_state) { + db_delete('fillpdf_fields') + ->condition('fid', $form['#pdf_field']->fid) + ->condition('pdf_key', $form['#pdf_field']->pdf_key) + ->execute(); + drupal_set_message('Your field has been deleted.'); + //return 'admin/content/fillpdf/'. $form['#pdf_field']->fid; + $form_state['redirect'] = 'admin/content/fillpdf/' . $form['#pdf_field']->fid; +} + +/** + * Stores the updated $field in the database + */ +function fillpdf_update_field(&$pdf_form, &$field, $old_key) { + db_update('fillpdf_fields') + ->fields(array( + 'label' => $field->label, + 'pdf_key' => $field->pdf_key, + 'value' => $field->value, + )) + ->condition('fid', $pdf_form->fid) + ->condition('pdf_key', $old_key) + ->execute(); +} diff --git a/fillpdf.info b/fillpdf.info index 1a403a0..3af0cc9 100644 --- a/fillpdf.info +++ b/fillpdf.info @@ -1,4 +1,20 @@ -name = "Fill PDF" -description = "Allows users to populate PDF forms (using XFDF) from submitted node data." +; $Id$ admin_menu.info,v 1.5.2.1 2008/11/30 12:50:36 sun Exp $ +name = Fill PDF +description = Allows users to populate PDF forms from submitted node data. package = Other -dependencies = content token \ No newline at end of file +core = 7.x + +dependencies[] = content +dependencies[] = token +; Information added by drupal.org packaging script on 2011-01-04 +version = "6.x-1.x-dev" +core = 7.x +project = "fillpdf" +datestamp = "1294143233" + + +files[] = fillpdf.admin.inc +files[] = fillpdf.install +files[] = fillpdf.module +files[] = webform_tokens.inc +files[] = xfdf.inc diff --git a/fillpdf.module b/fillpdf.module index 63d92ff..2382276 100644 --- a/fillpdf.module +++ b/fillpdf.module @@ -1,31 +1,34 @@ <?php // $Id$ - + /** * @file - * Allows mappings of PDFs to site content. + * Allows mappings of PDFs to site content */ -define("SERVLET_URL", "http://fillpdf.selfip.com:8080/fillpdf_servlet/xmlrpc"); +define("DEFAULT_SERVLET_URL", "http://fillpdf-service.com/xmlrpc.php"); +module_load_include('inc', 'fillpdf', 'fillpdf.admin'); + +if (module_exists('webform')) { + module_load_include('inc', 'fillpdf', 'webform_tokens'); +} /** - * Implementation of hook_help(). + * Implements hook_help(). */ -function fillpdf_help($section) { - switch ($section) { +function fillpdf_help($path, $arg) { + switch ($path) { case 'admin/help#fillpdf': - return '<p>After setting up your PDF-to-node mapping & you want to download the PDF, - you need to navigate to /fillpdf?fid=10&nid=10 - where fid is the form id of the form you\'ve just created, and nid is the node - id whose content you\'ll be pulling via tokens. You can obtain fid from the URL - when editing your form. It will look like: http://localhost/admin/content/fillpdf/form/FID/...</p>'; + $content = _fillpdf_get_file_contents(drupal_get_path('module', 'fillpdf') . '/README.txt'); + $content = '<pre>' . check_plain($content) . '</pre>'; + return $content; case 'admin/content/fillpdf': if (module_exists('help')) { return t('See the !link for an explaination on dowloading these forms to PDF', array('!link' => l(t('Documentation'), 'admin/help/fillpdf'))); } else { - return t('Activate the help module if you need an '. + return t('Activate the help module if you need an ' . 'explanation on downloading these forms to PDF.'); } } @@ -33,543 +36,550 @@ function fillpdf_help($section) { /** - * Implementation of hook_menu(). + * Implements hook_menu(). */ -function fillpdf_menu($may_cache) { - - if ($may_cache) { - $access = user_access('administer pdfs'); +function fillpdf_menu() { + $access = array('administer pdfs'); + $items = array(); + + // fillpdf&fid=10&nids[]=1&webforms[0][nid]=2&webforms[0][sid]=3 + $items['fillpdf'] = array( + 'page callback' => 'fillpdf_parse_uri', + // Can't use access callback. We need the arguments, but they're passed as $GET. Will access-check in fillpdf_merge_pdf + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); - $items[] = array( - 'path' => 'fillpdf', // fillpdf?fid=10&nid=20 - 'callback' => 'fillpdf_generate_pdf', - 'access' => user_access('access content') - ); + // ------- Config --------------------------- + $items['admin/config/fillpdf'] = array( + 'title' => 'Fill PDF Settings', + 'description' => 'Configure Fill PDF Servelet Information', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('fillpdf_settings'), + 'access arguments' => $access, + ); - $items[] = array( - 'path' => 'admin/content/fillpdf', - 'title' => t('Fill PDF'), - 'description' => t('Manage your PDFs.'), - 'callback' => 'fillpdf_admin', - 'access' => $access - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/list', - 'title' => t('List PDFs'), - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -10 - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/add', - 'title' => t('Add PDF'), - 'callback' => 'drupal_get_form', - 'callback arguments' => array('fillpdf_form_edit', 'add'), - 'access' => $access, - 'type' => MENU_LOCAL_TASK - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/delete', - 'callback' => 'drupal_get_form', - 'callback arguments' => array('fillpdf_form_delete_confirm'), - 'access' => $access, - 'type' => MENU_CALLBACK - ); - } - else if (is_numeric(arg(4))) { - $items[] = array( - 'path' => 'admin/content/fillpdf/form/'. arg(4) .'/edit', - 'title' => t('Edit PDF'), - 'callback' => 'drupal_get_form', - 'callback arguments' => array('fillpdf_form_edit', 'edit', arg(4)), - 'access' => $access, - 'type' => MENU_LOCAL_TASK, - 'weight' => -20, - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/form/'. arg(4), - 'callback' => 'fillpdf_field_edit_field', - 'type' => MENU_CALLBACK, - 'access' => $access - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/form/'. arg(4) .'/list', - 'title' => t('List fields'), - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -10 - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/form/'. arg(4) .'/generate', - 'title' => t('Generate Fields From PDF'), - 'callback' => 'fillpdf_generate_fields_from_pdf', - 'callback arguments' => array(arg(4)), - 'access' => $access, - 'type' => MENU_CALLBACK - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/form/'. arg(4) .'/add', - 'title' => t('Add field'), - 'callback' => 'fillpdf_field_edit_field', - 'access' => $access, - 'type' => MENU_LOCAL_TASK - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/form/'. arg(4) .'/edit/'. arg(6), - 'callback' => 'fillpdf_field_edit_field', - 'access' => $access, - 'type' => MENU_CALLBACK - ); - $items[] = array( - 'path' => 'admin/content/fillpdf/form/'. arg(4) .'/delete', - 'callback' => 'drupal_get_form', - 'callback arguments' => array('fillpdf_field_delete_confirm', arg(4), arg(6)), - 'access' => $access, - 'type' => MENU_CALLBACK - ); - } + // --------- Form ------------------------ + $items['admin/content/fillpdf'] = array( + 'title' => 'Fill PDF', + 'description' => 'Manage your PDFs', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('fillpdf_forms'), + 'access arguments' => $access, + ); + $items['admin/content/fillpdf/%'] = array( + 'title' => 'Edit PDF Form', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('fillpdf_form_edit', 3), + 'access arguments' => $access, + ); + $items['admin/content/fillpdf/%/delete'] = array( + 'page callback' => 'drupal_get_form', + 'page arguments' => array('fillpdf_form_delete_confirm', 3), + 'access arguments' => $access, + 'type' => MENU_CALLBACK, + ); + $items['admin/content/fillpdf/%/export'] = array( + 'title' => t('Export Fill PDF Field Mappings'), + 'page callback' => 'fillpdf_form_export', + 'page arguments' => array(3), + 'access arguments' => $access, + 'type' => MENU_CALLBACK, + ); + $items['admin/content/fillpdf/%/import'] = array( + 'title' => t('Import Fill PDF Field Mappings'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('fillpdf_form_import_form', 3), + 'access arguments' => $access, + 'type' => MENU_CALLBACK, + ); + //}else if (is_numeric(arg(4))) { + + // --------- Fields ------------------------ + $items['admin/content/fillpdf/%/add'] = array( + 'title' => 'Add field', + 'page callback' => 'fillpdf_field', + 'page arguments' => array(4, 3), + 'access arguments' => $access, + 'type' => MENU_LOCAL_TASK, + ); + $items['admin/content/fillpdf/%/edit/%'] = array( + 'page callback' => 'fillpdf_field', + 'page arguments' => array(4, 3, 5), + 'access arguments' => $access, + 'type' => MENU_CALLBACK, + ); + $items['admin/content/fillpdf/%/delete/%'] = array( + 'page callback' => 'drupal_get_form', + 'page arguments' => array('fillpdf_field_delete_confirm', 3, 5), + 'access arguments' => $access, + 'type' => MENU_CALLBACK, + ); + //} return $items; } /** - * Implementation of hook_perm(). + * Implements hook_permission(). */ -function fillpdf_perm() { - return array('administer pdfs'); +function fillpdf_permission() { + return array( + 'administer pdfs' => array( + 'title' => t('Administer PDFs'), + 'description' => t('Allows usage of the Fill PDF administration screen.'), + ), + 'publish own pdfs' => array( + 'title' => t('Publish Own PDFs'), + 'description' => t("Allows filling in and downloading PDFs with one's own site content."), + ), + 'publish all pdfs' => array( + 'title' => t('Publish All PDFs'), + 'description' => t('Allows filling in and downloading PDFs with any site content.'), + ), + ); } -function fillpdf_admin() { - $result = db_query("SELECT * FROM {fillpdf_forms} ORDER BY title"); - - $header = array(t('Title'), array('data' => t('Operations'), 'colspan' => '4')); +/** + * Gets a link to the prinable PDF, merged with the passed-in data + * @param array/int $nids or $nid, if you pass in one value it will merge with that node. + * If array, it will merge with multiple nodes, with later nids overriding previous ones. + * @param array $webforms Array of webforms, of this strucure: array('nid'=>1, 'sid'=>1) + * @param bool $sample True if you want to populate the form with its own field-names (to get a gist of PDF) + */ +function fillpdf_pdf_link($fid, $nids = null, $webform_arr = null, $sample = false) { - while ($pdf_form = db_fetch_object($result)) { - $row = array(); - $row[] = check_plain($pdf_form->title); - $row[] = l(t('Edit PDF'), "admin/content/fillpdf/form/$pdf_form->fid/edit"); - $row[] = l(t('Edit fields'), "admin/content/fillpdf/form/$pdf_form->fid/list"); - $row[] = l(t('Add field'), "admin/content/fillpdf/form/$pdf_form->fid/add"); - $row[] = l(t('Generate Fields From PDF'), "admin/content/fillpdf/form/$pdf_form->fid/generate"); - $rows[] = $row; + if (is_array($nids)) { + $nids_uri = '&nids[]=' . implode('&nids[]=', $nids); + } + elseif (isset($nids)) { + $nids_uri = "&nids[]={$nids}"; } - if (empty($rows)) { - $rows[] = array(array('data' => t('No PDFs available.'), 'colspan' => '5', 'class' => 'message')); + if (is_array($webform_arr)) { + if ($webform_arr['nid']) { + $webform_arr = array($webform_arr); + } + foreach ($webform_arr as $key => $webform) { + $webforms_uri .= "&webforms[{$key}][nid]={$webform['nid']}"; + } + $webforms_uri .= $webform['sid'] ? "&webforms[{$key}][sid]={$webform['sid']}" : ""; } + $sample = $sample ? '&sample=true' : ''; - return theme('table', $header, $rows, array('id' => 'fillpdf')); + return url('', array('absolute' => true)) . "fillpdf&fid={$fid}{$nids_uri}{$webforms_uri}{$sample}"; } -function fillpdf_form_edit($op = 'add', $fid = NULL) { - if ($op != 'add' && is_numeric($fid)) { - $pdf_form = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = %d", $fid)); - drupal_set_title(t('Edit form')); - } - $form['title'] = array('#type' => 'textfield', - '#title' => t('Title'), - '#maxlength' => 127, - '#default_value' => $pdf_form ? $pdf_form->title : '', - '#required' => TRUE, - '#weight' => -5, - ); - $form['url'] = array('#type' => 'textfield', - '#title' => t('URL'), - '#description' => t('The URL of the PDF file that will be parsed & merged. - Currently, this module doesn\'t upload, so if you want the PDF file on your - own server, upload it via one of Drupal\'s many uploading mechanisms (or FTP) - and paste the http:// url here.'), - '#maxlength' => 127, - '#default_value' => $pdf_form ? $pdf_form->url : '', - '#required' => TRUE, - '#weight' => -5, - ); - $form['submit'] = array('#type' => 'submit', - '#value' => t('Submit'), - '#weight' => 15, - ); - if ($pdf_form) { - $form['delete'] = array('#type' => 'submit', - '#value' => t('Delete'), - '#weight' => 16, - ); + +/** + * Get the data and form that need to be merged, from the $_GET, and print the PDF + * @seealso fillpdf_pdf_link for $_GET params + */ +function fillpdf_parse_uri() { + //this function called multiple times, cut down on DB calls + // static $get;if($get)return $get; + $sample = $_GET['sample']; // is this just the PDF populated with sample data? + $fid = $_GET['fid']; + $nids = $webforms = array(); + if ( $_GET['nid'] || $_GET['nids'] ) { + $nids = ( $_GET['nid'] ? array($_GET['nid']) : $_GET['nids'] ); } - else { - $pdf_form = (object) array('new' => TRUE); + if ( $_GET['webform'] || $_GET['webforms'] ) { + $webforms = ( $_GET['webform'] ? array($_GET['webform']) : $_GET['webforms'] ); } - $form['form'] = array('#type' => 'value', '#value' => &$pdf_form); + fillpdf_merge_pdf($fid, $nids, $webforms, $sample); +} - $form['#validate'] = array('fillpdf_form_edit_validate' => array()); - $form['#submit'] = array('fillpdf_form_edit_submit' => array()); - return $form; -} +/** + * Documentation stub + * @return doesn't return anything, actually constructs a page from scratch (pdf content-type) + * @seealso fillpdf_pdf_link for $_GET params + */ +function fillpdf_merge_pdf($fid, $nids = null, $webform_arr = null, $sample = null) { + // Case 1: No $fid + if (is_null($fid)) { + drupal_set_message('Fillpdf Form ID required to print a PDF', 'warning'); + drupal_goto(); + } -function fillpdf_form_edit_validate($form_id, &$form_values, &$form) { - $url = rtrim(ltrim($form_values['url'], '/'), '/'); - if (!valid_url($url, TRUE)) { //if they used drupal-relative URL - $url = 'http://'. $_SERVER['SERVER_NAME'] .'/'. $url; - } - form_set_value($form['url'], $url); -} + $fillpdf_info = db_fetch_object(db_query("SELECT title, url FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $fid))); + // Case 2: Only $fid -- just give them empty pdf + if (!empty($nodes) && !empty($webforms) && !is_null($sample)) { + $host = url('', array('absolute' => true)); + header("Location: " . $host . '/' . $fillpdf_info->url); + exit; + } -function fillpdf_form_edit_submit($form_id, &$form_values) { + global $user; - if (!$form_values['form']->new) { - if ($form_values['op'] == t('Delete')) { - return 'admin/content/fillpdf/delete/'. $form_values['form']->fid; + $nodes = $webforms = array(); + // Nodes + if (is_array($nids)) { + foreach ($nids as $nid) { + $nodes[] = node_load($nid); } - db_query("UPDATE {fillpdf_forms} SET title = '%s', url = '%s' WHERE fid = %d", - $form_values['title'], $form_values['url'], $form_values['form']->fid); } - else { - $form_values['form']->fid = db_next_id('{fillpdf}_fid'); - db_query("INSERT INTO {fillpdf_forms} (fid, title, url) VALUES(%d, '%s', '%s')", - $form_values['form']->fid, $form_values['title'], $form_values['url']); - } - return 'admin/content/fillpdf'; -} + // Webforms + if (module_exists('webform') && is_array($webform_arr)) { -function fillpdf_form_delete_confirm($pdf_form) { + // Load the submissions inc depending on webform-2.x or webform-3.x + $webform_info_file = drupal_parse_info_file(drupal_get_path('module', 'webform') . '/webform.info'); + if (strstr($webform_info_file['version'], "6.x-2") === FALSE) { + module_load_include('inc', 'webform', 'includes/webform.submissions'); + } + else { + module_load_include('inc', 'webform', 'webform_submissions'); + } - if (is_numeric(arg(4))) { - $pdf_form = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = %d", arg(4))); - } - if (!$pdf_form) { - drupal_not_found(); - exit; + foreach ($webform_arr as $webform) { + if (!$webform['sid']) { // user didn't specify submission-id, meaning they want most recent + $webform['sid'] = db_query('select sid from {webform_submissions} + where nid=%d and uid=%d order by submitted desc', $webform['nid'], $user->uid)->fetchField(); + } + $webforms[] = array( + 'webform' => node_load($webform['nid']), + 'submission' => webform_get_submission($webform['nid'], $webform['sid']), + ); + } } - $form['form'] = array('#type' => 'value', '#value' => $pdf_form); - - return confirm_form($form, - t('Are you sure you want to delete the form %title?', array('%title' => $pdf_form->title)), - 'admin/content/fillpdf', - t('Deleting a form will delete all the fields you created in it. This action cannot be undone.'), - t('Delete'), t('Cancel') - ); -} + if (!fillpdf_merge_pdf_access($nodes, $webforms)) { + drupal_access_denied(); + } -function fillpdf_form_delete_confirm_submit($form_id, &$form_values) { - db_query("DELETE FROM {fillpdf_fields} WHERE fid = %d", $form_values['form']->fid); - db_query("DELETE FROM {fillpdf_forms} WHERE fid = %d", $form_values['form']->fid); - drupal_set_message('Your form has been deleted.'); - return 'admin/content/fillpdf'; -} + $fields = array(); + $query = db_query("SELECT * FROM {fillpdf_fields} WHERE fid = :fid", array(':fid' => $fid)); + while ($obj = db_fetch_object($query)) { + // Fill a sample PDF & return + if ($sample == 'true') { + $fields[$obj->pdf_key] = $obj->pdf_key; + } + else { + // multiple nids, #516840 + // we want the last nid in $_GET to override previous ones (aka, of fillpdf?nids[]=1&nids[]=2, 2 wins) + $nodes = array_reverse($nodes); + $webforms = array_reverse($webforms); + + // --- node token replacements + if (!empty($nodes)) { + foreach ($nodes as $node) { + $token = token_replace($obj->value, $type = 'node', $object = $node); + if ($token) { + break; + } + } + // if they're populating with an imagefield + //@@TODO: check if an image (not another pdf or some-such)_ + if (strstr($obj->value, 'filefield-fid]')) { + module_load_include('inc', 'filefield', 'field_file'); + $filefield = field_file_load($token); + $file_bytes = _fillpdf_get_file_contents($filefield['filepath']); + $str = base64_encode($file_bytes); + $fields[$obj->pdf_key] = '{image}' . $str; + } + else { + $str = preg_replace('|<br />|', ' +', $token); + $fields[$obj->pdf_key] = $str; + } + } + // /--- node token replacements --- + + // --- webform token replacements + if (!empty($webforms)) { + foreach ($webforms as $webform) { + // $submission = node_load($submission->nid); + $token = token_replace($obj->value, $type = 'webform', $webform['submission']); + if ($token) { + break; + } + } + $str = preg_replace('|<br />|', ' +', $token); + $fields[$obj->pdf_key] = $str; + } + // /--- webform token replacements --- -/* fillpdf_get_types() -Array -( - [add] => Node adding form - [edit] => Node edit form - [view] => Node display - [manage] => Node management - [user_edit] => User edit form -) - */ -function fillpdf_field_edit_field() { - $fid=arg(4); - $pdf_key=arg(6); - - if (is_numeric($fid)) { - $pdf_form = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = %d", $fid)); - } - if (!$pdf_form) { - drupal_not_found(); - exit; + } } - if (arg(5) == 'add') { - drupal_set_title(check_plain($pdf_form->title)); - } - else if (arg(5) != 'edit') { - return fillpdf_form_overview($pdf_form); + $download_name = preg_replace('/[^a-zA-Z0-9_]/', '', $fillpdf_info->title) . '.pdf'; + //$download_name = preg_match('|\/[^\/].*$|',$fillpdf_info->url); + $pdf_data = _fillpdf_get_file_contents($fillpdf_info->url, "<front>"); + $fillpdf_remote_service = variable_get('fillpdf_remote_service', TRUE); + $fillpdf_local_service = variable_get('fillpdf_local_service', TRUE); + // use fillpdf-service.com's xmlrpc service (must be registered) + if ($fillpdf_remote_service) { + $api_key = variable_get('fillpdf_api_key', '0'); + $result = _fillpdf_xmlrpc_request(DEFAULT_SERVLET_URL, 'merge_pdf', base64_encode($pdf_data), $fields, $api_key); + if ($result->error == true) { + drupal_goto(); + } //after setting error message + $data = base64_decode($result->data); } - else if ($pdf_key) { - $field = db_fetch_object(db_query("SELECT * FROM {fillpdf_fields} WHERE pdf_key = '%s' AND fid = %d", $pdf_key, $fid)); - if (!$field) { - drupal_not_found(); - exit; + + // use local php/java bridge (must have Tomcat & JavaBridge installed on VPS or dedicated + elseif ($fillpdf_local_service) { + $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) { + $fillpdf->text($key, $field); + } } - drupal_set_title(check_plain($field->label)); - //$type = $field->type; + catch (JavaException $e) { + drupal_set_message(java_truncate((string) $e), 'error'); + drupal_goto(); //after setting error message + } + $data = java_values(base64_decode($fillpdf->toByteArray())); } - return drupal_get_form('fillpdf_field_edit', $pdf_form, $field); -} + // Use PDFTK to merge the two + else { + $data = fillpdf_execute_merge('pdftk', $fields, $fillpdf_info); + } -function fillpdf_field_edit($pdf_form, $field) { + // Log this, could be useful + watchdog('fillpdf', 'User %user has generated form %form for node %node.', array( + '%user' => $user->name, + '%form' => $fillpdf_info->title, + '%node' => $node->title, + )); + + header('Content-type:application/pdf'); + header('Content-disposition:attachment; filename="' . $download_name . '"'); + echo $data; + exit; +} - - $form['label'] = array( - '#type' => 'textfield', - '#title' => t('Label'), - '#maxlength' => 255, - '#default_value' => $field->label, - '#description' => t('An optional label to help you identify the field.'), - '#weight' => 0, - ); - $form['pdf_key'] = array( - '#type' => 'textfield', - '#title' => t('PDF Key'), - '#maxlength' => 255, - '#default_value' => $field->pdf_key, - '#required' => TRUE, - '#description' => t('The field key from the original PDF form. You likely need Acrobat Pro to discover this.'), - '#weight' => 1, - ); -// $form['type'] = array( -// '#type' => 'radios', -// '#options' => array('text','int'), -// '#title' => t('Type'), -// '#default_value' => ( ($field->type)?($field->type):0 ), -// '#description' => t('The type of PDF field.'), -// '#weight' => 3, -// ); - $form['value'] = array( - '#type' => 'textarea', - '#title' => t('Value'), - '#default_value' => $field->value, - '#description' => t('The content that will populate this field when the PDF is printed/saved. This content pulls data via tokens, see below for available tokens.'), - '#weight' => 4, - ); - $form['tokens_fieldset'] = array( - '#type' => 'fieldset', - '#title' => 'Tokens', - '#collapsible' => TRUE, - '#collapsed' => TRUE, - '#weight' => 5, - ); - $form['tokens_fieldset']['tokens'] = array( - '#value' => theme('token_help'), - ); +/** + * Make sure the user has access to data they want to populate the PDF + */ +function fillpdf_merge_pdf_access($nodes = array(), $webforms = array()) { + if ( user_access('administer pdfs') || user_access('publish all pdfs') ) { + return true; + } + if (!user_access('publish own pdfs')) { + return false; + } - $form['submit'] = array( - '#type' => 'submit', - '#value' => t('Submit'), - '#weight' => 9, - ); + // own node? + foreach ($nodes as $node) { + if ( !(node_access('view', $node)) ) { + return false; + } + } - if ($field) { - $form['delete'] = array( - '#type' => 'submit', - '#value' => t('Delete'), - '#weight' => 10, - ); + // own webform? + if (!(empty($webforms))) { + global $user; + if (!($user->uid && (user_access('access own webform submissions') || user_access('access webform results') || user_access('access webform submissions')))) { + return false; + } + foreach ($webforms as $webform) { + if ( !(webform_submission_access($webform['webform'], $webform['submission'], 'view')) ) { + return false; + } + } } - $form['field'] = array('#type' => 'value', '#value' => $field); - $form['form'] = array('#type' => 'value', '#value' => $pdf_form); - - return $form; + return true; } -function fillpdf_field_edit_validate($form_id, &$form_values, &$form) { - if (db_result( db_query("SELECT * FROM {fillpdf_fields} WHERE fid = %d AND pdf_key = '%s'", - $form_values['form']->fid, $form_values['pdf_key'] ))) { - if ($form_values['field'] && $form_values['field']->pdf_key == $form_values['pdf_key'] ) return; - else form_set_error('pdf_key', t('A field with this pdf_key already exists. Choose another pdf_key.')); +/** + * Utility function to allow other functions to merge PDFs with the various methods in a consistent way. + * @param string $method The service or program being used. Possible values: local, remote, pdftk. Currently, only pdftk is supported. + * @param array $fields The fields to merge into the PDF. Should be retrieved from the {fillpdf_fields} table. + * @param mixed $fillpdf When in URL mode, this is the record from {fillpdf_forms}. When in Stream mode, this is the PDF data. + * @param string $mode A special flag to control the behavior of this function. URL mode merges using a PDF on the + * file system and Stream mode merges using the value of $fillpdf directly. Possible values: url, stream. + */ +function fillpdf_execute_merge($method, $fields, $fillpdf, $mode = 'url') { + $data = NULL; + // Try to prepare the data so that the $method part can process it without caring too much about merge tool + switch ($mode) { + case 'url': + $filename = $fillpdf->url; + break; + case 'stream': + $filename = file_save_data($fillpdf, file_directory_temp() . '/pdf_data.pdf', FILE_EXISTS_RENAME); + break; } -} - -function fillpdf_field_edit_submit($form_id, &$form_values) { - if ($form_values['field']) { - if ($form_values['op'] == t('Delete')) { - return 'admin/content/fillpdf/form/'. $form_values['form']->fid .'/delete/'. $form_values['field']->pdf_key; - } - $edit_field = (object)$form_values; - fillpdf_update_field($form_values['form'], $edit_field, $form_values['field']->pdf_key); + switch ($method) { + case 'pdftk': + module_load_include('inc', 'fillpdf', 'xfdf'); // Looks like I'm the first actually to use this! (wizonesolutions) + $xfdfname = $filename . '.xfdf'; + $xfdf = createXFDF(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 + $data = shell_exec('pdftk ' . escapeshellarg($filename) . ' fill_form ' . escapeshellarg($xfdffile) . ' output - flatten drop_xfa'); + file_delete($xfdffile); + if ($mode == 'stream') { + file_delete($filename); + } + break; + } + if ($data) { + return $data; } else { - //add a new field - $edit_field = (object)$form_values; - db_query("INSERT INTO {fillpdf_fields} (fid, label, pdf_key, value) VALUES(%d, '%s', '%s', '%s')", - $form_values['form']->fid, $form_values['label'], $form_values['pdf_key'], $form_values['value']); + return FALSE; } - return 'admin/content/fillpdf/form/'. $form_values['form']->fid; } +/** + * This function generates the form fields from the specified PDF. It (1) sends a request to the iText + * servlet to parse the specified PDF, (2) iText returns an XML response with fields-mappings, this module + * parses the XML response & contsructs the fields. + */ +function fillpdf_parse_pdf($fid) { + $filename = db_query("SELECT url FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $fid))->fetchField(); + $content = _fillpdf_get_file_contents($filename, '<front>'); + $fillpdf_remote_service = variable_get('fillpdf_remote_service', true); + $fillpdf_local_service = variable_get('fillpdf_local_service', TRUE); + + // use fillpdf-service.com's xmlrpc service (must be registered) + if ($fillpdf_remote_service) { + $result = _fillpdf_xmlrpc_request(DEFAULT_SERVLET_URL, 'parse_pdf_fields', base64_encode($content)); + if ($result->error == true) { + drupal_goto("admin/content/fillpdf"); + } //after setting error message + $fields = $result->data; + } -function fillpdf_form_overview(&$pdf_form) { - - drupal_set_title(check_plain($pdf_form->title)); - $result = db_query("SELECT * FROM {fillpdf_fields} WHERE fid = %d ",/*ORDER BY weight, name*/ $pdf_form->fid); - - $header = array(t('Label'), t('PDF Key'), t('Value'), array('data' => t('Operations'), 'colspan' => '2')); - - $rows = array(); - while ($field = db_fetch_object($result)) { - $row = array(); - $row[] = check_plain($field->label); - $row[] = check_plain($field->pdf_key); - $row[] = $field->value; - $row[] = l(t('Edit'), "admin/content/fillpdf/form/$pdf_form->fid/edit/$field->pdf_key"); - $row[] = l(t('Delete'), "admin/content/fillpdf/form/$pdf_form->fid/delete/$field->pdf_key"); - $rows[] = $row; + // use local php/java bridge (must have Tomcat & JavaBridge installed on VPS or dedicated + elseif ($fillpdf_local_service) { + $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'); + drupal_goto("admin/content/fillpdf"); //after setting error message + } } - if (empty($rows)) { - $rows[] = array(array('data' => t('No fields available.'), 'colspan' => '5', 'class' => 'message')); + //use pdftk program (must be installed locally) + else { + $fields = fillpdf_execute_parse('pdftk', $filename); } - return theme('table', $header, $rows, array('id' => 'fillpdf_fields')); + //create fields + foreach ((array) $fields as $key => $arr) { + if ($arr['type']) { // Don't store "container" fields + $arr['name'] = str_replace('�', '', $arr['name']); // pdftk sometimes inserts random � markers - strip these out. NOTE: This may break forms that actually DO contain this pattern, but 99%-of-the-time functionality is better than merge failing due to improper parsing. + $field = new stdClass(); + $field->fid = $fid; + $field->pdf_key = $arr['name']; + $field->label = $arr['name']; + drupal_write_record('fillpdf_fields', $field); + } + } } -function fillpdf_field_delete_confirm($fid, $pdf_key) { - $pdf_form = db_fetch_object(db_query("SELECT * FROM {fillpdf_forms} WHERE fid = %d", $fid)); +/** + * Utility function to allow other functions to parse PDFs with the various methods in a consistent way. + * + * @param string $method The service or program being used. Possible values: local, remote, pdftk. Currently, only pdftk is supported. + * @param mixed $fillpdf When in URL mode, this is the filename to the PDF to parse. When in Stream mode, this is the PDF data. + * @param string $mode A special flag to control the behavior of this function. URL mode merges using a PDF on the + * file system and Stream mode merges using the value of $fillpdf directly. Possible values: url, stream. + */ +function fillpdf_execute_parse($method, $fillpdf, $mode = 'url') { + switch ($mode) { + case 'url': + $filename = $fillpdf; + break; + case 'stream': + $filename = file_save_data($fillpdf, file_directory_temp() . '/pdf_data.pdf', FILE_EXISTS_RENAME); + break; + } + // 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 = array(); + exec('pdftk ' . escapeshellarg($filename) . ' dump_data_fields', $output); + + // Build a simple map of dump_data_fields keys to our own array keys + $data_fields_map = array( + 'FieldType' => 'type', + 'FieldName' => 'name', + 'FieldFlags' => 'flags', + 'FieldJustification' => 'justification', + ); - if ($pdf_key) { - $field = db_fetch_object(db_query("SELECT * FROM {fillpdf_fields} WHERE pdf_key = '%s' AND fid = %d", $pdf_key, $fid)); + // Build the fields array + $fields = array(); + $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))) { + $fields[$fieldindex][$data_fields_map[$linedata[0]]] = trim($linedata[1]); + } } - if (!$field) { - drupal_not_found(); - exit; + if ($mode == 'stream') { + file_delete($filename); } - - $form['field'] = array('#type' => 'value', '#value' => $field); - $form['form'] = array('#type' => 'value', '#value' => $pdf_form); - - return confirm_form($form, - t('Are you sure you want to delete the field %pdf_key?', array('%pdf_key' => $field->pdf_key)), - 'admin/content/fillpdf/form/'. $pdf_form->fid, - t('This action cannot be undone.'), t('Delete'), t('Cancel') - ); + return $fields; } -function fillpdf_field_delete_confirm_submit($form_id, &$form_values) { - db_query("DELETE FROM {fillpdf_fields} WHERE fid = %d AND pdf_key ='%s'", - $form_values['field']->fid, $form_values['field']->pdf_key); - drupal_set_message('Your field has been deleted.'); - return 'admin/content/fillpdf/form/'. $form_values['field']->fid; +function _fillpdf_get_file_contents($filepath, $error_goto = null) { + if ($error_goto && !(file_exists($filepath))) { + drupal_set_message("{$filepath} does not exist. Check your + filesystem settings, as well as http://drupal.org/node/764936", 'error'); + drupal_goto($error_goto); + } + $handle = fopen($filepath, "r"); + $content = fread($handle, filesize($filepath)); + fclose($handle); + return $content; } -/* - * Stores the updated $field in the database - */ -function fillpdf_update_field(&$pdf_form, &$field, $old_key) { - db_query("UPDATE {fillpdf_fields} SET label = '%s', pdf_key='%s', - value = '%s' WHERE fid = %d AND pdf_key = '%s'", - $field->label, $field->pdf_key, $field->value, - $pdf_form->fid, $old_key); +function _fillpdf_xmlrpc_request($url, $method) { + $args = func_get_args(); + $result = call_user_func_array('xmlrpc', $args); + $ret = new stdClass; + if (isset($result['error'])) { + drupal_set_message($result['error'], 'error'); + $ret->error = true; + } + else if ($result == false || xmlrpc_error()) { + $error = xmlrpc_error(); + $ret->error = true; + drupal_set_message("There was a problem contacting the Fill PDF service. + It maybe be down, or you may not have internet access. [ERROR {$error->code}: {$error->message}]", 'error'); + } + else { + $ret->data = $result['data']; + $ret->error = false; + } + return $ret; } /** - * This function generates the form fields from the specified PDF. It (1) sends a request to the iText - * servlet to parse the specified PDF, (2) iText returns an XML response with fields-mappings, this module - * parses the XML response & contsructs the fields. + * Retrieve the PDF's fields. */ -function fillpdf_generate_fields_from_pdf($fid) { - - $form_url=db_result(db_query("SELECT url FROM {fillpdf_forms} WHERE fid=%d", $fid)); - if ($fp = fopen($form_url, 'r')) { - $content = ''; - // keep reading until there's nothing left - while ($line = fread($fp, 1024)) { - $content .= $line; - } - } - - $result = xmlrpc(SERVLET_URL, 'fillpdf_xmlrpc.parse_pdf',base64_encode($content)); - $contents = base64_decode($result); - $xml = simplexml_load_string( $contents ); - - - //create fields - $i=1; - $weight=-10; - foreach ($xml->field as $field) { - $field_type=''; - switch ((int)$field['type']) { - case 5: //List - case 6: //Combobox - $field_type='select'; break; - - case 3: //Radiobutton - case 2: //Checkbox - $field_type='select'; break; - - case 0: //None - case 1: //Pushbutton - //return; - - case 4: //Text - case 7: //Signature - default: - $field_type='textfield'; break; - } - -// $new_field->label = $new_field->pdf_key = $field['name']; -// $new_field->type=$field_type; -// $fields[]=$new_field; -// $field['name']=(string)$field['name']; //d6 seems to have required this... - $field_name=(string)$field['name']; - if ($field_name) { - if (!(db_result(db_query("SELECT 1 FROM {fillpdf_fields} WHERE fid=%d AND pdf_key='%s'", $fid, $field_name)))) { - db_query("INSERT INTO {fillpdf_fields} (fid, pdf_key, label) VALUES(%d, '%s', '%s')", - $fid, $field_name, $field_name); - } - } - $i++; - } - - drupal_goto("admin/content/fillpdf/form/{$fid}/list"); +function fillpdf_get_fields($fid) { + $result = db_query('select * from {fillpdf_fields} where fid = %d', $fid); + $return = array(); + while ($result_array = db_fetch_array($result)) { + $return[$result_array['pdf_key']] = array( + 'label' => $result_array['label'], + 'value' => $result_array['value'], + ); + } + return $return; } -/** - * Generates the PDF ouput based on field values - * It (1) constructs the XFDF from the form's fields, (2) saves the XFDF to /files/xfdf/x.xfdf, - * (3) redirects to the servlet at SERVLET_URL which downloads this XFDF, merges it with the - * user-specified PDF, and returns the output. The SERVLET_URL construct is SERVLET_URL?fid=10&nid=10 - * where fid is this form's id and nid is the node id from which data will be pulled via tokens. - */ -function fillpdf_generate_pdf() { - $fid = $_GET['fid']; - $nid = $_GET['nid']; - - if (is_null($fid)) return; - $fillpdf_info = db_fetch_object(db_query("SELECT title, url FROM {fillpdf_forms} WHERE fid=%d", $fid)); - - //just give them empty pdf if no nid - if (!$nid) { - header("Location: {$fillpdf_info->url}"); - exit; - } - - $host = 'http://'. $_SERVER['SERVER_NAME']; - $node = node_load($nid); - $fields = array(); - $query = db_query("SELECT * FROM {fillpdf_fields} WHERE fid=%d", $fid); - while ($obj = db_fetch_object($query)) { - $str = token_replace($obj->value, $type = 'node', $object = $node); - $str = preg_replace('|<br />|', ' -', $str); - $fields[$obj->pdf_key] = $str; - } - - // get the XFDF file contents - include_once(drupal_get_path('module', 'fillpdf') .'/xfdf.inc'); - $xfdf_data = createXFDF($fillpdf_info->url, $fields); - $download_name = preg_replace('/[^a-zA-Z0-9_]/', '', $fillpdf_info->title) .'.pdf'; - //$download_name = preg_match('|\/[^\/].*$|',$fillpdf_info->url); - - if ($fp = fopen($fillpdf_info->url, 'r')) { - $pdf_data = ''; - // keep reading until there's nothing left - while ($line = fread($fp, 1024)) { - $pdf_data .= $line; - } - } - - $result = xmlrpc(SERVLET_URL, 'fillpdf_xmlrpc.merge_pdf',base64_encode($pdf_data),base64_encode($xfdf_data)); - if($result){ - header('Content-type:application/pdf'); - header('Content-disposition:attachment; filename="'.$download_name.'"'); - echo base64_decode($result); - exit; - }else{ - drupal_set_message('FillPDF servlet error, please contact tylerrenelle@gmail.com','error'); - drupal_goto("<front>"); - } -} diff --git a/webform_tokens.inc b/webform_tokens.inc new file mode 100644 index 0000000..3e43fbf --- /dev/null +++ b/webform_tokens.inc @@ -0,0 +1,147 @@ +<?php + +// $Id$ + +/** + * Implements hook_token_values(). + */ +function fillpdf_token_values($type, $object = NULL, $options = array()) { + // When making PDFs with fillpdf, this function is called twice, once with $type = 'node' and $object a node object, and once with $type = 'global' and $object = null. During node display, this function is only called once with $type = 'global' */ + // static $tokens = array(); + // static $run_once=false;if($run_once)return $tokens;$run_once=true; + + switch ($type) { + // case 'global': + case 'webform': + $submission = $object; + + $tokens['webform-meta-nid'] = $submission->nid; + $tokens['webform-meta-sid'] = $submission->sid; + $tokens['webform-meta-uid'] = $submission->uid; + $tokens['webform-meta-remote_addr'] = $submission->remote_addr; + $tokens['webform-meta-submitted'] = $submission->submitted; + + $fields = array(); + $q = db_query('SELECT cid, form_key, type, extra FROM {webform_component} WHERE nid = :nid', array(':nid' => $submission->nid)); + while ($component = db_fetch_array($q)) { + // initialize empty fields, so they don't show as [webform-val-text_field] in the pdf + if ( !is_array($submission->data[$component['cid']]) ) { + $submission->data[$component['cid']] = array(); + } + + // add cid, form_key, etc along with ['value'] + $submission->data[$component['cid']] += $component; + } + $tokens += _fillpdf_get_tokens_from_components($submission); // modify the submission + return $tokens; + } +} + +/** + * Implements hook_token_list(). + */ +function fillpdf_token_list($type = 'all') { + if ($type == 'webform' || $type == 'all') { + $tokens['webform']['webform-meta-nid'] = t("The webform's node id"); + $tokens['webform']['webform-meta-sid'] = t("The webform's submission id"); + $tokens['webform']['webform-meta-uid'] = t("The user's id who submitted the webform"); + $tokens['webform']['webform-meta-remote_addr'] = t("The user's ip address who submitted the webform"); + $tokens['webform']['webform-meta-submitted'] = t("The date the webform was submitted"); + + $fields = array(); + $q = db_query('SELECT name, form_key FROM {webform_component}'); + while ($component = db_fetch_array($q)) { + $tokens['webform']["webform-val-{$component['form_key']}"] = t("The value for webform component [{$component['name']}]"); + } + return $tokens; + } +} + +function _fillpdf_get_tokens_from_components($submission) { + $tokens = array(); + foreach ($submission->data as $cid => $component) { + // $tokens["webform-val-{$component['form_key']}"] = $submission->data[$component['cid']]['value'][0]; + + + // First, unserialize everything so we can work with them as arrays + switch ($component['type']) { + case 'fieldset': + case 'pagebreak': + break; + default: + + $fullvalue = false; + // For components with selectable options (including grids), make an array of options in the form array(safe_key => "Some readable option", ...) + $options = false; + if (is_string($component['extra'])) { + $component['extra'] = unserialize($component['extra']); + // Selects use "items" + if (is_string($component['extra']['items'])) { + $component['extra']['options'] = $component['extra']['items']; + } + // Grids use "options" + if (is_string($component['extra']['options'])) { + foreach (preg_split('/[\r\n]+/', $component['extra']['options']) as $_) { + if (strpos($_, '|') !== false) { + $option = explode('|', $_, 2); + $options["$option[0]"] = $option[1]; + } + else { + // Make sure the keys are strings + $options["$_"] = $_; + } + } + } + } + if ($options) { + $component['extra']['options'] = $options; + unset($options); + } + else { + $component['extra']['options'] = false; + } + } + + if ($component['value']) { + switch ($component['type']) { + case 'date': + // Create ISO 8601 date + if ($component['value'][2] && $component['value'][0] && $component['value'][1]) { + $value = sprintf('%04d-%02d-%02d', $component['value'][2], $component['value'][0], $component['value'][1]); + } + else { + $value = ''; + } + break; + case 'select': + case 'grid': + // Make webform-fullval token + $fullvalue = array(); + foreach ($component['value'] as $value) { + if ($component['extra']['options'][$value]) { + $fullvalue[] = $component['extra']['options'][$value]; + } + else { + $fullvalue[] = $value; + } + } + $fullvalue = implode(', ', $fullvalue); + // Don't break: every field gets a webform-val token + default: + // Usually there is only one value, so implode just removes the array + // Otherwise, separate the values with a comma + // BUG: There should probably be better handling for multiple values + $value = implode(', ', $component['value']); + } + } + else { + $value = ''; + } + $tokens['webform-val-' . $component['form_key']] = $value; + if ($fullvalue) { + $tokens['webform-fullval-' . $component['form_key']] = $fullvalue; + } + + } + return $tokens; +} diff --git a/xfdf.inc b/xfdf.inc index a95f593..86033d4 100644 --- a/xfdf.inc +++ b/xfdf.inc @@ -3,63 +3,65 @@ /** * createXFDF - * + * * Tales values passed via associative array and generates XFDF file format * with that data for the pdf address sullpiled. - * + * * @param string $file The pdf file - url or file path accepted * @param array $info data to use in key/value pairs no more than 2 dimensions * @param string $enc default UTF-8, match server output: default_charset in php.ini * @return string The XFDF data for acrobat reader to use in the pdf form file */ -function createXFDF($file, $info, $enc='UTF-8') { - $data='<?xml version="1.0" encoding="'. $enc .'"?>'."\n". - '<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">'."\n". - '<fields>'."\n"; - $data .= print_fields($info); - $data .= '</fields>'."\n". - '<ids original="'. md5($file) .'" modified="'. time() .'" />'."\n". - '<f href="'. $file .'" />'."\n". - '</xfdf>'."\n"; - return $data; +function createXFDF($file, $info, $enc = 'UTF-8') { + $data = '<?xml version="1.0" encoding="' . $enc . '"?>' . "\n" . + '<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">' . "\n" . + '<fields>' . "\n"; + $data .= print_fields($info); + $data .= '</fields>' . "\n" . + '<ids original="' . md5($file) . '" modified="' . REQUEST_TIME . '" />' . "\n" . + '<f href="' . $file . '" />' . "\n" . + '</xfdf>' . "\n"; + return $data; } function escape_string($str) { - if ($str == NULL) return $str; + if ($str == NULL) { + return $str; + } $str = str_replace(array('\\', '\''), array('\\\\', '\\\''), $str); return $str; } function print_fields($info) { - $fields=array(); + $fields = array(); foreach ($info as $field => $val) { $arr = explode('.', $field); $str .= '$fields'; foreach ($arr as $node) { $str .= "['{$node}']"; } - $str .= "='". escape_string($val) ."';"; + $str .= "='" . escape_string($val) . "';"; } eval($str); - - $str=''; - foreach ($fields as $field => $val) { + + $str = ''; + foreach ($fields as $field => $val) { print_fields_recurse($field, $val, $str); } return $str; } function print_fields_recurse($field, $val, &$str) { - - $str .= '<field name="'. $field .'">'."\n"; - if (is_array($val)) { + + $str .= '<field name="' . $field . '">' . "\n"; + if (is_array($val)) { foreach ($val as $field => $val) { print_fields_recurse($field, $val, $str); } } - else { - $str .= '<value>'. $val .'</value>'."\n"; + else { + $str .= '<value>' . $val . '</value>' . "\n"; } - $str .= '</field>'."\n"; + $str .= '</field>' . "\n"; } -- GitLab