You are here

print_pdf.module in Printer, email and PDF versions 7.2

Displays Printer-friendly versions of Drupal pages.

File

print_pdf/print_pdf.module
View source
<?php

/**
 * @file
 * Displays Printer-friendly versions of Drupal pages.
 *
 * @ingroup print
 */
define('PRINT_PDF_PDF_TOOL_DEFAULT', FALSE);
define('PRINT_PDF_CONTENT_DISPOSITION_DEFAULT', 2);
define('PRINT_PDF_PAPER_SIZE_DEFAULT', 'A4');
define('PRINT_PDF_PAGE_ORIENTATION_DEFAULT', 'portrait');
define('PRINT_PDF_IMAGES_VIA_FILE_DEFAULT', 0);
define('PRINT_PDF_AUTOCONFIG_DEFAULT', 1);
define('PRINT_PDF_FILENAME_DEFAULT', '[site:name] - [node:title] - [node:changed:custom:Y-m-d]');
define('PRINT_PDF_CACHE_ENABLED_DEFAULT', 0);

// 1 day.
define('PRINT_PDF_CACHE_LIFETIME_DEFAULT', 86400);

/**
 * Implements hook_print_link().
 */
function print_pdf_print_link() {
  return array(
    'format' => 'pdf',
    'text' => t('PDF version'),
    'description' => t('Display a PDF version of this page.'),
    'path' => 'printpdf',
    'class' => 'print-pdf',
    'icon' => 'pdf_icon.png',
    'module' => 'print_pdf',
  );
}

/**
 * Implements hook_print_new_window_alter().
 */
function print_pdf_print_new_window_alter(&$new_window, $format) {
  $new_window = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT) == 1;
}

/**
 * Implements hook_permission().
 */
function print_pdf_permission() {
  return array(
    'access PDF version' => array(
      'title' => t('Access the PDF version'),
      'description' => t('View the PDF versions and the links to them in the original pages.'),
    ),
  );
}

/**
 * Implements hook_init().
 */
function print_pdf_init() {
  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
    $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
    $tool = explode('|', $print_pdf_pdf_tool);
    $function = $tool[0] . '_pdf_tool_info';
    $info = function_exists($function) ? $function() : array();
    if (isset($info['public_dirs'])) {
      foreach ($info['public_dirs'] as $dir) {
        $directory = 'public://print_pdf/' . $tool[0] . '/' . $dir;

        /** @var DrupalLocalStreamWrapper $wrapper */
        $wrapper = file_stream_wrapper_get_instance_by_uri($directory);
        $real_directory_path = $wrapper
          ->getDirectoryPath() . "/" . file_uri_target($directory);
        $result = file_prepare_directory($real_directory_path, FILE_CREATE_DIRECTORY);
        if (!$result) {
          watchdog('print_pdf', 'Failed to create directory "%dir" for %tool.', array(
            '%dir' => $directory,
            '%tool' => $tool[0],
          ), WATCHDOG_CRITICAL);
        }
      }
    }
  }
  if (variable_get('print_pdf_cache_enabled', PRINT_PDF_CACHE_ENABLED_DEFAULT)) {
    $directory = print_pdf_cache_dir();
    $wrapper = file_stream_wrapper_get_instance_by_uri($directory);
    $real_directory_path = $wrapper
      ->getDirectoryPath() . "/" . file_uri_target($directory);
    $result = file_prepare_directory($real_directory_path, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY);
    if (!$result) {
      watchdog('print_pdf', 'Failed to create directory "%dir" for print_pdf cache.', array(
        '%dir' => $directory,
      ), WATCHDOG_CRITICAL);
    }
  }
}

/**
 * Implements hook_flush_caches().
 */
function print_pdf_flush_caches() {
  print_pdf_cache_delete();
  return array();
}

/**
 * Implements hook_menu().
 */
