Project

General

Profile

Paste
Download (15.6 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / print / print_pdf / print_pdf.module @ 76bdcd04

1
<?php
2

    
3
/**
4
 * @file
5
 * Displays Printer-friendly versions of Drupal pages.
6
 *
7
 * @ingroup print
8
 */
9

    
10
define('PRINT_PDF_PDF_TOOL_DEFAULT', FALSE);
11
define('PRINT_PDF_CONTENT_DISPOSITION_DEFAULT', 2);
12
define('PRINT_PDF_PAPER_SIZE_DEFAULT', 'A4');
13
define('PRINT_PDF_PAGE_ORIENTATION_DEFAULT', 'portrait');
14
define('PRINT_PDF_IMAGES_VIA_FILE_DEFAULT', 0);
15
define('PRINT_PDF_AUTOCONFIG_DEFAULT', 1);
16
define('PRINT_PDF_FILENAME_DEFAULT', '[site:name] - [node:title] - [node:changed:custom:Y-m-d]');
17
define('PRINT_PDF_CACHE_ENABLED_DEFAULT', 0);
18
// 1 day.
19
define('PRINT_PDF_CACHE_LIFETIME_DEFAULT', 86400);
20

    
21
/**
22
 * Implements hook_print_link().
23
 */
24
function print_pdf_print_link() {
25
  return array(
26
    'format' => 'pdf',
27
    'text' => t('PDF version'),
28
    'description' => t('Display a PDF version of this page.'),
29
    'path' => 'printpdf',
30
    'class' => 'print-pdf',
31
    'icon' => 'pdf_icon.png',
32
    'module' => 'print_pdf',
33
  );
34
}
35

    
36
/**
37
 * Implements hook_print_new_window_alter().
38
 */
39
function print_pdf_print_new_window_alter(&$new_window, $format) {
40
  $new_window = (variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT) == 1);
41
}
42

    
43
/**
44
 * Implements hook_permission().
45
 */
46
function print_pdf_permission() {
47
  return array(
48
    'access PDF version' => array(
49
      'title' => t('Access the PDF version'),
50
      'description' => t('View the PDF versions and the links to them in the original pages.'),
51
    ),
52
  );
53
}
54

    
55
/**
56
 * Implements hook_init().
57
 */
58
function print_pdf_init() {
59
  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
60
    $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
61
    $tool = explode('|', $print_pdf_pdf_tool);
62
    $function = $tool[0] . '_pdf_tool_info';
63
    $info = function_exists($function) ? $function() : array();
64

    
65
    if (isset($info['public_dirs'])) {
66
      foreach ($info['public_dirs'] as $dir) {
67
        $directory = 'public://print_pdf/' . $tool[0] . '/' . $dir;
68
        /** @var DrupalLocalStreamWrapper $wrapper */
69
        $wrapper = file_stream_wrapper_get_instance_by_uri($directory);
70
        $real_directory_path = $wrapper->getDirectoryPath() . "/" . file_uri_target($directory);
71
        $result = file_prepare_directory($real_directory_path, FILE_CREATE_DIRECTORY);
72
        if (!$result) {
73
          watchdog('print_pdf', 'Failed to create directory "%dir" for %tool.', array('%dir' => $directory, '%tool' => $tool[0]), WATCHDOG_CRITICAL);
74
        }
75
      }
76
    }
77
  }
78
  if (variable_get('print_pdf_cache_enabled', PRINT_PDF_CACHE_ENABLED_DEFAULT)) {
79
    $directory = print_pdf_cache_dir();
80
    $wrapper = file_stream_wrapper_get_instance_by_uri($directory);
81
    $real_directory_path = $wrapper->getDirectoryPath() . "/" . file_uri_target($directory);
82
    $result = file_prepare_directory($real_directory_path, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY);
83
    if (!$result) {
84
      watchdog('print_pdf', 'Failed to create directory "%dir" for print_pdf cache.', array('%dir' => $directory), WATCHDOG_CRITICAL);
85
    }
86
  }
