print_pdf_dompdf.pages.inc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php
  2. /**
  3. * @file
  4. * Generates the PDF version using dompdf.
  5. *
  6. * This file is included by the print_pdf_dompdf module and includes the
  7. * functions that interface with the dompdf library.
  8. *
  9. * @ingroup print
  10. */
  11. /**
  12. * Implements hook_print_pdf_generate().
  13. */
  14. function print_pdf_dompdf_print_pdf_generate($html, $meta, $paper_size = NULL, $page_orientation = NULL) {
  15. module_load_include('inc', 'print', 'includes/print');
  16. $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
  17. if (empty($paper_size)) {
  18. $paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
  19. }
  20. if (empty($page_orientation)) {
  21. $page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
  22. }
  23. $images_via_file = variable_get('print_pdf_images_via_file', PRINT_PDF_IMAGES_VIA_FILE_DEFAULT);
  24. $unicode = TRUE;
  25. if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
  26. $font_subsetting = variable_get('print_pdf_dompdf_font_subsetting', PRINT_PDF_DOMPDF_FONT_SUBSETTING_DEFAULT);
  27. $unicode = variable_get('print_pdf_dompdf_unicode', PRINT_PDF_DOMPDF_UNICODE_DEFAULT);
  28. if (!defined('DOMPDF_ENABLE_PHP')) {
  29. define('DOMPDF_ENABLE_PHP', FALSE);
  30. }
  31. if (!defined('DOMPDF_ENABLE_REMOTE')) {
  32. define('DOMPDF_ENABLE_REMOTE', TRUE);
  33. }
  34. if (!defined('DOMPDF_TEMP_DIR')) {
  35. define('DOMPDF_TEMP_DIR', file_directory_temp());
  36. }
  37. if (!defined('DOMPDF_UNICODE_ENABLED')) {
  38. define('DOMPDF_UNICODE_ENABLED', $unicode);
  39. }
  40. if (!defined('DOMPDF_ENABLE_FONTSUBSETTING')) {
  41. define('DOMPDF_ENABLE_FONTSUBSETTING', $font_subsetting);
  42. }
  43. if (!defined('DOMPDF_FONT_CACHE')) {
  44. define('DOMPDF_FONT_CACHE', drupal_realpath('public://print_pdf/print_pdf_dompdf/fonts/'));
  45. }
  46. }
  47. $version = print_pdf_dompdf_pdf_tool_version($pdf_tool[1]);
  48. if (version_compare($version, '0.7', '<')) {
  49. // Version of dompdf is 0.6.* or 0.5.*.
  50. if (version_compare($version, '0.6', '<')) {
  51. // Version of dompdf is 0.5.
  52. spl_autoload_register('DOMPDF_autoload');
  53. }
  54. // Earlier dompdf versions could generate xml errors. Tell libxml to
  55. // hide them.
  56. libxml_use_internal_errors(TRUE);
  57. $dompdf = new DOMPDF();
  58. }
  59. else {
  60. // Version of dompdf is >= 0.7.
  61. $tool_path = dirname($pdf_tool[1]) . '/../autoload.inc.php';
  62. if (file_exists($tool_path)) {
  63. require_once $tool_path;
  64. }
  65. else {
  66. watchdog('print_pdf', 'Configured PDF tool does not exist at path: %path', array('%path' => $tool_path), WATCHDOG_ERROR);
  67. throw new Exception("Configured PDF tool does not exist, unable to generate PDF.");
  68. }
  69. $dompdf = new \Dompdf\Dompdf();
  70. $unicode = TRUE;
  71. if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
  72. $dompdf->set_option('enable_php', FALSE);
  73. $dompdf->set_option('enable_remote', TRUE);
  74. $dompdf->set_option('temp_dir', file_directory_temp());
  75. $dompdf->set_option('enable_font_subsetting', $font_subsetting);
  76. $dompdf->set_option('font_cache', drupal_realpath('public://print_pdf/print_pdf_dompdf/fonts/'));
  77. }
  78. }
  79. // Try to use local file access for image files.
  80. $html = _print_access_images_via_file($html, $images_via_file);
  81. // Remove all scripts due to security concerns.
  82. $html = preg_replace('!<script(.*?)>(.*?)</script>!is', '', $html);
  83. // Spaces in img URLs must be replaced with %20, when using external access.
  84. if (!$images_via_file) {
  85. $pattern = '!<(img\s[^>]*?)>!is';
  86. $html = preg_replace_callback($pattern, '_print_replace_spaces', $html);
  87. }
  88. // It seems dompdf has problems with something in system.css, don't use it.
  89. $html = preg_replace('!<link.*?modules/system/system.css.*?/>!', '', $html);
  90. $url_array = parse_url($meta['url']);
  91. $protocol = $url_array['scheme'] . '://';
  92. $host = $url_array['host'];
  93. $path = dirname($url_array['path']) . '/';
  94. $dompdf->set_base_path($path);
  95. $dompdf->set_host($host);
  96. $dompdf->set_paper(drupal_strtolower($paper_size), $page_orientation);
  97. $dompdf->set_protocol($protocol);
  98. // It seems dompdf can't handle footers cleanly, so disable the following.
  99. /* $html = theme('print_pdf_dompdf_footer', array('html' => $html)); */
  100. // If dompdf Unicode support is disabled, try to convert to ISO-8859-1 and
  101. // then to HTML entities.
  102. if (!$unicode) {
  103. // Convert the euro sign to an HTML entity.
  104. $html = str_replace('€', '&#0128;', $html);
  105. // Convert from UTF-8 to ISO 8859-1 and then to HTML entities.
  106. if (function_exists('utf8_decode')) {
  107. $html = utf8_decode($html);
  108. }
  109. // iconv fails silently when it encounters something that it doesn't know,
  110. // so don't use it.
  111. /*
  112. else if (function_exists('iconv')) {
  113. $html = iconv('UTF-8', 'ISO-8859-1', $html);
  114. }
  115. */
  116. elseif (function_exists('mb_convert_encoding')) {
  117. $html = mb_convert_encoding($html, 'ISO-8859-1', 'UTF-8');
  118. }
  119. elseif (function_exists('recode_string')) {
  120. $html = recode_string('UTF-8..ISO_8859-1', $html);
  121. }
  122. $html = htmlspecialchars_decode(htmlentities($html, ENT_NOQUOTES, 'ISO-8859-1'), ENT_NOQUOTES);
  123. }
  124. else {
  125. // Otherwise, ensure the content is properly formatted Unicode.
  126. $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
  127. }
  128. // Must get rid of tbody (dompdf goes into recursion).
  129. $html = preg_replace('!<tbody[^>]*?>|</tbody>!i', '', $html);
  130. $dompdf->load_html($html);
  131. $dompdf->render();
  132. return $dompdf->output();
  133. }
  134. /**
  135. * Format the dompdf footer contents.
  136. *
  137. * @param array $vars
  138. * An associative array containing:
  139. * - $html: contents of the body of the HTML from the original node.
  140. *
  141. * @return string
  142. * customized HTML text
  143. *
  144. * @ingroup themeable
  145. * @ingroup print_themeable
  146. */
  147. function theme_print_pdf_dompdf_footer($vars) {
  148. preg_match('!<div class="print-footer">(.*?)</div>!si', $vars['html'], $tpl_footer);
  149. if (isset($tpl_footer[1])) {
  150. $html = str_replace($tpl_footer[0], '', $vars['html']);
  151. $text = '<script type="text/php">
  152. if (isset($pdf)) {
  153. $font = Font_Metrics::get_font("verdana");;
  154. $size = 10;
  155. $color = array(0,0,0);
  156. $text_height = Font_Metrics::get_font_height($font, $size);
  157. $w = $pdf->get_width();
  158. $h = $pdf->get_height();
  159. $footer = $pdf->open_object();
  160. // Draw a line along the bottom
  161. $y = $h - 25;
  162. $pdf->line(15, $y, $w - 15, $y, $color, 1);
  163. $y += $text_height / 2;
  164. $pdf->page_text(15, $y, \'' . addslashes(strip_tags($tpl_footer[1])) . '\', $font, $size, $color);
  165. $pdf->close_object();
  166. $pdf->add_object($footer, "all");
  167. // Center the text
  168. $width = Font_Metrics::get_text_width("Page 1 of 2", $font, $size);
  169. $pagenumtxt = t("Page !n of !total", array("!n" => "{PAGE_NUM}", "!total" => "{PAGE_COUNT}"));
  170. $pdf->page_text($w - 15 - $width, $y, $pagenumtxt, $font, $size, $color);
  171. }
  172. </script>';
  173. return str_replace("<body>", "<body>" . $text, $html);
  174. }
  175. else {
  176. return $vars['html'];
  177. }
  178. }