]*?)>!is'; $print['content'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['content']); $print['logo'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['logo']); $print['footer_message'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['footer_message']); // And converted from private to public paths $file_downloads = variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC); if ($file_downloads == FILE_DOWNLOADS_PRIVATE) { switch (variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE)) { case LANGUAGE_NEGOTIATION_PATH_DEFAULT: case LANGUAGE_NEGOTIATION_PATH: $lang = $language->language; break; default: $lang = ''; break; } $pattern = "!(]*?src\s*?=\s*?['\"]?)${base_url}/(?:(?:index.php)?\?q=)?(?:${lang}/)?system/files(/[^>]*?>)!is"; $replacement = '$1file://' . realpath(file_directory_path()) . '$2'; $print['content'] = preg_replace($pattern, $replacement, $print['content']); $print['logo'] = preg_replace($pattern, $replacement, $print['logo']); $print['footer_message'] = preg_replace($pattern, $replacement, $print['footer_message']); } $node = $print['node']; ob_start(); include_once(DRUPAL_ROOT . '/' . _print_get_template(PRINT_PDF_FORMAT, $print['type'])); $html = ob_get_contents(); ob_end_clean(); // Convert the a href elements $pattern = '!<(a\s[^>]*?)>!is'; $html = preg_replace_callback($pattern, '_print_rewrite_urls', $html); $pdf_filename = variable_get('print_pdf_filename', PRINT_PDF_FILENAME_DEFAULT); if (function_exists('token_replace') && !empty($pdf_filename)) { $pdf_filename = token_replace($pdf_filename, 'node', $node) . '.pdf'; } else { $pdf_filename = str_replace('/', '_', $path) . '.pdf'; } if (basename($print_pdf_pdf_tool) == 'dompdf_config.inc.php') { _print_pdf_dompdf($print, $html, $pdf_filename); } elseif (basename($print_pdf_pdf_tool) == 'tcpdf.php') { _print_pdf_tcpdf($print, $html, $pdf_filename); } elseif (basename($print_pdf_pdf_tool) == 'wkhtmltopdf') { _print_pdf_wkhtmltopdf($print, $html, $pdf_filename); } else { return drupal_not_found(); } $nodepath = (isset($node->path)) ? drupal_get_normal_path($node->path) : 'node/' . $path; db_merge('print_pdf_page_counter') ->key(array('path' => $nodepath)) ->fields(array( 'totalcount' => 1, 'timestamp' => REQUEST_TIME, )) ->expression('totalcount', 'totalcount + :inc', array(':inc' => 1)) ->execute(); } /** * Generate the PDF file using the dompdf library * * @param $print * array containing the configured data * @param $html * contents of the post-processed template already with the node data * @param $filename * name of the PDF file to be generated * @see print_pdf_controller() */ function _print_pdf_dompdf($print, $html, $filename) { $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT); $print_pdf_paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT); $print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT); $print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT); require_once(DRUPAL_ROOT . '/' . $print_pdf_pdf_tool); // dompdf seems to have problems with something in system.css so let's not use it $html = preg_replace('!!', '', $html); $url_array = parse_url($print['url']); $protocol = $url_array['scheme'] . '://'; $host = $url_array['host']; $path = dirname($url_array['path']) . '/'; $dompdf = new DOMPDF(); $dompdf->set_base_path($path); $dompdf->set_host($host); $dompdf->set_paper(drupal_strtolower($print_pdf_paper_size), $print_pdf_page_orientation); $dompdf->set_protocol($protocol); // dompdf can't handle footers cleanly, so disable the following // $html = theme('print_pdf_dompdf_footer', $html); // Convert from UTF-8 to ISO 8859-1 and then to HTML entities if (function_exists('utf8_decode')) { $html = utf8_decode($html); } // iconv fails silently when it encounters something that it doesn't know, so don't use it // else if (function_exists('iconv')) { // $html = iconv('UTF-8', 'ISO-8859-1', $html); // } elseif (function_exists('mb_convert_encoding')) { $html = mb_convert_encoding($html, 'ISO-8859-1', 'UTF-8'); } elseif (function_exists('recode_string')) { $html = recode_string('UTF-8..ISO_8859-1', $html); } $html = htmlspecialchars_decode(htmlentities($html, ENT_NOQUOTES, 'ISO-8859-1'), ENT_NOQUOTES); //must get rid of tbody (dompdf goes into recursion) $html = preg_replace('!]*?>|!i', '', $html); $dompdf->load_html($html); $dompdf->render(); $dompdf->stream($filename, array('Attachment' => ($print_pdf_content_disposition == 2))); } /** * Generate the PDF file using the TCPDF library * * @param $print * array containing the configured data * @param $html * contents of the post-processed template already with the node data * @param $filename * name of the PDF file to be generated * @see print_pdf_controller() */ function _print_pdf_tcpdf($print, $html, $filename) { global $base_url, $language; $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT); $print_pdf_paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT); $print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT); $print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT); $pdf_tool_path = realpath(dirname($print_pdf_pdf_tool)); define('K_TCPDF_EXTERNAL_CONFIG', TRUE); define('K_PATH_MAIN', dirname($_SERVER['SCRIPT_FILENAME'])); define('K_PATH_URL', $base_url); define('K_PATH_FONTS', $pdf_tool_path . '/fonts/'); define('K_PATH_CACHE', $pdf_tool_path . '/cache/'); define('K_PATH_IMAGES', ''); define('K_BLANK_IMAGE', $pdf_tool_path . '/images/_blank.png'); define('K_CELL_HEIGHT_RATIO', 1.25); define('K_SMALL_RATIO', 2/3); // Decode HTML entities in image filenames $pattern = "!]*?>!is"; $html = preg_replace_callback($pattern, create_function('$matches', 'return html_entity_decode($matches[0], ENT_QUOTES);'), $html); // Remove imagefield/filefield numerical parameter $pattern = "!(]*?src\s*?=.*?)%3F\d+([^>]*?>)!is"; $html = preg_replace($pattern, '$1$2', $html); require_once(DRUPAL_ROOT . '/' . $print_pdf_pdf_tool); if (strpos(PDF_PRODUCER, 'PHP4') === FALSE) { require_once(DRUPAL_ROOT . '/' . drupal_get_path('module', 'print_pdf') . '/print_pdf.class.inc'); } else { drupal_set_message(t("The PHP4 version of TCPDF is not supported. Please upgrade it."), 'error', FALSE); drupal_goto($_GET['q']); } $font = Array( variable_get('print_pdf_font_family', PRINT_PDF_FONT_FAMILY_DEFAULT), '', variable_get('print_pdf_font_size', PRINT_PDF_FONT_SIZE_DEFAULT), ); $orientation = drupal_strtoupper($print_pdf_page_orientation[0]); // create new PDF document $pdf = new PrintTCPDF($orientation , 'mm', $print_pdf_paper_size, TRUE); // set document information $pdf->SetAuthor(strip_tags($print['submitted'])); $pdf->SetCreator(variable_get('site_name', 'Drupal')); $pdf->SetTitle(html_entity_decode($print['title'], ENT_QUOTES, UTF-8)); $keys = implode(' ', explode("\n", trim(strip_tags($print['taxonomy'])))); $pdf->SetKeywords($keys); $pdf->setPDFVersion('1.6'); if (defined('LANGUAGE_RTL') && $language->direction == LANGUAGE_RTL) { $pdf->setRTL(TRUE); } $pdf = theme('print_pdf_tcpdf_header', $pdf, $html, $font); $pdf = theme('print_pdf_tcpdf_footer', $pdf, $html, $font); $pdf = theme('print_pdf_tcpdf_page', $pdf); //initialize document $pdf->AliasNbPages(); // add a page $pdf->AddPage(); $pdf = theme('print_pdf_tcpdf_content', $pdf, $html, $font); // reset pointer to the last page $pdf->lastPage(); // try to recover from any warning/error ob_clean(); //Close and output PDF document $output_dest = ($print_pdf_content_disposition == 2) ? 'D' : 'I'; $pdf->Output($filename, $output_dest); } /** * Generate the PDF file using wkhtmltopdf * * @param $print * array containing the configured data * @param $html * contents of the post-processed template already with the node data * @param $filename * name of the PDF file to be generated * @see print_pdf_controller() */ function _print_pdf_wkhtmltopdf($print, $html, $filename) { $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT); $print_pdf_paper_size = drupal_strtolower(variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT)); $print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT); $print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT); $print_pdf_wkhtmltopdf_options = variable_get('print_pdf_wkhtmltopdf_options', PRINT_PDF_WKHTMLTOPDF_OPTIONS); $print_pdf_xvfb_options = variable_get('print_pdf_xvfb_options', PRINT_PDF_XVFB_OPTIONS); $xvfb_binary = key(file_scan_directory(drupal_get_path('module', 'print'), '!^Xvfb$!')); $dpi = 96; // If available, launch a temporary X server if (isset($xvfb_binary)) { $xdisplay = variable_get('print_pdf_wkhtmltopdf_xdisplay', 10); variable_set('print_pdf_wkhtmltopdf_xdisplay', ($xdisplay == 4990) ? 10 : $xdisplay + 10); $xdisplay += mt_rand(0, 9); $xcmd = realpath($xvfb_binary) . " :$xdisplay -screen 0 320x200x24 -dpi $dpi -terminate -nolisten tcp -tst $print_pdf_xvfb_options"; $xdescriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')); $xprocess = proc_open($xcmd, $xdescriptor, $xpipes, NULL, NULL); } $descriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')); $cmd = realpath($print_pdf_pdf_tool) . " --page-size $print_pdf_paper_size --orientation $print_pdf_page_orientation --dpi $dpi $print_pdf_wkhtmltopdf_options - -"; $process = proc_open($cmd, $descriptor, $pipes, NULL, isset($xvfb_binary) ? array('DISPLAY' => ':' . $xdisplay) : NULL); if (is_resource($process)) { fwrite($pipes[0], $html); fclose($pipes[0]); $pdf = stream_get_contents($pipes[1]); fclose($pipes[1]); stream_set_blocking($xpipes[2], 0); $error = stream_get_contents($pipes[2]); if (!empty($error)) { watchdog('print_pdf', 'wkhtmltopdf: ' . $error); } fclose($pipes[2]); $retval = proc_terminate($process); } if (isset($xvfb_binary)) { fclose($xpipes[0]); fclose($xpipes[1]); stream_set_blocking($xpipes[2], 0); $xerror = stream_get_contents($xpipes[2]); if (!empty($xerror)) { watchdog('print_pdf', 'wkhtmltopdf Xvfb: ' . $xerror); } fclose($xpipes[2]); proc_terminate($xprocess); } if (!empty($pdf)) { if (headers_sent()) { die("Unable to stream pdf: headers already sent"); } header("Cache-Control: private"); header("Content-Type: application/pdf"); $attachment = ($print_pdf_content_disposition == 2) ? "attachment" : "inline"; header("Content-Disposition: $attachment; filename=\"$filename\""); echo $pdf; flush(); } else { drupal_goto($print['url']); exit; } } /** * Format the dompdf footer contents * * @param $html * contents of the body of the HTML from the original node * @see theme_print_pdf_tcpdf_footer() */ function theme_print_pdf_dompdf_footer(&$html) { preg_match('!!si', $html, $tpl_footer); $html = str_replace($tpl_footer[0], '', $html); $text = ''; return str_replace("", "" . $text, $html); } /** * Format the TCPDF header * * @param $pdf * current TCPDF object * @param $html * contents of the body of the HTML from the original node * @param $font * array with the font definition (font name, styles and size) * @see theme_print_pdf_tcpdf_header() */ function theme_print_pdf_tcpdf_header(&$pdf, &$html, $font) { preg_match('!!si', $html, $tpl_logo); preg_match('!