87
}
88

    
89
/**
90
 * Implements hook_flush_caches().
91
 */
92
function print_pdf_flush_caches() {
93
  print_pdf_cache_delete();
94

    
95
  return array();
96
}
97

    
98
/**
99
 * Implements hook_menu().
100
 */
101
function print_pdf_menu() {
102
  $link = print_pdf_print_link();
103
  $items = array();
104

    
105
  $items[$link['path']] = array(
106
    'title' => 'Printer-friendly PDF',
107
    'page callback' => 'print_pdf_controller',
108
    'access arguments' => array('access PDF version'),
109
    'type' => MENU_CALLBACK,
110
    'file' => 'print_pdf.pages.inc',
111
  );
112
  $items[$link['path'] . '/' . $link['path']] = array(
113
    'access callback' => FALSE,
114
  );
115
  $items['admin/config/user-interface/print/pdf'] = array(
116
    'title' => 'PDF',
117
    'description' => 'Configure the settings of the PDF generation functionality.',
118
    'page callback' => 'drupal_get_form',
119
    'page arguments' => array('print_pdf_settings'),
120
    'access arguments'  => array('administer print'),
121
    'weight' => 3,
122
    'type' => MENU_LOCAL_TASK,
123
    'file' => 'print_pdf.admin.inc',
124
  );
125
  $items['admin/config/user-interface/print/pdf/options'] = array(
126
    'title' => 'Options',
127
    'weight' => -1,
128
    'type' => MENU_DEFAULT_LOCAL_TASK,
129
  );
130

    
131
  return $items;
132
}
133

    
134
/**
135
 * Implements hook_variable_info().
136
 */
137
function print_pdf_variable_info($options) {
138
  $link = print_pdf_print_link();
139

    
140
  $variable['print_pdf_link_text'] = array(
141
    'title' => t('PDF version'),
142
    'description' => t('Text used in the link to the PDF version.'),
143
    'type' => 'string',
144
    'default' => t($link['text']),
145
  );
146

    
147
  return $variable;
148
}
149

    
150
/**
151
 * Implements hook_block_info().
152
 */
153
function print_pdf_block_info() {
154
  $block['print_pdf-top']['info'] = t('Most PDFd');
155
  $block['print_pdf-top']['cache'] = DRUPAL_CACHE_GLOBAL;
156
  return $block;
157
}
158

    
159
/**
160
 * Implements hook_block_view().
161
 */
162
function print_pdf_block_view($delta = 0) {
163
  $block = array();
164
  switch ($delta) {
165
    case 'print_pdf-top':
166
      $block['subject'] = t('Most PDFd');
167
      $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)
168
        ->fetchAll();
169
      if (count($result)) {
170
        $items = array();
171
        foreach ($result as $obj) {
172
          $items[] = l(_print_get_title($obj->path), $obj->path);
173
        }
174
        $block['content'] = theme('item_list', array('items' => $items, 'type' => 'ul'));
175
      }
176
      break;
177
  }
178
  return $block;
179
}
180

    
181
/**
182
 * Implements hook_node_load().
183
 */
184
function print_pdf_node_load($nodes, $types) {
185
  $ids = array();
186
  foreach ($nodes as $node) {
187
    $ids[] = $node->nid;
188
  }
189

    
190
  $link = print_pdf_print_link();
191

    
192
  $size = 'print_' . $link['format'] . '_size';
193
  $orientation = 'print_' . $link['format'] . '_orientation';
194

    
195
  $result = db_query('SELECT nid, size, orientation FROM {print_pdf_node_conf} WHERE nid IN (:nids)', array(':nids' => $ids))->fetchAllAssoc('nid');
196

    
197
  foreach ($nodes as $node) {
198
    $node->{$size} = (isset($result[$node->nid]) && !empty($result[$node->nid]->size)) ? $result[$node->nid]->size : variable_get($size . '_' . $node->type);
199
    $node->{$orientation} = (isset($result[$node->nid]) && !empty($result[$node->nid]->orientation)) ? $result[$node->nid]->orientation : variable_get($orientation . '_' . $node->type);
200
  }
201
}
202

    
203
/**
204
 * Implements hook_node_insert().
205
 */
