From c1bf6e19b89b33b1a6be778f888108ded3f57bf3 Mon Sep 17 00:00:00 2001 From: Kevin Kaland <kevin@wizonesolutions.com> Date: Sun, 16 Oct 2011 03:48:23 -0700 Subject: [PATCH] Issue #1151112: Allow saving filled PDFs as files. --- fillpdf.admin.inc | 34 +++++++++++++++-- fillpdf.install | 11 ++++++ fillpdf.module | 97 ++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 122 insertions(+), 20 deletions(-) diff --git a/fillpdf.admin.inc b/fillpdf.admin.inc index 23c2954..85517b7 100644 --- a/fillpdf.admin.inc +++ b/fillpdf.admin.inc @@ -235,14 +235,42 @@ function fillpdf_form_edit($form, &$form_state, $fid) { $form['pdf_info']['sample_populate'] = array( '#type' => 'item', '#title' => 'Sample PDF', - '#description' => l("See which fields are which in this PDF", fillpdf_pdf_link($fid, null, null, true)), + '#description' => l("See which fields are which in this PDF", fillpdf_pdf_link($fid, null, null, true)) . '<br />' . + t('If you have set a custom path on this PDF, the sample will be saved there silently.'), ); $form['pdf_info']['form_id'] = array( '#type' => 'item', '#title' => 'Form Info', '#description' => "Form ID: [$fid]. Populate this form with node IDs, such as /fillpdf?fid=$fid&nid=10<br/>", ); - + $form['destination_path'] = array( + '#type' => 'textfield', + '#title' => t('Custom path for generated PDFs'), + '#description' => t("<p>By default, filled PDFs are not saved to disk; they are simply sent + directly to the browser for download. Enter a path here to change this behavior (tokens allowed). + <strong>Warning! Unless you include the &download=1 flag in the Fill PDF URL, PDFs will only + be saved to disk <em>and won't</em> be sent to the browser as well.</strong></p><p>The path + you specify must be in one of the following two formats:<br /> + <ul> + <li><em>path/to/directory</em> (path will be treated as relative to + your <em>files</em> directory)</li> + <li><em>/absolute/path/to/directory</em> (path will be treated as relative to your entire + filesystem)</li> + </ul> + Note that, in both cases, you are responsible for ensuring that the user under which PHP is running can write to this path. Do not include a trailing slash.</p>"), + '#maxlength' => 255, + '#default_value' => $pdf_form->destination_path, + ); + $form['tokens_fieldset'] = array( + '#type' => 'fieldset', + '#title' => 'Tokens', + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + $form['tokens_fieldset']['tokens'] = array( + '#theme' => 'token_tree', + '#token_types' => array('node', 'webform'), + ); $form['submit'] = array( '#type' => 'submit', @@ -252,7 +280,6 @@ function fillpdf_form_edit($form, &$form_state, $fid) { '#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 @@ -304,6 +331,7 @@ function fillpdf_form_edit_submit($form, &$form_state) { db_update('fillpdf_forms') ->fields(array( 'title' => $form_state['values']['title'], + 'destination_path' => $form_state['values']['destination_path'], )) ->condition('fid', $form['#pdf_form']->fid) ->execute(); diff --git a/fillpdf.install b/fillpdf.install index 3167c43..2fe5a94 100644 --- a/fillpdf.install +++ b/fillpdf.install @@ -29,6 +29,11 @@ function fillpdf_schema() { 'length' => 255, 'not null' => TRUE, ), + 'destination_path' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE + ), ), 'primary key' => array('fid'), ); @@ -77,3 +82,9 @@ function fillpdf_uninstall() { } +/** + * Add field to store destination path for saving PDFs as files. + */ +function fillpdf_update_7001() { + db_add_field('fillpdf_forms', 'destination_path', array('type' => 'varchar', 'length' => 255, 'not null' => FALSE)); +} diff --git a/fillpdf.module b/fillpdf.module index 27fe482..5b72880 100644 --- a/fillpdf.module +++ b/fillpdf.module @@ -187,8 +187,10 @@ function fillpdf_parse_uri() { 'webform' => '', 'webforms' => '', 'fid' => '', - 'sample' => '' + 'sample' => '', + 'download' => '', ); + $force_download = FALSE; //this function called multiple times, cut down on DB calls // static $get;if($get)return $get; @@ -202,24 +204,27 @@ function fillpdf_parse_uri() { if ( $_GET['webform'] || $_GET['webforms'] ) { $webforms = ( $_GET['webform'] ? array($_GET['webform']) : $_GET['webforms'] ); } - - fillpdf_merge_pdf($fid, $nids, $webforms, $sample); + + if (isset($_GET['download']) && (int) $_GET['download'] == 1) { + $force_download = TRUE; + } + fillpdf_merge_pdf($fid, $nids, $webforms, $sample, $force_download); } - /** - * Documentation stub * @return doesn't return anything, actually constructs a page from scratch (pdf content-type) + * and sends it to the browser or saves it, depending on if a custom path is configured + * or not. * @seealso fillpdf_pdf_link for $_GET params */ -function fillpdf_merge_pdf($fid, $nids = null, $webform_arr = null, $sample = null) { +function fillpdf_merge_pdf($fid, $nids = null, $webform_arr = null, $sample = null, $force_download = FALSE) { // Case 1: No $fid if (is_null($fid)) { drupal_set_message('Fillpdf Form ID required to print a PDF', 'warning'); drupal_goto(); } - $fillpdf_info = db_query("SELECT title, url FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $fid))->fetch(); + $fillpdf_info = db_query("SELECT title, url, destination_path FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $fid))->fetch(); // Case 2: Only $fid -- just give them empty pdf if (!empty($nodes) && !empty($webforms) && !is_null($sample)) { $host = url('', array('absolute' => true)); @@ -265,12 +270,14 @@ function fillpdf_merge_pdf($fid, $nids = null, $webform_arr = null, $sample = nu drupal_exit(); } - $fields = array(); + $fields = $token_objects = array(); $query = db_query("SELECT * FROM {fillpdf_fields} WHERE fid = :fid", array(':fid' => $fid)); foreach ($query as $obj) { // Fill a sample PDF & return if ($sample == 'true') { $fields[$obj->pdf_key] = $obj->pdf_key; + // If sampling, return to the form edit page + $_GET['destination'] = "admin/structure/fillpdf/$fid"; } else { // multiple nids, #516840 @@ -283,6 +290,7 @@ function fillpdf_merge_pdf($fid, $nids = null, $webform_arr = null, $sample = nu foreach ($nodes as $node) { $token = token_replace($obj->value, array('node' => $node)); if ($token) { + $token_objects['node'] = $node; break; } } @@ -308,6 +316,7 @@ function fillpdf_merge_pdf($fid, $nids = null, $webform_arr = null, $sample = nu foreach ($webforms as $webform) { $token = token_replace($obj->value, array('webform' => $webform['submission'])); if ($token) { + $token_objects['webform'] = $webform['submission']; break; } } @@ -321,8 +330,7 @@ function fillpdf_merge_pdf($fid, $nids = null, $webform_arr = null, $sample = nu } } - $download_name = preg_replace('/[^a-zA-Z0-9_]/', '', $fillpdf_info->title) . '.pdf'; - //$download_name = preg_match('|\/[^\/].*$|',$fillpdf_info->url); + $output_name = preg_replace('/[^a-zA-Z0-9_]/', '', $fillpdf_info->title) .'.pdf'; $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); @@ -360,19 +368,46 @@ function fillpdf_merge_pdf($fid, $nids = null, $webform_arr = null, $sample = nu if ($webform_arr) $node = $webform['webform']; - // 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, - )); + if (!empty($node)) { + // 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, + )); + } + + if (!empty($fillpdf_info->destination_path)) { + $destination_path = _fillpdf_process_destination_path($fillpdf_info->destination_path, $token_objects); + $path_exists = file_prepare_directory($destination_path, FILE_CREATE_DIRECTORY); + if ($path_exists === FALSE) { + watchdog('fillpdf', "The path %destination_path does not exist and could not be + automatically created. Therefore, the previous submission was not saved. If + the URL contained download=1, then the PDF was still sent to the user's browser. + If the destination path looks wrong and you have used tokens, check that you have + used the correct token and that it is available to Fill PDF at the time of PDF + generation.", + array('%destination_path' => $destination_path)); + } + else { + // Full steam ahead! + file_save_data($data, $destination_path . "/$output_name", FILE_EXISTS_RENAME); + } + if ($force_download === FALSE) { + // Allow the "destination" query string parameter to be used + // e.g. fillpdf?nid=1&fid=1&destination=node/1 + // If no destination is provided, drupal_goto() will send the + // user to the front page. + drupal_goto(); + } + } drupal_add_http_header("Pragma", "public"); drupal_add_http_header('Expires', 0); drupal_add_http_header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0'); drupal_add_http_header('Content-type', 'application-download'); drupal_add_http_header('Content-Length', strlen($data)); - drupal_add_http_header('Content-disposition', 'attachment; filename="' . $download_name . '"'); + drupal_add_http_header('Content-disposition', 'attachment; filename="' . $output_name . '"'); drupal_add_http_header('Content-Transfer-Encoding', 'binary'); echo $data; drupal_exit(); @@ -619,3 +654,31 @@ function fillpdf_get_fields($fid) { return $return; } +function _fillpdf_process_destination_path($destination_path, $token_objects) { + // Two formats of $destination_path are possible: + // 1) /absolute/path/to/directory + // 2) path/below/files/directory + // So, first: Does it begin with a forward slash? + $orig_path = $destination_path; + $destination_path = trim($orig_path); + // Replace any applicable tokens + $types = array(); + if (isset($token_objects['node'])) { + $types[] = 'node'; + } + elseif (isset($token_objects['webform'])) { + $types[] = 'webform'; + } + foreach ($types as $type) { + $destination_path = token_replace($destination_path, array($type => $token_objects[$type])); + } + if (substr($destination_path, 0, 1) == '/') { + // No further modifications needed + } + else { + // Slap on the files directory in front and return it + $destination_path = file_build_uri($destination_path); + } + return $destination_path; +} + -- GitLab