(.*?)

!si', $html, $tpl_title); preg_match('!!si', $html, $tpl_site_name); $ratio = 0; $logo = ''; $logo_ret = preg_match('!src\s*=\s*(\'.*?\'|".*?"|[^\s]*)!i', $tpl_logo[1], $matches); if ($logo_ret) { $logo = trim($matches[1], '\'"'); $size = getimagesize($logo); $ratio = $size ? ($size[0] / $size[1]) : 0; } // set header font $pdf->setHeaderFont($font); // set header margin $pdf->SetHeaderMargin(5); // set header data $pdf->SetHeaderData($logo, 10 * $ratio, html_entity_decode($tpl_title[1], ENT_QUOTES, 'UTF-8'), strip_tags($tpl_site_name[1])); return $pdf; } /** * Format the TCPDF page settings (margins, etc) * * @param $pdf * current TCPDF object * @see theme_print_pdf_tcpdf_page() */ function theme_print_pdf_tcpdf_page(&$pdf) { // set margins $pdf->SetMargins(15, 20, 15); // set auto page breaks $pdf->SetAutoPageBreak(TRUE, 15); // set image scale factor $pdf->setImageScale(4); // set image compression quality $pdf->setJPEGQuality(100); return $pdf; } /** * Format the TCPDF page content * * @param $pdf * current TCPDF object * @param $html * contents of the body of the HTML from the original node * @param $font * array with the font definition (font name, styles and size) * @see theme_print_pdf_tcpdf_content() */ function theme_print_pdf_tcpdf_content(&$pdf, &$html, $font) { // set content font $pdf->setFont($font[0], $font[1], $font[2]); preg_match('!(.*)!sim', $html, $matches); $pattern = '!(?:|)!si'; $matches[1] = preg_replace($pattern, '', $matches[1]); // Make CCK fields look better $matches[1] = preg_replace('!(
.*?
)\s*!sm', '$1', $matches[1]); $matches[1] = preg_replace('!(.*?)!si', $html, $tpl_footer); $footer = trim(preg_replace('!]*?>!i', '', $tpl_footer[1])); // set footer font $font[2] *= 0.8; $pdf->setFooterFont($font); // set footer margin $pdf->SetFooterMargin(10); // set footer data $pdf->SetFooterData($footer); return $pdf; } /** * Format the TCPDF footer layout * * @param $pdf * current TCPDF object * @see theme_print_pdf_tcpdf_footer2() */ function theme_print_pdf_tcpdf_footer2(&$pdf) { //Position at 1.5 cm from bottom $pdf->writeHTMLCell(0, 15, 15, -10, $pdf->footer, 0, 0, 0, TRUE, ''); $ormargins = $pdf->getOriginalMargins(); $pagenumtxt = t('Page !n of !total', array('!n' => $pdf->PageNo(), '!total' => $pdf->getAliasNbPages())); //Print page number if ($pdf->getRTL()) { $pdf->SetX($ormargins['right']); $pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'L'); } else { $pdf->SetX($ormargins['left']); $pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'R'); } return $pdf; }