206
function print_pdf_node_insert($node) {
207
  print_pdf_node_update($node);
208
}
209

    
210
/**
211
 * Implements hook_node_update().
212
 */
213
function print_pdf_node_update($node) {
214
  if (user_access('administer print') || user_access('node-specific print configuration')) {
215
    $link = print_pdf_print_link();
216

    
217
    $size = 'print_' . $link['format'] . '_size';
218
    $orientation = 'print_' . $link['format'] . '_orientation';
219

    
220
    if (!isset($node->{$size})) {
221
      $node->{$size} = variable_get($size . '_' . $node->type);
222
    }
223
    if (!isset($node->{$orientation})) {
224
      $node->{$orientation} = variable_get($orientation . '_' . $node->type);
225
    }
226

    
227
    db_merge('print_pdf_node_conf')
228
      ->key(array('nid' => $node->nid))
229
      ->fields(array(
230
        'size' => $node->{$size},
231
        'orientation' => $node->{$orientation},
232
      ))
233
      ->execute();
234
  }
235

    
236
  print_pdf_cache_delete($node->nid);
237
}
238

    
239
/**
240
 * Implements hook_node_delete().
241
 */
242
function print_pdf_node_delete($node) {
243
  db_delete('print_pdf_page_counter')
244
    ->condition('path', 'node/' . $node->nid)
245
    ->execute();
246

    
247
  print_pdf_cache_delete($node->nid);
248
}
249

    
250
/**
251
 * Implements hook_form_alter().
252
 */
253
function print_pdf_form_alter(&$form, &$form_state, $form_id) {
254
  // Add the node-type settings to activate the printer-friendly version link.
255
  if ((user_access('administer print') || user_access('node-specific print configuration')) &&
256
      (($form_id == 'node_type_form') || !empty($form['#node_edit_form']))) {
257
    $link = print_pdf_print_link();
258

    
259
    $size = 'print_' . $link['format'] . '_size';
260
    $orientation = 'print_' . $link['format'] . '_orientation';
261

    
262
    $form['print']['print_' . $link['format']][$size] = array(
263
      '#type' => 'select',
264
      '#title' => t('Paper size'),
265
      '#options' => _print_pdf_paper_sizes(TRUE),
266
      '#description' => t('Choose the paper size of the generated PDF.'),
267
    );
268

    
269
    $form['print']['print_' . $link['format']][$orientation] = array(
270
      '#type' => 'select',
271
      '#title' => t('Page orientation'),
272
      '#options' => array(
273
        '' => 'Unchanged',
274
        'portrait' => t('Portrait'),
275
        'landscape' => t('Landscape'),
276
      ),
277
      '#description' => t('Choose the page orientation of the generated PDF.'),
278
    );
279

    
280
    if ($form_id == 'node_type_form') {
281
      $form['print']['print_' . $link['format']][$size]['#default_value'] = variable_get($size . '_' . $form['#node_type']->type);
282
      $form['print']['print_' . $link['format']][$orientation]['#default_value'] = variable_get($orientation . '_' . $form['#node_type']->type);
283
    }
284
    else {
285
      $node = $form['#node'];
286
      $form['print']['print_' . $link['format']][$size]['#default_value'] = isset($node->{$size}) ? $node->{$size} : variable_get($size . '_' . $node->type);
287
      $form['print']['print_' . $link['format']][$orientation]['#default_value'] = isset($node->{$orientation}) ? $node->{$orientation} : variable_get($orientation . '_' . $node->type);
288
    }
289
  }
290
}
291

    
292
/**
293
 * Auxiliary function to display a formatted PDF version link.
294
 *
295
 * Function made available so that developers may call this function from
296
 * their defined pages/blocks.
297
 *
298
 * @param string $path
299
 *   Path to be used in the link. If not specified, the current URL is used.
300
 * @param object $node
301
 *   Node object, to be used in checking node access. If the path argument is
302
 *   not provided, the path used will be node/nid.
303
 * @param string $location
304
 *   Where in the page where the link is being inserted ('link', 'corner',
305
 *   'block', 'help').
306
 *
307
 * @return bool
308
 *   string with the HTML link to the printer-friendly page
309
 *
310
 * @ingroup print_api
311
 */
