Revision 76bdcd04
Added by Assos Assos almost 6 years ago
drupal7/sites/all/modules/print/print_pdf/print_pdf.pages.inc | ||
---|---|---|
2 | 2 |
|
3 | 3 |
/** |
4 | 4 |
* @file |
5 |
* Generates the PDF versions of the pages |
|
5 |
* Generates the PDF versions of the pages.
|
|
6 | 6 |
* |
7 | 7 |
* This file is included by the print_pdf module and includes the |
8 | 8 |
* functions that interface with the PDF generation packages. |
... | ... | |
13 | 13 |
module_load_include('inc', 'print', 'print.pages'); |
14 | 14 |
|
15 | 15 |
/** |
16 |
* Generate a PDF version of the printer-friendly page |
|
16 |
* Generate a PDF version of the printer-friendly page.
|
|
17 | 17 |
* |
18 | 18 |
* @see print_controller() |
19 | 19 |
* @see _print_pdf_dompdf() |
20 | 20 |
* @see _print_pdf_tcpdf() |
21 | 21 |
*/ |
22 | 22 |
function print_pdf_controller() { |
23 |
// Disable caching for generated PDFs, as Drupal doesn't ouput the proper headers from the cache |
|
23 |
// Disable caching for generated PDFs, as Drupal doesn't output the proper |
|
24 |
// headers from the cache. |
|
24 | 25 |
$GLOBALS['conf']['cache'] = FALSE; |
25 | 26 |
|
26 | 27 |
$args = func_get_args(); |
27 | 28 |
$path = filter_xss(implode('/', $args)); |
28 |
$cid = isset($_GET['comment']) ? (int)$_GET['comment'] : NULL; |
|
29 |
$cid = isset($_GET['comment']) ? (int) $_GET['comment'] : NULL;
|
|
29 | 30 |
|
30 |
// Handle the query |
|
31 |
// Handle the query.
|
|
31 | 32 |
$query = $_GET; |
32 | 33 |
unset($query['q']); |
33 | 34 |
|
35 |
$node = NULL; |
|
34 | 36 |
if (!empty($path)) { |
35 | 37 |
if ($alias = drupal_lookup_path('source', $path)) { |
36 |
// Alias |
|
38 |
// Alias.
|
|
37 | 39 |
$path_arr = explode('/', $alias); |
38 | 40 |
$node = node_load($path_arr[1]); |
39 | 41 |
} |
40 | 42 |
elseif (ctype_digit($args[0])) { |
41 |
// normal nid
|
|
43 |
// Normal nid.
|
|
42 | 44 |
$node = node_load($args[0]); |
43 | 45 |
} |
44 | 46 |
|
... | ... | |
49 | 51 |
else { |
50 | 52 |
$pdf_filename = token_replace($pdf_filename, array('site'), array('clear' => TRUE)); |
51 | 53 |
if (empty($pdf_filename)) { |
52 |
// If empty, use a fallback solution |
|
54 |
// If empty, use a fallback solution.
|
|
53 | 55 |
$pdf_filename = str_replace('/', '_', $path); |
54 | 56 |
} |
55 | 57 |
} |
... | ... | |
70 | 72 |
exit; |
71 | 73 |
} |
72 | 74 |
|
73 |
$nodepath = (isset($node->path) && is_string($node->path)) ? drupal_get_normal_path($node->path) : 'node/' . $path;
|
|
75 |
$nodepath = (isset($node->nid)) ? 'node/' . $node->nid : drupal_get_normal_path($path);
|
|
74 | 76 |
db_merge('print_pdf_page_counter') |
75 | 77 |
->key(array('path' => $nodepath)) |
76 | 78 |
->fields(array( |
77 |
'totalcount' => 1,
|
|
78 |
'timestamp' => REQUEST_TIME,
|
|
79 |
'totalcount' => 1, |
|
80 |
'timestamp' => REQUEST_TIME, |
|
79 | 81 |
)) |
80 | 82 |
->expression('totalcount', 'totalcount + 1') |
81 | 83 |
->execute(); |
... | ... | |
83 | 85 |
drupal_exit(); |
84 | 86 |
} |
85 | 87 |
|
86 |
function print_pdf_generate_path($path, $query = NULL, $cid = NULL, $pdf_filename = NULL) { |
|
87 |
global $base_url; |
|
88 |
|
|
89 |
$print = print_controller($path, $query, $cid, PRINT_PDF_FORMAT); |
|
90 |
if ($print === FALSE) { |
|
91 |
return; |
|
92 |
} |
|
93 |
|
|
94 |
// Img elements must be set to absolute |
|
95 |
$pattern = '!<(img\s[^>]*?)>!is'; |
|
96 |
$print['content'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['content']); |
|
97 |
$print['logo'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['logo']); |
|
98 |
$print['footer_message'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['footer_message']); |
|
99 |
|
|
100 |
// Send to printer option causes problems with PDF |
|
101 |
$print['sendtoprinter'] = ''; |
|
102 |
|
|
103 |
$node = $print['node']; |
|
104 |
$html = theme('print', array('print' => $print, 'type' => PRINT_PDF_FORMAT, 'node' => $node)); |
|
105 |
|
|
106 |
// Convert the a href elements, to make sure no relative links remain |
|
107 |
$pattern = '!<(a\s[^>]*?)>!is'; |
|
108 |
$html = preg_replace_callback($pattern, '_print_rewrite_urls', $html); |
|
109 |
// And make anchor links relative again, to permit in-PDF navigation |
|
110 |
$html = preg_replace("!${base_url}/" . PRINTPDF_PATH . '/.*?#!', '#', $html); |
|
111 |
|
|
112 |
return print_pdf_generate_html($print, $html, $pdf_filename); |
|
113 |
} |
|
114 |
|
|
115 |
function print_pdf_generate_html($print, $html, $filename = NULL) { |
|
116 |
$print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT); |
|
117 |
|
|
118 |
if (basename($print_pdf_pdf_tool) == 'dompdf_config.inc.php') { |
|
119 |
return _print_pdf_dompdf($print, $html, $filename); |
|
120 |
} |
|
121 |
elseif (basename($print_pdf_pdf_tool) == 'tcpdf.php') { |
|
122 |
return _print_pdf_tcpdf($print, $html, $filename); |
|
123 |
} |
|
124 |
elseif (drupal_substr(basename($print_pdf_pdf_tool, '.exe'), 0, 11) == 'wkhtmltopdf') { |
|
125 |
return _print_pdf_wkhtmltopdf($print, $html, $filename); |
|
126 |
} |
|
127 |
elseif ($filename) { |
|
128 |
return drupal_not_found(); |
|
129 |
} |
|
130 |
return NULL; |
|
131 |
} |
|
132 |
|
|
133 | 88 |
/** |
134 |
* Convert image paths to the file:// protocol
|
|
89 |
* Gennerate a PDF for a given Drupal path.
|
|
135 | 90 |
* |
136 |
* In some Drupal setups, the use of the 'private' filesystem or Apache's |
|
137 |
* configuration prevent access to the images of the page. This function |
|
138 |
* tries to circumnvent those problems by accessing files in the local |
|
139 |
* filesystem. |
|
91 |
* @param string $path |
|
92 |
* path of the page to convert to PDF. |
|
93 |
* @param array $query |
|
94 |
* (Optional) array of key/value pairs as used in the url() function for the |
|
95 |
* query. |
|
96 |
* @param int $cid |
|
97 |
* (Optional) comment ID of the comment to render. |
|
98 |
* @param string $pdf_filename |
|
99 |
* (Optional) filename of the generated PDF. |
|
100 |
* @param string $view_mode |
|
101 |
* (Optional) view mode to be used when rendering the content. |
|
140 | 102 |
* |
141 |
* @param $html |
|
142 |
* contents of the post-processed template already with the node data |
|
143 |
* @see print_pdf_controller() |
|
144 |
*/ |
|
145 |
function _print_pdf_file_access_images($html) { |
|
146 |
global $base_url, $language; |
|
147 |
$print_pdf_images_via_file = variable_get('print_pdf_images_via_file', PRINT_PDF_IMAGES_VIA_FILE_DEFAULT); |
|
148 |
|
|
149 |
$lang = (function_exists('language_negotiation_get_any') && language_negotiation_get_any('locale-url')) ? $language->language : ''; |
|
150 |
|
|
151 |
// Always convert private to local paths |
|
152 |
$pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?)${base_url}/(?:(?:index.php)?\?q=)?(?:${lang}/)?system/files/([^>]*?>)!is"; |
|
153 |
$replacement = '$1file://' . realpath(variable_get('file_private_path', '')) . '/$2'; |
|
154 |
$html = preg_replace($pattern, $replacement, $html); |
|
155 |
if ($print_pdf_images_via_file) { |
|
156 |
$pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?)${base_url}/(?:(?:index.php)?\?q=)?(?:${lang}/)?([^>]*?>)!is"; |
|
157 |
$replacement = '$1file://' . dirname($_SERVER['SCRIPT_FILENAME']) . '/$2'; |
|
158 |
$html = preg_replace($pattern, $replacement, $html); |
|
159 |
} |
|
160 |
|
|
161 |
return $html; |
|
162 |
} |
|
163 |
|
|
164 |
/** |
|
165 |
* Generate the PDF file using the dompdf library |
|
166 |
* |
|
167 |
* @param $print |
|
168 |
* array containing the configured data |
|
169 |
* @param $html |
|
170 |
* contents of the post-processed template already with the node data |
|
171 |
* @param $filename |
|
172 |
* name of the PDF file to be generated |
|
173 |
* @see print_pdf_controller() |
|
174 |
*/ |
|
175 |
function _print_pdf_dompdf($print, $html, $filename = NULL) { |
|
176 |
$print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT); |
|
177 |
$print_pdf_paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT); |
|
178 |
$print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT); |
|
179 |
$print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT); |
|
180 |
|
|
181 |
if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) { |
|
182 |
if (!defined('DOMPDF_ENABLE_PHP')) define("DOMPDF_ENABLE_PHP", FALSE); |
|
183 |
if (!defined('DOMPDF_ENABLE_REMOTE')) define("DOMPDF_ENABLE_REMOTE", TRUE); |
|
184 |
if (!defined('DOMPDF_TEMP_DIR')) define("DOMPDF_TEMP_DIR", file_directory_temp()); |
|
185 |
if (!defined('DOMPDF_UNICODE_ENABLED')) define("DOMPDF_UNICODE_ENABLED", variable_get('print_pdf_dompdf_unicode', PRINT_PDF_DOMPDF_UNICODE_DEFAULT)); |
|
186 |
if (!defined('DOMPDF_FONT_CACHE')) define("DOMPDF_FONT_CACHE", drupal_realpath('public://' . PRINT_PDF_DOMPDF_CACHE_DIR_DEFAULT . '/fonts/')); |
|
187 |
} |
|
188 |
|
|
189 |
require_once(DRUPAL_ROOT . '/' . $print_pdf_pdf_tool); |
|
190 |
spl_autoload_register('DOMPDF_autoload'); |
|
191 |
|
|
192 |
// Try to use local file access for image files |
|
193 |
$html = _print_pdf_file_access_images($html); |
|
194 |
|
|
195 |
// Spaces in img URLs must be replaced with %20 |
|
196 |
$pattern = '!<(img\s[^>]*?)>!is'; |
|
197 |
$html = preg_replace_callback($pattern, '_print_replace_spaces', $html); |
|
198 |
|
|
199 |
// dompdf seems to have problems with something in system.css so let's not use it |
|
200 |
$html = preg_replace('!<link.*?modules/system/system.css.*?/>!', '', $html); |
|
201 |
|
|
202 |
$url_array = parse_url($print['url']); |
|
203 |
|
|
204 |
$protocol = $url_array['scheme'] . '://'; |
|
205 |
$host = $url_array['host']; |
|
206 |
$path = dirname($url_array['path']) . '/'; |
|
207 |
|
|
208 |
$dompdf = new DOMPDF(); |
|
209 |
$dompdf->set_base_path($path); |
|
210 |
$dompdf->set_host($host); |
|
211 |
$dompdf->set_paper(drupal_strtolower($print_pdf_paper_size), $print_pdf_page_orientation); |
|
212 |
$dompdf->set_protocol($protocol); |
|
213 |
|
|
214 |
// dompdf can't handle footers cleanly, so disable the following |
|
215 |
// $html = theme('print_pdf_dompdf_footer', array('html' => $html)); |
|
216 |
|
|
217 |
// If dompdf Unicode support is disabled, try to convert to ISO-8859-1 and then to HTML entities |
|
218 |
if (!variable_get('print_pdf_dompdf_unicode', PRINT_PDF_DOMPDF_UNICODE_DEFAULT)) { |
|
219 |
// Convert the euro sign to an HTML entity |
|
220 |
$html = str_replace('€', '€', $html); |
|
221 |
|
|
222 |
// Convert from UTF-8 to ISO 8859-1 and then to HTML entities |
|
223 |
if (function_exists('utf8_decode')) { |
|
224 |
$html = utf8_decode($html); |
|
225 |
} |
|
226 |
// iconv fails silently when it encounters something that it doesn't know, so don't use it |
|
227 |
// else if (function_exists('iconv')) { |
|
228 |
// $html = iconv('UTF-8', 'ISO-8859-1', $html); |
|
229 |
// } |
|
230 |
elseif (function_exists('mb_convert_encoding')) { |
|
231 |
$html = mb_convert_encoding($html, 'ISO-8859-1', 'UTF-8'); |
|
232 |
} |
|
233 |
elseif (function_exists('recode_string')) { |
|
234 |
$html = recode_string('UTF-8..ISO_8859-1', $html); |
|
235 |
} |
|
236 |
$html = htmlspecialchars_decode(htmlentities($html, ENT_NOQUOTES, 'ISO-8859-1'), ENT_NOQUOTES); |
|
237 |
} |
|
238 |
else { |
|
239 |
// Otherwise, ensure the content is properly formatted Unicode. |
|
240 |
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'); |
|
241 |
} |
|
242 |
|
|
243 |
// Must get rid of tbody (dompdf goes into recursion) |
|
244 |
$html = preg_replace('!<tbody[^>]*?>|</tbody>!i', '', $html); |
|
245 |
|
|
246 |
$dompdf->load_html($html); |
|
247 |
|
|
248 |
$dompdf->render(); |
|
249 |
if ($filename) { |
|
250 |
$dompdf->stream($filename, array('Attachment' => ($print_pdf_content_disposition == 2))); |
|
251 |
return TRUE; |
|
252 |
} |
|
253 |
else { |
|
254 |
return $dompdf->output(); |
|
255 |
} |
|
256 |
} |
|
257 |
|
|
258 |
/** |
|
259 |
* Generate the PDF file using the TCPDF library |
|
260 |
* |
|
261 |
* @param $print |
|
262 |
* array containing the configured data |
|
263 |
* @param $html |
|
264 |
* contents of the post-processed template already with the node data |
|
265 |
* @param $filename |
|
266 |
* name of the PDF file to be generated |
|
267 |
* @see print_pdf_controller() |
|
268 |
*/ |
|
269 |
function _print_pdf_tcpdf($print, $html, $filename = NULL) { |
|
270 |
global $base_url, $language; |
|
271 |
|
|
272 |
$print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT); |
|
273 |
$print_pdf_paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT); |
|
274 |
$print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT); |
|
275 |
$print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT); |
|
276 |
|
|
277 |
$pdf_tool_path = realpath(dirname($print_pdf_pdf_tool)); |
|
278 |
|
|
279 |
if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) { |
|
280 |
if (!defined('K_TCPDF_EXTERNAL_CONFIG')) define('K_TCPDF_EXTERNAL_CONFIG', TRUE); |
|
281 |
if (!defined('K_PATH_MAIN')) define('K_PATH_MAIN', dirname($_SERVER['SCRIPT_FILENAME'])); |
|
282 |
if (!defined('K_PATH_URL')) define('K_PATH_URL', $base_url); |
|
283 |
if (!defined('K_PATH_FONTS')) define('K_PATH_FONTS', $pdf_tool_path . '/fonts/'); |
|
284 |
if (!defined('K_PATH_CACHE')) define('K_PATH_CACHE', drupal_realpath('public://' . PRINT_PDF_TCPDF_CACHE_DIR_DEFAULT . '/cache') . '/'); |
|
285 |
if (!defined('K_PATH_IMAGES')) define('K_PATH_IMAGES', ''); |
|
286 |
if (!defined('K_BLANK_IMAGE')) define('K_BLANK_IMAGE', $pdf_tool_path . '/images/_blank.png'); |
|
287 |
if (!defined('K_CELL_HEIGHT_RATIO')) define('K_CELL_HEIGHT_RATIO', 1.25); |
|
288 |
if (!defined('K_SMALL_RATIO')) define('K_SMALL_RATIO', 2/3); |
|
289 |
} |
|
290 |
|
|
291 |
// Try to use local file access for image files |
|
292 |
$html = _print_pdf_file_access_images($html); |
|
293 |
|
|
294 |
// Decode HTML entities in image filenames |
|
295 |
$pattern = "!<img\s[^>]*?src\s*?=\s*?['\"]?{$base_url}[^>]*?>!is"; |
|
296 |
$html = preg_replace_callback($pattern, create_function('$matches', 'return html_entity_decode($matches[0], ENT_QUOTES);'), $html); |
|
297 |
// Remove queries from the image URL |
|
298 |
$pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?{$base_url}[^>]*?)(?:%3F|\?)[^\s'\"]+([^>]*?>)!is"; |
|
299 |
$html = preg_replace($pattern, '$1$2', $html); |
|
300 |
|
|
301 |
require_once(DRUPAL_ROOT . '/' . $print_pdf_pdf_tool); |
|
302 |
module_load_include('inc', 'print_pdf', 'print_pdf.class'); |
|
303 |
|
|
304 |
$font = Array( |
|
305 |
check_plain(variable_get('print_pdf_font_family', PRINT_PDF_FONT_FAMILY_DEFAULT)), |
|
306 |
'', |
|
307 |
check_plain(variable_get('print_pdf_font_size', PRINT_PDF_FONT_SIZE_DEFAULT)), |
|
308 |
); |
|
309 |
$orientation = drupal_strtoupper($print_pdf_page_orientation[0]); |
|
310 |
|
|
311 |
// create new PDF document |
|
312 |
$pdf = new PrintTCPDF($orientation , 'mm', $print_pdf_paper_size, TRUE); |
|
313 |
|
|
314 |
// set document information |
|
315 |
if (property_exists($print['node'], 'name')) { |
|
316 |
$pdf->SetAuthor(strip_tags($print['node']->name)); |
|
317 |
} |
|
318 |
$pdf->SetCreator(variable_get('site_name', 'Drupal')); |
|
319 |
$pdf->SetTitle(html_entity_decode($print['title'], ENT_QUOTES, 'UTF-8')); |
|
320 |
$pdf->setPDFVersion('1.6'); |
|
321 |
$pdf->setFontSubsetting(variable_get('print_pdf_font_subsetting', PRINT_PDF_FONT_SUBSETTING_DEFAULT)); |
|
322 |
$pdf->setTcpdfLink(false); |
|
323 |
|
|
324 |
if ($language->direction == LANGUAGE_RTL) { |
|
325 |
$pdf->setRTL(TRUE); |
|
326 |
} |
|
327 |
|
|
328 |
$pdf = theme('print_pdf_tcpdf_header', array('pdf' => $pdf, 'html' => $html, 'font' => $font)); |
|
329 |
$pdf = theme('print_pdf_tcpdf_footer', array('pdf' => $pdf, 'html' => $html, 'font' => $font)); |
|
330 |
$pdf = theme('print_pdf_tcpdf_page', array('pdf' => $pdf)); |
|
331 |
|
|
332 |
// add a page |
|
333 |
$pdf->AddPage(); |
|
334 |
|
|
335 |
$pdf = theme('print_pdf_tcpdf_content', array('pdf' => $pdf, 'html' => $html, 'font' => $font)); |
|
336 |
|
|
337 |
// reset pointer to the last page |
|
338 |
$pdf->lastPage(); |
|
339 |
|
|
340 |
// try to recover from any warning/error |
|
341 |
ob_clean(); |
|
342 |
|
|
343 |
if ($filename) { |
|
344 |
// Close and output PDF document |
|
345 |
$output_dest = ($print_pdf_content_disposition == 2) ? 'D' : 'I'; |
|
346 |
$pdf->Output($filename, $output_dest); |
|
347 |
return TRUE; |
|
348 |
} |
|
349 |
else { |
|
350 |
return $pdf = $pdf->Output('', 'S'); |
|
351 |
} |
|
352 |
} |
|
353 |
|
|
354 |
/** |
|
355 |
* Generate the PDF file using wkhtmltopdf |
|
103 |
* @return string|null |
|
104 |
* generated PDF page, or NULL in case of error |
|
356 | 105 |
* |
357 |
* @param $print |
|
358 |
* array containing the configured data |
|
359 |
* @param $html |
|
360 |
* contents of the post-processed template already with the node data |
|
361 |
* @param $filename |
|
362 |
* name of the PDF file to be generated |
|
363 | 106 |
* @see print_pdf_controller() |
364 | 107 |
*/ |
365 |
function _print_pdf_wkhtmltopdf($print, $html, $filename = NULL) { |
|
366 |
$print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT); |
|
367 |
$print_pdf_paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT); |
|
368 |
$print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT); |
|
369 |
$print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT); |
|
370 |
$print_pdf_wkhtmltopdf_options = variable_get('print_pdf_wkhtmltopdf_options', PRINT_PDF_WKHTMLTOPDF_OPTIONS); |
|
371 |
|
|
372 |
$dpi = 96; |
|
373 |
|
|
374 |
if (!empty($print_pdf_wkhtmltopdf_options)) { |
|
375 |
$print_pdf_wkhtmltopdf_options = token_replace($print_pdf_wkhtmltopdf_options, array('node' => $print['node']), array('clear' => TRUE)); |
|
376 |
} |
|
377 |
|
|
378 |
$version = _print_pdf_wkhtmltopdf_version(); |
|
379 |
|
|
380 |
// 0.10.0 beta2 identifies itself as 0.9.9 |
|
381 |
if (version_compare($version, '0.9.9', '>=')) { |
|
382 |
$print_pdf_wkhtmltopdf_options = '--disable-local-file-access ' . $print_pdf_wkhtmltopdf_options; |
|
383 |
} |
|
384 |
elseif (version_compare($version, '0.9.6', '>=')) { |
|
385 |
$print_pdf_wkhtmltopdf_options = '--disallow-local-file-access ' . $print_pdf_wkhtmltopdf_options; |
|
386 |
} |
|
387 |
else { |
|
388 |
drupal_goto($print['url']); |
|
389 |
exit; |
|
390 |
} |
|
391 |
|
|
392 |
$descriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'a')); |
|
393 |
$cmd = '"' . realpath($print_pdf_pdf_tool) . "\" --page-size $print_pdf_paper_size --orientation $print_pdf_page_orientation --dpi $dpi $print_pdf_wkhtmltopdf_options - -"; |
|
394 |
|
|
395 |
$process = proc_open($cmd, $descriptor, $pipes, NULL, NULL); |
|
396 |
|
|
397 |
if (is_resource($process)) { |
|
398 |
fwrite($pipes[0], $html); |
|
399 |
fclose($pipes[0]); |
|
400 |
|
|
401 |
$pdf = stream_get_contents($pipes[1]); |
|
402 |
fclose($pipes[1]); |
|
108 |
function print_pdf_generate_path($path, $query = NULL, $cid = NULL, $pdf_filename = NULL, $view_mode = PRINT_VIEW_MODE) { |
|
109 |
global $base_url; |
|
403 | 110 |
|
404 |
stream_set_blocking($pipes[2], 0); |
|
405 |
$error = stream_get_contents($pipes[2]); |
|
406 |
fclose($pipes[2]); |
|
111 |
$link = print_pdf_print_link(); |
|
112 |
$node = print_controller($path, $link['format'], $cid, $view_mode); |
|
113 |
if ($node) { |
|
114 |
// Call the tool's hook_pdf_tool_info(), to see if CSS must be expanded. |
|
115 |
$pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT)); |
|
116 |
$cache_enabled = variable_get('print_pdf_cache_enabled', PRINT_PDF_CACHE_ENABLED_DEFAULT); |
|
407 | 117 |
|
408 |
$retval = proc_close($process); |
|
409 |
if (!empty($error) || ($retval != 0)) { |
|
410 |
if (empty($error)) { |
|
411 |
$error = 'No stderr output available.'; |
|
412 |
} |
|
413 |
watchdog('print_pdf', 'wkhtmltopdf [%cmd] (returned %ret): %error', array('%cmd' => $cmd, '%ret' => $retval, '%error' => $error)); |
|
118 |
$function = $pdf_tool[0] . '_pdf_tool_info'; |
|
119 |
if (function_exists($function)) { |
|
120 |
$info = $function(); |
|
414 | 121 |
} |
415 |
} |
|
416 |
|
|
417 |
if (!empty($pdf)) { |
|
418 |
if ($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 |
$attachment = ($print_pdf_content_disposition == 2) ? "attachment" : "inline"; |
|
426 |
|
|
427 |
header("Content-Disposition: $attachment; filename=\"$filename\""); |
|
428 |
|
|
429 |
echo $pdf; |
|
430 |
flush(); |
|
431 |
return TRUE; |
|
122 |
$expand = isset($info['expand_css']) ? $info['expand_css'] : FALSE; |
|
123 |
|
|
124 |
$html = theme('print', array( |
|
125 |
'node' => $node, |
|
126 |
'query' => $query, |
|
127 |
'expand_css' => $expand, |
|
128 |
'format' => $link['format'], |
|
129 |
)); |
|
130 |
|
|
131 |
// Img elements must be set to absolute. |
|
132 |
$pattern = '!<(img\s[^>]*?)>!is'; |
|
133 |
$html = preg_replace_callback($pattern, '_print_rewrite_urls', $html); |
|
134 |
|
|
135 |
// Convert the a href elements, to make sure no relative links remain. |
|
136 |
$pattern = '!<(a\s[^>]*?)>!is'; |
|
137 |
$html = preg_replace_callback($pattern, '_print_rewrite_urls', $html); |
|
138 |
// And make anchor links relative again, to permit in-PDF navigation. |
|
139 |
$html = preg_replace("!${base_url}/" . $link['path'] . '/.*?#!', '#', $html); |
|
140 |
// Remove all scripts due to security concerns. |
|
141 |
$html = preg_replace('!<script(.*?)>(.*?)</script>!is', '', $html); |
|
142 |
|
|
143 |
$meta = array( |
|
144 |
'node' => $node, |
|
145 |
'url' => url(drupal_get_path_alias(empty($node->nid) ? $node->path : "node/$node->nid"), array('absolute' => TRUE)), |
|
146 |
); |
|
147 |
if (isset($node->name)) { |
|
148 |
$meta['name'] = $node->name; |
|
432 | 149 |
} |
433 |
else {
|
|
434 |
return $pdf;
|
|
150 |
if (isset($node->title)) {
|
|
151 |
$meta['title'] = $node->title;
|
|
435 | 152 |
} |
436 |
} |
|
437 |
else { |
|
438 |
drupal_set_message(t('Unable to generate PDF file.'), 'error'); |
|
439 |
drupal_goto($print['url']); |
|
440 |
return NULL; |
|
441 |
} |
|
442 |
} |
|
443 |
|
|
444 |
/** |
|
445 |
* Format the dompdf footer contents |
|
446 |
* |
|
447 |
* @param $html |
|
448 |
* contents of the body of the HTML from the original node |
|
449 |
* @see theme_print_pdf_tcpdf_footer() |
|
450 |
*/ |
|
451 |
function theme_print_pdf_dompdf_footer($vars) { |
|
452 |
preg_match('!<div class="print-footer">(.*?)</div>!si', $vars['html'], $tpl_footer); |
|
453 |
|
|
454 |
if (isset($tpl_footer[1])) { |
|
455 |
$html = str_replace($tpl_footer[0], '', $vars['html']); |
|
456 | 153 |
|
457 |
$text = '<script type="text/php"> |
|
458 |
if (isset($pdf)) { |
|
459 |
$font = Font_Metrics::get_font("verdana");; |
|
460 |
$size = 10; |
|
461 |
$color = array(0,0,0); |
|
462 |
$text_height = Font_Metrics::get_font_height($font, $size); |
|
463 |
|
|
464 |
$w = $pdf->get_width(); |
|
465 |
$h = $pdf->get_height(); |
|
466 |
|
|
467 |
$footer = $pdf->open_object(); |
|
468 |
|
|
469 |
// Draw a line along the bottom |
|
470 |
$y = $h - 25; |
|
471 |
$pdf->line(15, $y, $w - 15, $y, $color, 1); |
|
472 |
|
|
473 |
$y += $text_height / 2; |
|
474 |
$pdf->page_text(15, $y, \'' . addslashes(strip_tags($tpl_footer[1])) . '\', $font, $size, $color); |
|
475 |
|
|
476 |
$pdf->close_object(); |
|
477 |
$pdf->add_object($footer, "all"); |
|
478 |
|
|
479 |
// Center the text |
|
480 |
$width = Font_Metrics::get_text_width("Page 1 of 2", $font, $size); |
|
481 |
$pagenumtxt = t("Page !n of !total", array("!n" => "{PAGE_NUM}", "!total" => "{PAGE_COUNT}")); |
|
482 |
$pdf->page_text($w - 15 - $width, $y, $pagenumtxt, $font, $size, $color); |
|
154 |
$paper_size = isset($node->print_pdf_size) ? $node->print_pdf_size : NULL; |
|
155 |
$page_orientation = isset($node->print_pdf_orientation) ? $node->print_pdf_orientation : NULL; |
|
156 |
|
|
157 |
$pdf = ''; |
|
158 |
$cachemiss = FALSE; |
|
159 |
$cachefile = ''; |
|
160 |
if ($cache_enabled && isset($node->nid)) { |
|
161 |
// See if the file exists in the cache. |
|
162 |
$cachefile = drupal_realpath(print_pdf_cache_dir()) . '/' . $node->nid . '.pdf'; |
|
163 |
if (is_readable($cachefile)) { |
|
164 |
// Get the PDF content from the cached file. |
|
165 |
$pdf = file_get_contents($cachefile); |
|
166 |
if ($pdf === FALSE) { |
|
167 |
watchdog('print_pdf', 'Failed to read from cached file %file', array('%file' => $cachefile), WATCHDOG_ERROR); |
|
168 |
} |
|
169 |
} |
|
170 |
else { |
|
171 |
$cachemiss = TRUE; |
|
483 | 172 |
} |
484 |
</script>'; |
|
485 |
|
|
486 |
return str_replace("<body>", "<body>" . $text, $html); |
|
487 |
} else { |
|
488 |
return $vars['html']; |
|
489 |
} |
|
490 |
} |
|
491 |
|
|
492 |
/** |
|
493 |
* Format the TCPDF header |
|
494 |
* |
|
495 |
* @param $pdf |
|
496 |
* current TCPDF object |
|
497 |
* @param $html |
|
498 |
* contents of the body of the HTML from the original node |
|
499 |
* @param $font |
|
500 |
* array with the font definition (font name, styles and size) |
|
501 |
* @see theme_print_pdf_tcpdf_header() |
|
502 |
*/ |
|
503 |
function theme_print_pdf_tcpdf_header($vars) { |
|
504 |
$pdf = $vars['pdf']; |
|
505 |
preg_match('!<div class="print-logo">(.*?)</div>!si', $vars['html'], $tpl_logo); |
|
506 |
preg_match('!<title>(.*?)</title>!si', $vars['html'], $tpl_title); |
|
507 |
preg_match('!<div class="print-site_name">(.*?)</div>!si', $vars['html'], $tpl_site_name); |
|
508 |
|
|
509 |
$ratio = 0; |
|
510 |
$logo = ''; |
|
511 |
if (isset($tpl_logo[1]) && preg_match('!src\s*=\s*(?:"(.*?)"|\'(.*?)\'|([^\s]*))!i', $tpl_logo[1], $logo_url)) { |
|
512 |
$logo = $logo_url[1]; |
|
513 |
if (!empty($logo)) { |
|
514 |
$size = getimagesize($logo); |
|
515 |
$ratio = $size ? ($size[0] / $size[1]) : 0; |
|
516 | 173 |
} |
517 |
} |
|
518 |
|
|
519 |
// set header font |
|
520 |
$pdf->setHeaderFont($vars['font']); |
|
521 |
// set header margin |
|
522 |
$pdf->setHeaderMargin(5); |
|
523 |
// set header data |
|
524 |
$pdf->setHeaderData($logo, 10 * $ratio, html_entity_decode($tpl_title[1], ENT_QUOTES, 'UTF-8'), html_entity_decode(strip_tags($tpl_site_name[1]), ENT_QUOTES, 'UTF-8')); |
|
525 |
|
|
526 |
return $pdf; |
|
527 |
} |
|
528 |
|
|
529 |
/** |
|
530 |
* Format the TCPDF page settings (margins, etc) |
|
531 |
* |
|
532 |
* @param $pdf |
|
533 |
* current TCPDF object |
|
534 |
* @see theme_print_pdf_tcpdf_page() |
|
535 |
*/ |
|
536 |
function theme_print_pdf_tcpdf_page($vars) { |
|
537 |
$pdf = $vars['pdf']; |
|
538 |
// set margins |
|
539 |
$pdf->SetMargins(15, 20, 15); |
|
540 |
// set auto page breaks |
|
541 |
$pdf->SetAutoPageBreak(TRUE, 15); |
|
542 |
// set image scale factor |
|
543 |
$pdf->setImageScale(1); |
|
544 |
// set image compression quality |
|
545 |
$pdf->setJPEGQuality(100); |
|
546 |
|
|
547 |
return $pdf; |
|
548 |
} |
|
549 |
|
|
550 |
/** |
|
551 |
* Format the TCPDF page content |
|
552 |
* |
|
553 |
* @param $pdf |
|
554 |
* current TCPDF object |
|
555 |
* @param $html |
|
556 |
* contents of the body of the HTML from the original node |
|
557 |
* @param $font |
|
558 |
* array with the font definition (font name, styles and size) |
|
559 |
* @see theme_print_pdf_tcpdf_content() |
|
560 |
*/ |
|
561 |
function theme_print_pdf_tcpdf_content($vars) { |
|
562 |
$pdf = $vars['pdf']; |
|
563 |
// set content font |
|
564 |
$pdf->setFont($vars['font'][0], $vars['font'][1], $vars['font'][2]); |
|
565 |
|
|
566 |
preg_match('!<body.*?>(.*)</body>!sim', $vars['html'], $matches); |
|
567 |
$pattern = '!(?:<div class="print-(?:logo|site_name|breadcrumb|footer)">.*?</div>|<hr class="print-hr" />)!si'; |
|
568 |
$matches[1] = preg_replace($pattern, '', $matches[1]); |
|
569 |
|
|
570 |
// Make CCK fields look better |
|
571 |
$matches[1] = preg_replace('!(<div class="field.*?>)\s*!sm', '$1', $matches[1]); |
|
572 |
$matches[1] = preg_replace('!(<div class="field.*?>.*?</div>)\s*!sm', '$1', $matches[1]); |
|
573 |
$matches[1] = preg_replace('!<div( class="field-label.*?>.*?)</div>!sm', '<strong$1</strong>', $matches[1]); |
|
574 | 174 |
|
575 |
// Since TCPDF's writeHTML is so bad with <p>, do everything possible to make it look nice |
|
576 |
$matches[1] = preg_replace('!<(?:p(|\s+.*?)/?|/p)>!i', '<br$1 />', $matches[1]); |
|
577 |
$matches[1] = str_replace(array('<div', 'div>'), array('<span', 'span><br />'), $matches[1]); |
|
578 |
do { |
|
579 |
$prev = $matches[1]; |
|
580 |
$matches[1] = preg_replace('!(</span>)<br />(\s*?</span><br />)!s', '$1$2', $matches[1]); |
|
581 |
} while ($prev != $matches[1]); |
|
582 |
|
|
583 |
@$pdf->writeHTML($matches[1]); |
|
584 |
|
|
585 |
return $pdf; |
|
586 |
} |
|
587 |
|
|
588 |
/** |
|
589 |
* Format the TCPDF footer contents |
|
590 |
* |
|
591 |
* @param $pdf |
|
592 |
* current TCPDF object |
|
593 |
* @param $html |
|
594 |
* contents of the body of the HTML from the original node |
|
595 |
* @param $font |
|
596 |
* array with the font definition (font name, styles and size) |
|
597 |
* @see theme_print_pdf_tcpdf_footer() |
|
598 |
*/ |
|
599 |
function theme_print_pdf_tcpdf_footer($vars) { |
|
600 |
$pdf = $vars['pdf']; |
|
601 |
preg_match('!<div class="print-footer">(.*?)</div>!si', $vars['html'], $tpl_footer); |
|
602 |
if (isset($tpl_footer[1])) { |
|
603 |
$footer = trim(preg_replace('!</?div[^>]*?>!i', '', $tpl_footer[1])); |
|
604 |
|
|
605 |
// set footer font |
|
606 |
$vars['font'][2] *= 0.8; |
|
607 |
$pdf->setFooterFont($vars['font']); |
|
608 |
// set footer margin |
|
609 |
$pdf->SetFooterMargin(10); |
|
610 |
// set footer data |
|
611 |
$pdf->setFooterContent($footer); |
|
612 |
} |
|
613 |
|
|
614 |
return $pdf; |
|
615 |
} |
|
175 |
// If cache is off or file is not cached, generate one from scratch. |
|
176 |
if (empty($pdf)) { |
|
177 |
$pdf = print_pdf_generate_html($html, $meta, NULL, $paper_size, $page_orientation); |
|
178 |
} |
|
616 | 179 |
|
617 |
/** |
|
618 |
* Format the TCPDF footer layout |
|
619 |
* |
|
620 |
* @param $pdf |
|
621 |
* current TCPDF object |
|
622 |
* @see theme_print_pdf_tcpdf_footer2() |
|
623 |
*/ |
|
624 |
function theme_print_pdf_tcpdf_footer2($vars) { |
|
625 |
$pdf = $vars['pdf']; |
|
626 |
// Position at 1.5 cm from bottom |
|
627 |
$pdf->writeHTMLCell(0, 15, 15, $pdf->getPageHeight()-15, $pdf->footer); |
|
180 |
if (!empty($pdf)) { |
|
181 |
// A PDF was created, save it to cache if configured. |
|
182 |
if ($cachemiss) { |
|
183 |
if (file_unmanaged_save_data($pdf, $cachefile, FILE_EXISTS_REPLACE) == FALSE) { |
|
184 |
watchdog('print_pdf', 'Failed to write to "%f".', array('%f' => $cachefile), WATCHDOG_ERROR); |
|
185 |
} |
|
186 |
} |
|
628 | 187 |
|
629 |
$ormargins = $pdf->getOriginalMargins(); |
|
630 |
$pagenumtxt = t('Page !n of !total', array('!n' => $pdf->PageNo(), '!total' => $pdf->getAliasNbPages())); |
|
631 |
// Print page number |
|
632 |
if ($pdf->getRTL()) { |
|
633 |
$pdf->SetX($ormargins['right']); |
|
634 |
$pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'L'); |
|
635 |
} |
|
636 |
else { |
|
637 |
$pdf->SetX($ormargins['left']); |
|
638 |
$pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'R'); |
|
188 |
return $pdf_filename ? print_pdf_dispose_content($pdf, $pdf_filename) : $pdf; |
|
189 |
} |
|
639 | 190 |
} |
640 |
|
|
641 |
return $pdf; |
|
191 |
return NULL; |
|
642 | 192 |
} |
Also available in: Unified diff
Weekly update of contrib modules