function print_pdf_menu() {
  $link = print_pdf_print_link();
  $items = array();
  $items[$link['path']] = array(
    'title' => 'Printer-friendly PDF',
    'page callback' => 'print_pdf_controller',
    'access arguments' => array(
      'access PDF version',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'print_pdf.pages.inc',
  );
  $items[$link['path'] . '/' . $link['path']] = array(
    'access callback' => FALSE,
  );
  $items['admin/config/user-interface/print/pdf'] = array(
    'title' => 'PDF',
    'description' => 'Configure the settings of the PDF generation functionality.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'print_pdf_settings',
    ),
    'access arguments' => array(
      'administer print',
    ),
    'weight' => 3,
    'type' => MENU_LOCAL_TASK,
    'file' => 'print_pdf.admin.inc',
  );
  $items['admin/config/user-interface/print/pdf/options'] = array(
    'title' => 'Options',
    'weight' => -1,
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  return $items;
}

/**
 * Implements hook_variable_info().
 */
function print_pdf_variable_info($options) {
  $link = print_pdf_print_link();
  $variable['print_pdf_link_text'] = array(
    'title' => t('PDF version'),
    'description' => t('Text used in the link to the PDF version.'),
    'type' => 'string',
    'default' => t($link['text']),
  );
  return $variable;
}

/**
 * Implements hook_block_info().
 */
function print_pdf_block_info() {
  $block['print_pdf-top']['info'] = t('Most PDFd');
  $block['print_pdf-top']['cache'] = DRUPAL_CACHE_GLOBAL;
  return $block;
}

/**
 * Implements hook_block_view().
 */
function print_pdf_block_view($delta = 0) {
  $block = array();
  switch ($delta) {
    case 'print_pdf-top':
      $block['subject'] = t('Most PDFd');
      $result = db_query_range("SELECT path FROM {print_pdf_page_counter} LEFT JOIN {node} n ON path = CONCAT('node/', n.nid) WHERE status <> 0 OR status IS NULL ORDER BY totalcount DESC", 0, 3)
        ->fetchAll();
      if (count($result)) {
        $items = array();
        foreach ($result as $obj) {
          $items[] = l(_print_get_title($obj->path), $obj->path);
        }
        $block['content'] = theme('item_list', array(
          'items' => $items,
          'type' => 'ul',
        ));
      }
      break;
  }
  return $block;
}

/**
 * Implements hook_node_load().
 */
function print_pdf_node_load($nodes, $types) {
  $ids = array();
  foreach ($nodes as $node) {
    $ids[] = $node->nid;
  }
  $link = print_pdf_print_link();
  $size = 'print_' . $link['format'] . '_size';
  $orientation = 'print_' . $link['format'] . '_orientation';
  try {
    $result = db_query('SELECT nid, size, orientation FROM {print_pdf_node_conf} WHERE nid IN (:nids)', array(
      ':nids' => $ids,
    ))
      ->fetchAllAssoc('nid');
  } catch (PDOException $ex) {

    // An exception may occur when a node is loaded before update 7203 runs.
    $result = array();
  }
  foreach ($nodes as $node) {
    $node->{$size} = isset($result[$node->nid]) && !empty($result[$node->nid]->size) ? $result[$node->nid]->size : variable_get($size . '_' . $node->type);
    $node->{$orientation} = isset($result[$node->nid]) && !empty($result[$node->nid]->orientation) ? $result[$node->nid]->orientation : variable_get($orientation . '_' . $node->type);
  }
}

/**
 * Implements hook_node_insert().
 */
function print_pdf_node_insert($node) {
  print_pdf_node_update($node);
}

/**
 * Implements hook_node_update().
 */
function print_pdf_node_update($node) {

  // If no global user object, the user_access call will fail.
  if (!isset($GLOBALS['user']) || !is_object($GLOBALS['user'])) {
    return;
  }
  if (user_access('administer print') || user_access('node-specific print configuration')) {
    $link = print_pdf_print_link();
    $size = 'print_' . $link['format'] . '_size';
    $orientation = 'print_' . $link['format'] . '_orientation';
    if (!isset($node->{$size})) {
      $node->{$size} = variable_get($size . '_' . $node->type);
    }
    if (!isset($node->{$orientation})) {
      $node->{$orientation} = variable_get($orientation . '_' . $node->type);
    }
    db_merge('print_pdf_node_conf')
      ->key(array(
      'nid' => $node->nid,
    ))
      ->fields(array(
      'size' => $node->{$size},
      'orientation' => $node->{$orientation},
    ))
      ->execute();
  }

  //For a book page, not only delete the PDF file for the page but also delete the caching PDF file for the entire book.
  if (isset($node->book) && isset($node->book['bid'])) {

    //Delete the book PDF file.
    print_pdf_cache_delete($node->book['bid']);
  }
  print_pdf_cache_delete($node->nid);
}

/**
 * Implements hook_node_delete().
 */
function print_pdf_node_delete($node) {
  db_delete('print_pdf_page_counter')
    ->condition('path', 'node/' . $node->nid)
    ->execute();
  print_pdf_cache_delete($node->nid);
}

/**
 * Implements hook_form_alter().
 */
function print_pdf_form_alter(&$form, &$form_state, $form_id) {

  // Add the node-type settings to activate the printer-friendly version link.
  if ((user_access('administer print') || user_access('node-specific print configuration')) && ($form_id == 'node_type_form' || !empty($form['#node_edit_form']))) {
    $link = print_pdf_print_link();
    $size = 'print_' . $link['format'] . '_size';
    $orientation = 'print_' . $link['format'] . '_orientation';
    $form['print']['print_' . $link['format']][$size] = array(
      '#type' => 'select',
      '#title' => t('Paper size'),
      '#options' => _print_pdf_paper_sizes(TRUE),
      '#description' => t('Choose the paper size of the generated PDF.'),
    );
    $form['print']['print_' . $link['format']][$orientation] = array(
      '#type' => 'select',
      '#title' => t('Page orientation'),
      '#options' => array(
        '' => 'Unchanged',
        'portrait' => t('Portrait'),
        'landscape' => t('Landscape'),
      ),
      '#description' => t('Choose the page orientation of the generated PDF.'),
    );
    if ($form_id == 'node_type_form') {
      $form['print']['print_' . $link['format']][$size]['#default_value'] = variable_get($size . '_' . $form['#node_type']->type);
      $form['print']['print_' . $link['format']][$orientation]['#default_value'] = variable_get($orientation . '_' . $form['#node_type']->type);
    }
    else {
      $node = $form['#node'];
      $form['print']['print_' . $link['format']][$size]['#default_value'] = isset($node->{$size}) ? $node->{$size} : variable_get($size . '_' . $node->type);
      $form['print']['print_' . $link['format']][$orientation]['#default_value'] = isset($node->{$orientation}) ? $node->{$orientation} : variable_get($orientation . '_' . $node->type);
    }
  }
}

/**
 * Auxiliary function to display a formatted PDF version link.
 *
 * Function made available so that developers may call this function from
 * their defined pages/blocks.
 *
 * @param string $path
 *   Path to be used in the link. If not specified, the current URL is used.
 * @param object $node
 *   Node object, to be used in checking node access. If the path argument is
 *   not provided, the path used will be node/nid.
 * @param string $location
 *   Where in the page where the link is being inserted ('link', 'corner',
 *   'block', 'help').
 *
 * @return bool
 *   string with the HTML link to the printer-friendly page
 *
 * @ingroup print_api
 */
function print_pdf_insert_link($path = NULL, $node = NULL, $location = '') {
  if (function_exists('print_ui_insert_link')) {
    return print_ui_insert_link(print_pdf_print_link(), array(
      'path' => $path,
      'node' => $node,
      'location' => $location,
    ));
  }
  else {
    return FALSE;
  }
}

/**
 * Check if the link to the PDF version is allowed depending on the settings.
 *
 * @param array $args
 *   Array containing the possible parameters:
 *    view_mode, node, type, path.
 *
 * @return bool
 *   FALSE if not allowed, TRUE otherwise
 */
function print_pdf_link_allowed($args) {
  $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
  return user_access('access PDF version') && !empty($print_pdf_pdf_tool);
}

/**
 * Implements hook_cron().
 */
function print_pdf_cron() {
  print_pdf_cache_clean();
}

/**
 * Removes pdf files for nodes/paths if they are older than the lifetime.
 */
function print_pdf_cache_clean() {
  $lifetime = variable_get('print_pdf_cache_lifetime', PRINT_PDF_CACHE_LIFETIME_DEFAULT);
  if ($lifetime > 0) {
    $files = file_scan_directory(print_pdf_cache_dir(), '!\\d+\\.pdf$!');
    foreach ($files as $file) {

      // For all files in the cache directory, see when they were last accessed.
      $result = db_query("SELECT timestamp FROM {print_pdf_page_counter} WHERE path = :path", array(
        ':path' => 'node/' . $file->name,
      ))
        ->fetchField();

      // Keep the file only if last access was within the cache max life value.
      if ($result === FALSE || $result + $lifetime < REQUEST_TIME) {
        print_pdf_cache_delete($file->name);
      }
    }
  }
}

/**
 * Returns the cache directory.
 *
 * @return string
 *   The scheme://path of the cache directory
 */
function print_pdf_cache_dir() {
  global $language_url;
  $scheme = 'private';
  if (!file_stream_wrapper_valid_scheme($scheme)) {
    $scheme = 'temporary';
  }
  return $scheme . '://print_pdf/cache/' . $language_url->language;
}

/**
 * Deletes one or more files from the PDF cache directory.
 *
 * @param int $nid
 *   The node ID of the page for which the cached PDF should be deleted.
 *   If not provided, the entire cache directory will be deleted.
 */
function print_pdf_cache_delete($nid = NULL) {
  $directory = print_pdf_cache_dir();
  if ($nid) {
    $filename = $directory . '/' . $nid . '.pdf';
    if (is_file($filename)) {
      file_unmanaged_delete($filename);
    }
  }
  else {

    // If no nid is provided, flush the entire cache.
    if (is_dir($directory)) {
      file_unmanaged_delete_recursive($directory);
    }
  }
}

/**
 * Displays the PDF as inline or a downloadable file.
 *
 * @param string $pdf
 *   PDF content string.
 * @param string $filename
 *   Filename of the generated PDF.
 *
 * @return string
 *   The disposed PDF file
 */
function print_pdf_dispose_content($pdf, $filename) {
  if (headers_sent()) {
    exit('Unable to stream pdf: headers already sent');
  }
  header('Cache-Control: private');
  header('Content-Type: application/pdf');
  $content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
  $attachment = $content_disposition == 2 ? 'attachment' : 'inline';
  header("Content-Disposition: {$attachment}; filename=\"{$filename}\"");
  echo $pdf;
  flush();
  return TRUE;
}

/**
 * Generate a PDF version of the provided HTML.
 *
 * @param string $html
 *   HTML content of the PDF.
 * @param array $meta
 *   Meta information to be used in the PDF
 *   - url: original URL
 *   - name: author's name
 *   - title: Page title
 *   - node: node object.
 * @param string $filename
 *   (optional) Filename of the generated PDF.
 * @param string $paper_size
 *   (optional) Paper size of the generated PDF.
 * @param string $page_orientation
 *   (optional) Page orientation of the generated PDF.
 *
 * @return string|null
 *   generated PDF page, or NULL in case of error
 *
 * @see print_pdf_controller()
 *
 * @ingroup print_api
 */
function print_pdf_generate_html($html, $meta, $filename = NULL, $paper_size = NULL, $page_orientation = NULL) {
  $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
  module_load_include('inc', $pdf_tool[0], $pdf_tool[0] . '.pages');
  $function = $pdf_tool[0] . '_print_pdf_generate';
  $pdf = function_exists($function) ? $function($html, $meta, $paper_size, $page_orientation) : NULL;
  if ($filename) {
    return print_pdf_dispose_content($pdf, $filename);
  }
  return $pdf;
}

/**
 * Implements hook_views_api().
 */
function print_pdf_views_api() {
  return array(
    'api' => 2.0,
    'path' => drupal_get_path('module', 'print_pdf'),
  );
}

/**
 * Lists all possible paper sizes.
 *
 * @param bool $include_default
 *   Flag indicating whether to include the tool's default value.
 *
 * @return array
 *   array of strings with the available paper sizes
 */
function _print_pdf_paper_sizes($include_default = FALSE) {
  $ret = $include_default ? array(
    '' => 'Unchanged',
  ) : array();
  $ret += array(
    '4A0' => '4A0',
    '2A0' => '2A0',
    'A0' => 'A0',
    'A1' => 'A1',
    'A2' => 'A2',
    'A3' => 'A3',
    'A4' => 'A4',
    'A5' => 'A5',
    'A6' => 'A6',
    'A7' => 'A7',
    'A8' => 'A8',
    'A9' => 'A9',
    'A10' => 'A10',
    'B0' => 'B0',
    'B1' => 'B1',
    'B2' => 'B2',
    'B3' => 'B3',
    'B4' => 'B4',
    'B5' => 'B5',
    'B6' => 'B6',
    'B7' => 'B7',
    'B8' => 'B8',
    'B9' => 'B9',
    'B10' => 'B10',
    'C0' => 'C0',
    'C1' => 'C1',
    'C2' => 'C2',
    'C3' => 'C3',
    'C4' => 'C4',
    'C5' => 'C5',
    'C6' => 'C6',
    'C7' => 'C7',
    'C8' => 'C8',
    'C9' => 'C9',
    'C10' => 'C10',
    'RA0' => 'RA0',
    'RA1' => 'RA1',
    'RA2' => 'RA2',
    'RA3' => 'RA3',
    'RA4' => 'RA4',
    'SRA0' => 'SRA0',
    'SRA1' => 'SRA1',
    'SRA2' => 'SRA2',
    'SRA3' => 'SRA3',
    'SRA4' => 'SRA4',
    'LETTER' => 'Letter',
    'LEGAL' => 'Legal',
    'EXECUTIVE' => 'Executive',
    'FOLIO' => 'Folio',
  );
  return $ret;
}

Related topics

Functions

Namesort descending Description
print_pdf_block_info Implements hook_block_info().
print_pdf_block_view Implements hook_block_view().
print_pdf_cache_clean Removes pdf files for nodes/paths if they are older than the lifetime.
print_pdf_cache_delete Deletes one or more files from the PDF cache directory.
print_pdf_cache_dir Returns the cache directory.
print_pdf_cron Implements hook_cron().
print_pdf_dispose_content Displays the PDF as inline or a downloadable file.
print_pdf_flush_caches Implements hook_flush_caches().
print_pdf_form_alter Implements hook_form_alter().
print_pdf_generate_html Generate a PDF version of the provided HTML.
print_pdf_init Implements hook_init().
print_pdf_insert_link Auxiliary function to display a formatted PDF version link.
print_pdf_link_allowed Check if the link to the PDF version is allowed depending on the settings.
print_pdf_menu Implements hook_menu().
print_pdf_node_delete Implements hook_node_delete().
print_pdf_node_insert Implements hook_node_insert().
print_pdf_node_load Implements hook_node_load().
print_pdf_node_update Implements hook_node_update().
print_pdf_permission Implements hook_permission().
print_pdf_print_link Implements hook_print_link().
print_pdf_print_new_window_alter Implements hook_print_new_window_alter().
print_pdf_variable_info Implements hook_variable_info().
print_pdf_views_api Implements hook_views_api().
_print_pdf_paper_sizes Lists all possible paper sizes.

Constants