312
function print_pdf_insert_link($path = NULL, $node = NULL, $location = '') {
313
  if (function_exists('print_ui_insert_link')) {
314
    return print_ui_insert_link(print_pdf_print_link(), array(
315
      'path' => $path,
316
      'node' => $node,
317
      'location' => $location,
318
    ));
319
  }
320
  else {
321
    return FALSE;
322
  }
323
}
324

    
325
/**
326
 * Check if the link to the PDF version is allowed depending on the settings.
327
 *
328
 * @param array $args
329
 *   Array containing the possible parameters:
330
 *    view_mode, node, type, path.
331
 *
332
 * @return bool
333
 *   FALSE if not allowed, TRUE otherwise
334
 */
335
function print_pdf_link_allowed($args) {
336
  $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
337

    
338
  return (user_access('access PDF version') && (!empty($print_pdf_pdf_tool)));
339
}
340

    
341
/**
342
 * Implements hook_cron().
343
 */
344
function print_pdf_cron() {
345
  print_pdf_cache_clean();
346
}
347

    
348
/**
349
 * Removes pdf files for nodes/paths if they are older than the lifetime.
350
 */
351
function print_pdf_cache_clean() {
352
  $lifetime = variable_get('print_pdf_cache_lifetime', PRINT_PDF_CACHE_LIFETIME_DEFAULT);
353

    
354
  if ($lifetime > 0) {
355
    $files = file_scan_directory(print_pdf_cache_dir(), '!\d+\.pdf$!');
356
    foreach ($files as $file) {
357
      // For all files in the cache directory, see when they were last accessed.
358
      $result = db_query("SELECT timestamp FROM {print_pdf_page_counter} WHERE path = :path", array(':path' => 'node/' . $file->name))
359
        ->fetchField();
360

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

    
369
/**
370
 * Returns the cache directory.
371
 *
372
 * @return string
373
 *   The scheme://path of the cache directory
374
 */
375
function print_pdf_cache_dir() {
376
  $scheme = 'private';
377
  if (!file_stream_wrapper_valid_scheme($scheme)) {
378
    $scheme = 'temporary';
379
  }
380
  return $scheme . '://print_pdf/cache';
381
}
382

    
383
/**
384
 * Deletes one or more files from the PDF cache directory.
385
 *
386
 * @param int $nid
387
 *   The node ID of the page for which the cached PDF should be deleted.
388
 *   If not provided, the entire cache directory will be deleted.
389
 */
390
function print_pdf_cache_delete($nid = NULL) {
391
  $directory = print_pdf_cache_dir();
392

    
393
  if ($nid) {
394
    $filename = $directory . '/' . $nid . '.pdf';
395
    if (is_file($filename)) {
396
      file_unmanaged_delete($filename);
397
    }
398
  }
399
  else {
400
    // If no nid is provided, flush the entire cache.
401
    if (is_dir($directory)) {
402
      file_unmanaged_delete_recursive($directory);
403
    }
404
  }
405
}
406

    
407
/**
408
 * Displays the PDF as inline or a downloadable file.
409
 *
410
 * @param string $pdf
411
 *   PDF content string.
412
 * @param string $filename
413
 *   Filename of the generated PDF.
414
 *
415
 * @return string
416
 *   The disposed PDF file
417
 */
418
function print_pdf_dispose_content($pdf, $filename) {
419
  if (headers_sent()) {
420
    exit('Unable to stream pdf: headers already sent');
421
  }
422
  header('Cache-Control: private');
423
  header('Content-Type: application/pdf');
424

    
425
  $content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
426
  $attachment = ($content_disposition == 2) ? 'attachment' : 'inline';
427

    
428
  header("Content-Disposition: $attachment; filename=\"$filename\"");
429

    
430
  echo $pdf;
431
  flush();
432

    
433
  return TRUE;
434
}
435

    
436
/**
437
 * Generate a PDF version of the provided HTML.
438
 *
439
 * @param string $html
440
 *   HTML content of the PDF.
441
 * @param array $meta
442
 *   Meta information to be used in the PDF
443
 *   - url: original URL
444
 *   - name: author's name
445
 *   - title: Page title
446
 *   - node: node object.
447
 * @param string $filename
448
 *   (optional) Filename of the generated PDF.
449
 * @param string $paper_size
450
 *   (optional) Paper size of the generated PDF.
451
 * @param string $page_orientation
452
 *   (optional) Page orientation of the generated PDF.
453
 *
454
 * @return string|null
455
 *   generated PDF page, or NULL in case of error
456
 *
457
 * @see print_pdf_controller()
458
 *
459
 * @ingroup print_api
460
 */
461
function print_pdf_generate_html($html, $meta, $filename = NULL, $paper_size = NULL, $page_orientation = NULL) {
462
  $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
463

    
464
  module_load_include('inc', $pdf_tool[0], $pdf_tool[0] . '.pages');
465

    
466
  $function = $pdf_tool[0] . '_print_pdf_generate';
467
  $pdf = function_exists($function) ? $function($html, $meta, $paper_size, $page_orientation) : NULL;
468
  if ($filename) {
469
    return print_pdf_dispose_content($pdf, $filename);
470
  }
471

    
472
  return $pdf;
473
}
474

    
475
/**
476
 * Implements hook_views_api().
477
 */
478
function print_pdf_views_api() {
479
  return array(
480
    'api' => 2.0,
481
    'path' => drupal_get_path('module', 'print_pdf'),
482
  );
483
}
484

    
485
/**
486
 * Lists all possible paper sizes.
487
 *
488
 * @param bool $include_default
489
 *   Flag indicating whether to include the tool's default value.
490
 *
491
 * @return array
492
 *   array of strings with the available paper sizes
493
 */
494
function _print_pdf_paper_sizes($include_default = FALSE) {
495
  $ret = ($include_default) ? array('' => 'Unchanged') : array();
496

    
497
  $ret += array(
498
    '4A0' => '4A0',
499
    '2A0' => '2A0',
500
    'A0' => 'A0',
501
    'A1' => 'A1',
502
    'A2' => 'A2',
503
    'A3' => 'A3',
504
    'A4' => 'A4',
505
    'A5' => 'A5',
506
    'A6' => 'A6',
507
    'A7' => 'A7',
508
    'A8' => 'A8',
509
    'A9' => 'A9',
510
    'A10' => 'A10',
511
    'B0' => 'B0',
512
    'B1' => 'B1',
513
    'B2' => 'B2',
514
    'B3' => 'B3',
515
    'B4' => 'B4',
516
    'B5' => 'B5',
517
    'B6' => 'B6',
518
    'B7' => 'B7',
519
    'B8' => 'B8',
520
    'B9' => 'B9',
521
    'B10' => 'B10',
522
    'C0' => 'C0',
523
    'C1' => 'C1',
524
    'C2' => 'C2',
525
    'C3' => 'C3',
526
    'C4' => 'C4',
527
    'C5' => 'C5',
528
    'C6' => 'C6',
529
    'C7' => 'C7',
530
    'C8' => 'C8',
531
    'C9' => 'C9',
532
    'C10' => 'C10',
533
    'RA0' => 'RA0',
534
    'RA1' => 'RA1',
535
    'RA2' => 'RA2',
536
    'RA3' => 'RA3',
537
    'RA4' => 'RA4',
538
    'SRA0' => 'SRA0',
539
    'SRA1' => 'SRA1',
540
    'SRA2' => 'SRA2',
541
    'SRA3' => 'SRA3',
542
    'SRA4' => 'SRA4',
543
    'LETTER' => 'Letter',
544
    'LEGAL' => 'Legal',
545
    'EXECUTIVE' => 'Executive',
546
    'FOLIO' => 'Folio',
547
  );
548

    
549
  return $ret;
550
}