mode = 'none';
$this->error = false;
if (empty($printMode)) {
$printMode = $prefs['print_pdf_from_url'];
}
if ($printMode == self::WEBKIT) {
$path = $prefs['print_pdf_webkit_path'];
if (! empty($path) && is_executable($path)) {
$this->mode = 'webkit';
$this->location = $path;
} else {
if (! empty($path)) {
$this->error = tr('PDF webkit path "%0" not found.', $path);
} else {
$this->error = tr('The PDF webkit path has not been set.');
}
}
} elseif ($printMode == self::WEASYPRINT) {
$path = $prefs['print_pdf_weasyprint_path'];
if (! empty($path) && is_executable($path)) {
$this->mode = 'weasyprint';
$this->location = $path;
} else {
if (! empty($path)) {
$this->error = tr('PDF WeasyPrint path "%0" not found.', $path);
} else {
$this->error = tr('The PDF WeasyPrint path has not been set.');
}
}
} elseif ($printMode == self::WEBSERVICE) {
$path = $prefs['path'];
if (! empty($path)) {
$this->mode = 'webservice';
$this->location = $path;
} else {
if (! empty($path)) {
$this->error = tr('PDF webservice URL "%0" not found.', $path);
} else {
$this->error = tr('The PDF webservice URL has not been set.');
}
}
} elseif ($printMode == self::MPDF) {
if (class_exists('\\Mpdf\\Mpdf')) {
$this->mode = 'mpdf';
} else {
$this->error = tr('The package mPDF is not installed. You can install it using packages.');
}
}
if ($this->error) {
$this->error = tr('PDF generation failed.') . ' ' . $this->error . ' '
. tr('This is set by the administrator (search for "print" in the control panels to locate the setting).');
}
}
/**
* @param $file
* @param array $params
* @return mixed
*/
public function getPdf($file, array $params, $pdata = '')
{
return TikiLib::lib('tiki')->allocate_extra(
'print_pdf',
function () use ($file, $params, $pdata) {
global $prefs, $base_url, $tikiroot;
if ($prefs['auth_token_access'] == 'y') {
$perms = Perms::get();
require_once 'lib/auth/tokens.php';
$tokenlib = AuthTokens::build($prefs);
$params['TOKEN'] = $tokenlib->createToken(
$tikiroot . $file,
$params,
$perms->getGroups(),
['timeout' => 120]
);
}
if (is_array($params['printpages']) || is_array($params['printstructures'])) {
if (is_array($params['printpages'])) {
$params['printpages'] = implode('&', $params['printpages']);
} else {
$params['printpages'] = implode('&', $params['printstructures']);
}
//getting parsed data
foreach ($params['pages'] as $page) {
$pdata .= $page['parsed'];
}
}
$url = $base_url . $file . '?' . http_build_query($params, '', '&');
$return = $this->{$this->mode}($url, $pdata, $params);
if ($prefs['auth_token_access'] == 'y') {
// clean up token created above just in case PDF needs to access images etc
$data = $tokenlib->getToken($params['TOKEN']);
$tokenlib->deleteToken($data['tokenId']);
}
return $return;
}
);
}
/**
* @param $url
* @return null
*/
private function none($url)
{
return null;
}
/**
* @param $url
* @return mixed
*/
private function webkit($url)
{
// Make sure shell_exec is available
if (! function_exists('shell_exec')) {
die(tra('Required function shell_exec is not enabled.'));
}
// escapeshellarg will replace all % characters with spaces on Windows
// So, decode the URL before sending it to the commandline
$urlDecoded = urldecode($url);
$arg = escapeshellarg($urlDecoded);
// Write a temporary file, instead of using stdout
// There seemed to be encoding issues when using stdout (on Windows 7 64 bit).
// Use temp/public. It is cleaned up during a cache clean, in case some files are left
$filename = 'temp/public/out' . mt_rand() . '.pdf';
// Run shell_exec command to generate out file
// NOTE: this requires write permissions
$quotedFilename = '"' . $filename . '"';
$quotedCommand = '"' . $this->location . '"';
`$quotedCommand -q $arg $quotedFilename`;
// Read the out file
$pdf = file_get_contents($filename);
// Delete the outfile
unlink($filename);
return $pdf;
}
/**
* @param $url
* @return mixed
*/
private function weasyprint($url)
{
// Make sure shell_exec is available
if (! function_exists('shell_exec')) {
die(tra('Required function shell_exec is not enabled.'));
}
// escapeshellarg will replace all % characters with spaces on Windows
// So, decode the URL before sending it to the commandline
$urlDecoded = urldecode($url);
$arg = escapeshellarg($urlDecoded);
// Write a temporary file, instead of using stdout
// There seemed to be encoding issues when using stdout (on Windows 7 64 bit).
// Use temp/public. It is cleaned up during a cache clean, in case some files are left
$filename = 'temp/public/out' . mt_rand() . '.pdf';
// Run shell_exec command to generate out file
// NOTE: this requires write permissions
$quotedFilename = '"' . $filename . '"';
$quotedCommand = '"' . $this->location . '"';
// redirect STDERR to null with 2>/dev/null becasue it outputs plenty of irrelevant warnings (hopefully nothing critical)
`$quotedCommand $arg $quotedFilename 2>/dev/null`;
// Read the out file
$pdf = file_get_contents($filename);
// Delete the outfile
unlink($filename);
return $pdf;
}
/**
* @param $url
* @return bool
*/
private function webservice($url)
{
global $tikilib;
$target = $this->location . '?' . $url;
return $tikilib->httprequest($target);
}
/**
* @param $url string - address of the item to print as PDF
* @return string - contents of the PDF
*/
private function mpdf($url, $parsedData = '', $params = [])
{
global $prefs;
if ($parsedData != '') {
$html = $parsedData;
}
//getting n replacing images
$tempImgArr = [];
$wikilib = TikiLib::lib('wiki');
//checking and getting plugin_pdf parameters if set
$pdfSettings = $this->getPDFSettings($html, $prefs, $params);
//Add page title with content enabled in prefs and page indiviual settings
if (($prefs['feature_page_title'] == 'y' && $wikilib->get_page_hide_title($params['page']) == 0 && $pdfSettings['pagetitle'] != 'n') || $pdfSettings['pagetitle'] == 'y') {
$html = '
' . $params['page'] . ' ' . $html;
}
if ($pdfSettings['toc'] == 'y') { //checking toc
//checking links
if ($pdfSettings['toclinks'] == 'y') {
$links = "links=\"1\"";
}
//checking toc heading
if ($pdfSettings['tocheading']) {
$tocpreHTML = htmlspecialchars("" . $pdfSettings['tocheading'] . " ", ENT_QUOTES);
}
$html = " " . $html . "";
}
$this->_parseHTML($html);
$this->_getImages($html, $tempImgArr);
$defaults = new \Mpdf\Config\ConfigVariables();
$defaultVariables = $defaults->getDefaults();
$mpdfConfig = [
'fontDir' => array_merge([TIKI_PATH . '/lib/pdf/fontdata/fontttf/'], $defaultVariables['fontDir']),
'mode' => 'utf8',
'format' => $pdfSettings['pagesize'],
'margin_left' => $pdfSettings['margin_left'],
'margin_right' => $pdfSettings['margin_right'],
'margin_top' => $pdfSettings['margin_top'],
'margin_bottom' => $pdfSettings['margin_bottom'],
'margin_header' => $pdfSettings['margin_header'],
'margin_footer' => $pdfSettings['margin_footer'],
'orientation' => $pdfSettings['orientation'],
'setAutoTopMargin' => 'stretch',
'setAutoBottomMargin' => 'stretch',
'tempDir' => TIKI_PATH . '/temp/mpdf'
];
if (! file_exists($mpdfConfig['tempDir'])) {
mkdir($mpdfConfig['tempDir'], 0770, true);
}
$mpdf = new \Mpdf\Mpdf($mpdfConfig);
$mpdf->curlAllowUnsafeSslRequests = ($prefs['print_pdf_mpdf_allow_unsafe_ssl_requests'] ?? 'y') === 'y';
//custom fonts add, currently fontawesome support is added, more fonts can be added in future
$custom_fontdata = [
'fontawesome' => [
'R' => "fontawesome.ttf",
'I' => "fontawesome.ttf",
]];
//calling function to add custom fonts
add_custom_font_to_mpdf($mpdf, $custom_fontdata);
//for Cantonese support
$mpdf->autoScriptToLang = true;
$mpdf->autoLangToFont = true;
$mpdf->SetTitle($params['page']);
//toc levels
$mpdf->h2toc = $pdfSettings['toclevels'];
//password protection
if ($pdfSettings['print_pdf_mpdf_password']) {
$mpdf->SetProtection([], 'UserPassword', $pdfSettings['print_pdf_mpdf_password']);
}
$mpdf->CSSselectMedia = 'print'; // assuming you used this in the document header
//getting main base css file
$basecss = file_get_contents('themes/base_files/css/tiki_base.css'); // external css
//getting theme css
$themeLib = TikiLib::lib('theme');
$themecss = $themeLib->get_theme_path($prefs['theme'], '', $prefs['theme'] . '.css');
$themecss = file_get_contents($themecss) . 'b,strong{font-weight:bold !important;}';
$extcss = file_get_contents('vendor/jquery/jquery-sheet/jquery.sheet.css');
//this CSS Overrides bootstrap 4 grid definitions (mPDF doesn't support Bootstrap 4)
$customGrid = file_get_contents('themes/base_files/css/custom_grid_pdf.css');
//checking if print friendly option is enabled, then attach print css otherwise theme styles will be retained by theme css
if ($pdfSettings['print_pdf_mpdf_printfriendly'] == 'y') {
$printcss = file_get_contents('themes/base_files/css/printpdf.css'); // external css
$bodycss = 'tiki tiki-print'; //execluding theme css in case print friendly is set to yes.
} else {//preserving theme styles by removing media print styles to print what is shown on screen
$themecss = str_replace(["media print","color : fff"], ["media p","color : #fff"], $themecss);
$printcss = file_get_contents('themes/base_files/css/printqueries.css'); //for bootstrap print hidden, screen hidden styles on divs
$bodycss = '';
}
$pdfPages = $this->getPDFPages($html, $pdfSettings);
$cssStyles = str_replace([".tiki","opacity: 0;","page-break-inside: avoid;"], ["","fill: #fff;opacity:0.3;stroke:black","page-break-inside: auto;"], ''); //adding css styles with first page content
//PDF import templates will not work if background color is set, need to replace in css
if (
array_filter(array_column($pdfPages, 'pageContent'), function ($var) {
return preg_match("/\bpdfinclude\b/i", $var);
})
) {
$cssStyles = str_replace(["background-color: #fff;","background:#fff;"], "background:none", $cssStyles);
}
//cover page checking
if ($pdfSettings['coverpage_text_settings'] != '' || ($pdfSettings['coverpage_image_settings'] != '' && $pdfSettings['coverpage_image_settings'] != 'off')) {
$coverPage = explode("|", $pdfSettings['coverpage_text_settings']);
$coverImage = $pdfSettings['coverpage_image_settings'] != 'off' ? $pdfSettings['coverpage_image_settings'] : '';
$mpdf->SetHTMLHeader(); //resetting header footer for cover page
$mpdf->SetHTMLFooter();
$mpdf->AddPage($pdfSettings['orientation'], '', '', '', '', 0, 0, 0, 0, 0, 0); //adding new page with 0 margins
$coverPage[2] = $coverPage[2] == '' ? 'center' : $coverPage[2];
//getting border settings
if (count($coverPage) > 5) {
$borderWidth = $coverPage[5] == '' ? 1 : $coverPage[5];
$coverPageTextStyles = 'border:' . $borderWidth . ' solid ' . $coverPage[6] . ';';
} else {
$coverPageTextStyles = '';
}
$bgColor = $coverPage[3] == '' ? 'background-color:' . $coverPage[3] : '';
$mpdf->WriteHTML('
' . $coverPage[0] . '
' . $coverPage[1] . '
');
}
//Checking bookmark
if (is_array($pdfSettings['autobookmarks'])) {
$mpdf->h2bookmarks = $pdfSettings['autobookmarks'];
}
$pageNo = 1;
$pagesTotal = 1;
$pdfLimit = ini_get('pcre.backtrack_limit');
//end of coverpage generation
foreach ($pdfPages as $pdfPage) {
$resetPage = '';
if ($pageNo == 1) {
$resetPage = 1;
}
if (strip_tags(trim($pdfPage['pageContent']), "img,pdfinclude") != '') { //including external pdf
if (strpos($pdfPage['pageContent'], "
.",""," ","\""], "", $pdfPage['pageContent']);
$breakPageContent = trim($breakPageContent);
if ($prefs['auth_token_access'] === 'y') {
global $tikiroot;
if (preg_match('/dl(\d+)/', $breakPageContent, $parts)) {
$fileId = isset($parts[1]) ? $parts[1] : 0;
$params = ['fileId' => $fileId];
$tokenParam = '?TOKEN';
}
if (preg_match('/display(\d+)/', $breakPageContent, $parts)) {
$fileId = isset($parts[1]) ? $parts[1] : 0;
$params = ['fileId' => $fileId, 'display' => ''];
$tokenParam = '?TOKEN';
}
if (preg_match('/fileId=(\d+)/', $breakPageContent, $parts)) {
$fileId = isset($parts[1]) ? $parts[1] : 0;
$params = ['fileId' => $fileId];
$tokenParam = '&TOKEN';
}
if (preg_match('/fileId=(\d+)(.*)display/', $breakPageContent, $parts)) {
$fileId = isset($parts[1]) ? $parts[1] : 0;
$params = ['fileId' => $fileId, 'display' => ''];
$tokenParam = '&TOKEN';
}
if ($fileId > 0) {
$perms = Perms::get();
require_once 'lib/auth/tokens.php';
$tokenlib = AuthTokens::build($prefs);
$token = $tokenlib->createToken(
$tikiroot . 'tiki-download_file.php',
$params,
$perms->getGroups(),
['timeout' => 72000, 'hits' => 1]
);
$breakPageContent = htmlspecialchars_decode($breakPageContent) . $tokenParam . '=' . $token;
}
}
$tmpExtPDF = "temp/tmp_" . rand(0, 999999999) . ".pdf";
file_put_contents($tmpExtPDF, fopen($breakPageContent, 'r'));
chmod($tmpExtPDF, 0755);
$finfo = finfo_open(FILEINFO_MIME_TYPE); //recheck if its valid pdf file
if (finfo_file($finfo, $tmpExtPDF) === 'application/pdf') {
try {
$pagecount = $mpdf->setSourceFile(
$tmpExtPDF
); //temp file name
for ($i = 1; $i <= $pagecount; $i++) {
$tplId = $mpdf->importPage($i);
$size = $mpdf->getTemplateSize($tplId);
$orientation = isset($size['orientation']) ? $size['orientation'] : '';
$mpdf->SetHTMLHeader();
$mpdf->AddPage($orientation);
$mpdf->SetHTMLFooter();
$mpdf->UseTemplate($tplId);
}
} catch (Exception $e) {
$mpdf->WriteHTML("PDF not supported");
}
}
unlink($tmpExtPDF);
} else {
//checking header and footer
if (trim(strtolower($pdfPage['header'])) == "off") {
$header = "";
} else {
$pdfPage['header'] == '' ? $header = $pdfSettings['header'] : $header = $pdfPage['header'];
}
if (trim(strtolower($pdfPage['footer'])) == "off") {
$footer = "";
} elseif ($pdfPage['footer']) {
$footer = $pdfPage['footer'];
}
$mpdf->SetHTMLHeader($this->processHeaderFooter($header, $params['page']));
$mpdf->AddPage($pdfPage['orientation'], '', $resetPage, '', '', $pdfPage['margin_left'], $pdfPage['margin_right'], $pdfPage['margin_top'], $pdfPage['margin_bottom'], $pdfPage['margin_header'], $pdfPage['margin_footer'], '', '', '', '', '', '', '', '', '', $pdfPage['pagesize']);
$mpdf->SetHTMLFooter($this->processHeaderFooter($footer, $params['page'], 'top')); //footer needs to be reset after page content is added
//checking watermark on page
$mpdf->SetWatermarkText($pdfPage['watermark']);
$mpdf->showWatermarkText = true;
$mpdf->SetWatermarkImage($pdfPage['watermark_image'], 0.15, '');
if ($pdfPage['background_image']) {
$mpdf->SetWatermarkImage($pdfPage['background_image'], 1);
$mpdf->watermarkImgBehind = true;
}
$mpdf->showWatermarkImage = true;
//hyperlink check
if ($pdfPage['hyperlinks'] != "") {
$pdfPage['pageContent'] = $this->processHyperlinks($pdfPage['pageContent'], $pdfPage['hyperlinks'], $pageCounter++);
}
if ($pdfPage['columns'] > 1) {
$mpdf->SetColumns($pdfPage['columns'], 'justify');
} else {
$mpdf->SetColumns(1, 'justify');
}
$backgroundImage = '';
if (strstr($_GET['display'], 'pdf') != '') {
$bgColor = "background: linear-gradient(top, '','');";
}
if ($pdfPage['background'] != '') {
$bgColor = "background: linear-gradient(top, " . $pdfPage['background'] . ", " . $pdfPage['background'] . ");";
}
$pdfPage['pageContent'] = $this->getHtmlLayout($pdfPage['pageContent']);
$mpdf->WriteHTML('' . $cssStyles);
$pagesTotal += floor(strlen($pdfPage['pageContent']) / 3000);
//checking if page content is less than mPDF character limit, otherwise split it and loop to writeHTML
for ($charLimit = 0; $charLimit <= strlen($pdfPage['pageContent']); $charLimit += $pdfLimit) {
$mpdf->WriteHTML(substr($pdfPage['pageContent'], $charLimit, $pdfLimit));
}
$mpdf->WriteHTML('');
$pageNo++;
$cssStyles = ''; //set to blank after added with first page
}
}
}
$mpdf->setWatermarkText($pdfSettings['watermark']);
$mpdf->SetWatermarkImage($pdfSettings['watermark_image'], 0.15, '');
//resetting header,footer
trim(strtolower($pdfSettings['header'])) == "off" ? $mpdf->SetHTMLHeader() : $mpdf->SetHTMLHeader($this->processHeaderFooter($pdfSettings['header'], $params['page']));
trim(strtolower($pdfSettings['footer'])) == "off" ? $mpdf->SetHTMLFooter() : $mpdf->SetHTMLFooter($this->processHeaderFooter($pdfSettings['footer'], $params['page'], 'top'));
$this->clearTempImg($tempImgArr);
$tempFile = fopen("temp/public/pdffile_" . session_id() . ".txt", "w");
fwrite($tempFile, ($pagesTotal * 30));
return $mpdf->Output('', 'S'); // Return as a string
}
public function getHtmlLayout($pageContent)
{
require_once('tiki-setup.php');
$modlib = TikiLib::lib('mod');
include_once('tiki-module_controls.php');
global $prefs, $user;
clearstatcache();
preg_match_all('#\"(.*?)\"#', $prefs['print_pdf_modules'], $match);
$modules_to_print = array_map(
function ($item) {
return str_replace('"','', $item);
},
$match[0]
);
$modules_to_print_contents = [];
$modules = $modlib->get_modules_for_user($user);
$modnames = [];
if (is_array($modules_to_print)) {
foreach ($modules_to_print as $module_key) {
$content = '';
if (isset($modules[$module_key]) && is_array($modules[$module_key])) {
foreach ($modules[$module_key] as & $mod_reference) {
$ref = (array) $mod_reference;
$mod_reference['data'] = new Tiki_Render_Lazy(
function () use ($ref) {
$modlib = TikiLib::lib('mod');
return $modlib->execute_module($ref);
}
);
$modnames[$ref['name']] = '';
}
$content = implode(
'',
array_map(
function ($module) {
return (isset($module['data']) ? $module['data'] : '');
},
$modules[$module_key]
)
);
}
$dir = '';
if (Language::isRTL()) {
$dir = ' dir="rtl"';
}
$modules_to_print_contents[$module_key] = <<
$content
OUT;
}
}
$htmlLayout["staringPart"] = '';
$htmlLayout["endingPart"] = '';
if ($modules_to_print_contents['top_modules']) {
$htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '' . $modules_to_print_contents['top_modules'] . '
';
}
if ($modules_to_print_contents['topbar_modules']) {
$htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '' . $modules_to_print_contents['topbar_modules'] . '
';
}
$htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '';
if ($modules_to_print_contents['left_modules'] || $modules_to_print_contents['right_modules']) {
$sideColumn = 'col-xs-4';
if ($modules_to_print_contents['left_modules'] && $modules_to_print_contents['right_modules']) {
$sideColumn = 'col-xs-2';
}
if ($modules_to_print_contents['left_modules']) {
$htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '
' . $modules_to_print_contents['left_modules'] . '
';
}
$htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '
';
if ($modules_to_print_contents['pagetop_modules']) {
$htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '
' . $modules_to_print_contents['pagetop_modules'] . '
';
}
if ($modules_to_print_contents['pagebottom_modules']) {
$htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '
' . $modules_to_print_contents['pagebottom_modules'] . '
';
}
$htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '
';
if ($modules_to_print_contents['right_modules']) {
$htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '
' . $modules_to_print_contents['right_modules'] . '
';
}
} else {
if ($modules_to_print_contents['pagetop_modules']) {
$htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '
' . $modules_to_print_contents['pagetop_modules'] . '
';
}
if ($modules_to_print_contents['pagebottom_modules']) {
$htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '
' . $modules_to_print_contents['pagebottom_modules'] . '
';
}
}
$htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '
';
//check if Module contains navbar and force display (when printing nav is by default display none)
if (str_contains($htmlLayout["staringPart"], '", "", $pageContent);
}
if ($modules_to_print_contents['bottom_modules']) {
$htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '' . $modules_to_print_contents['bottom_modules'] . '
';
}
$pageContent = str_replace("", "" . $htmlLayout["staringPart"], $pageContent);
$pageContent = str_replace("", $htmlLayout["endingPart"] . "", $pageContent);
return $pageContent;
}
public function getPDFSettings($html, $prefs, $params)
{
$pdfSettings = [];
//checking if pdf plugin is set and passed
$doc = new DOMDocument();
@$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$pdf = $doc->getElementsByTagName('pdfsettings')->item(0);
$prefs['print_pdf_mpdf_pagesize'] = $prefs['print_pdf_mpdf_size'];
if ($pdf) {
if ($pdf->hasAttributes()) {
foreach ($pdf->attributes as $attr) {
//overridding global settings
$prefs['print_pdf_mpdf_' . $attr->nodeName] = $attr->nodeValue;
}
}
}
//checking preferences
$pdfSettings['print_pdf_mpdf_printfriendly'] = $prefs['print_pdf_mpdf_printfriendly'] != '' ? $prefs['print_pdf_mpdf_printfriendly'] : '';
$orientation = ! empty($params['orientation']) ? $params['orientation'] : $prefs['print_pdf_mpdf_orientation'];
$pdfSettings['orientation'] = $orientation != '' ? $orientation : 'P';
$pdfSettings['pagesize'] = $prefs['print_pdf_mpdf_pagesize'] != '' ? $prefs['print_pdf_mpdf_pagesize'] : 'Letter';
if (in_array($pdfSettings['pagesize'], ['Tabloid/Ledger', 'Tabloid-Ledger'])) {
$pdfSettings['pagesize'] = 'Tabloid';
}
//custom size needs to be passed for Tabloid
if ($prefs['print_pdf_mpdf_size'] == "Tabloid") {
$pdfSettings['pagesize'] = [279,432];
} elseif ($pdfSettings['orientation'] == 'L') {
$pdfSettings['pagesize'] = $pdfSettings['pagesize'] . '-' . $pdfSettings['orientation'];
}
$pdfSettings['margin_left'] = $prefs['print_pdf_mpdf_margin_left'] != '' ? $prefs['print_pdf_mpdf_margin_left'] : '10';
$pdfSettings['margin_right'] = $prefs['print_pdf_mpdf_margin_right'] != '' ? $prefs['print_pdf_mpdf_margin_right'] : '10';
$pdfSettings['margin_top'] = $prefs['print_pdf_mpdf_margin_top'] != '' ? $prefs['print_pdf_mpdf_margin_top'] : '10';
$pdfSettings['margin_bottom'] = $prefs['print_pdf_mpdf_margin_bottom'] != '' ? $prefs['print_pdf_mpdf_margin_bottom'] : '10';
$pdfSettings['margin_header'] = $prefs['print_pdf_mpdf_margin_header'] != '' ? $prefs['print_pdf_mpdf_margin_header'] : '5';
$pdfSettings['margin_footer'] = $prefs['print_pdf_mpdf_margin_footer'] != '' ? $prefs['print_pdf_mpdf_margin_footer'] : '5';
$pdfSettings['header'] = str_ireplace("{PAGETITLE}", $params['page'], $prefs['print_pdf_mpdf_header']);
$pdfSettings['footer'] = str_ireplace("{PAGETITLE}", $params['page'], $prefs['print_pdf_mpdf_footer']);
$pdfSettings['print_pdf_mpdf_password'] = $prefs['print_pdf_mpdf_password'];
$pdfSettings['toc'] = $prefs['print_pdf_mpdf_toc'] != '' ? $prefs['print_pdf_mpdf_toc'] : 'n';
$pdfSettings['toclinks'] = $prefs['print_pdf_mpdf_toclinks'] != '' ? $prefs['print_pdf_mpdf_toclinks'] : 'n';
$pdfSettings['tocheading'] = $prefs['print_pdf_mpdf_tocheading'];
$pdfSettings['pagetitle'] = $prefs['print_pdf_mpdf_pagetitle'];
$pdfSettings['watermark'] = $prefs['print_pdf_mpdf_watermark'];
$pdfSettings['watermark_image'] = $prefs['print_pdf_mpdf_watermark_image'];
$pdfSettings['coverpage_text_settings'] = str_ireplace("{PAGETITLE}", $params['page'], $prefs['print_pdf_mpdf_coverpage_text_settings']);
$pdfSettings['coverpage_image_settings'] = str_ireplace("{PAGETITLE}", $params['page'], $prefs['print_pdf_mpdf_coverpage_image_settings']);
$pdfSettings['hyperlinks'] = $prefs['print_pdf_mpdf_hyperlinks'];
$pdfSettings['columns'] = $prefs['print_pdf_mpdf_columns'];
$pdfSettings['background'] = $prefs['print_pdf_mpdf_background'];
$pdfSettings['background_image'] = $prefs['print_pdf_mpdf_background_image'];
$pdfSettings['autobookmarks'] = $prefs['print_pdf_mpdf_autobookmarks'];
if ($pdfSettings['toc'] == 'y') {
//toc levels
['H1' => 0, 'H2' => 1, 'H3' => 2];
$toclevels = $prefs['print_pdf_mpdf_toclevels'] != '' ? $prefs['print_pdf_mpdf_toclevels'] : 'H1|H2|H3';
$toclevels = explode("|", $toclevels);
$pdfSettings['toclevels'] = [];
for ($toclevel = 0; $toclevel < count($toclevels); $toclevel++) {
$pdfSettings['toclevels'][$toclevels[$toclevel]] = $toclevel;
}
}
//Setting PDF bookmarks
if ($pdfSettings['autobookmarks']) {
$bookmark = explode("|", $pdfSettings['autobookmarks']);
$pdfSettings['autobookmarks'] = [];
for ($level = 0; $level < count($bookmark); $level++) {
$pdfSettings['autobookmarks'][strtoupper($bookmark[$level])] = $level;
}
}
//PDF settings
return $pdfSettings;
}
//mpdf read page for plugin PDFPage, introduced for advanced pdf creation
public function getPDFPages($html, $pdfSettings)
{
//checking if pdf page tag exists
$doc = new DOMDocument();
$doc->loadHTML($html);
$xpath = new DOMXpath($doc);
//Getting pdf page custom pages from content
$pdfPages = $doc->getElementsByTagName('pdfpage');
$pageData = [];
$mainContent = $html;
foreach ($pdfPages as $page) {
$pages = [];
$pageTag = "hasAttributes()) {
foreach ($page->attributes as $attr) {
$pages[$attr->nodeName] = $attr->nodeValue;
$paramVal = str_replace(""", '"', htmlentities($attr->nodeValue));
strchr($paramVal, '"') ? $enclosingChar = "'" : $enclosingChar = "\"";
$pageTag .= " " . $attr->nodeName . "=" . $enclosingChar . $paramVal . $enclosingChar;
}
}
$pageTag .= ">";
//mapping empty values with defaults
foreach ($pdfSettings as $setting => $value) {
if ($pages[$setting] == "") {
$pages[$setting] = $value;
}
}
if (in_array($pages['pagesize'], ['Tabloid/Ledger', 'Tabloid-Ledger'])) {
$pages['pagesize'] = 'Tabloid';
}
if ($pages['pagesize'] == "Tabloid") {
$pages['pagesize'] = [279,432];
} elseif ($pages['orientation'] == 'L') {
$pages['pagesize'] = $pages['pagesize'] . '-' . $pages['orientation'];
}
//dividing content in segments
$ppages = explode($pageTag, $mainContent, 2);
$lpages = explode(" ", $ppages[1], 2);
//for prepage settings pdfsettings will be used
if (preg_replace('~<(?:!DOCTYPE|/?(?:html|body))[^>]*>\s*~i', '', $ppages[0]) != "") {
$prePage = $pdfSettings;
$prePage['pageContent'] = $ppages[0];
$pageData[] = $prePage;
}
$pages['pageContent'] = $doc->saveXML($page);
$pageData[] = $pages;
if (trim(strip_tags($lpages[1])) != "") {
$mainContent = $lpages[1];
}
}
//no pages found
if (count($pageData) == 0) {
$defaultPage = $pdfSettings;
$defaultPage['pageContent'] = $html;
$pageData[] = $defaultPage;
} elseif (trim(strip_tags($lpages[1])) != '') { //adding and resetting options for last page if any
$lastPage = $pdfSettings;
$lastPage['pageContent'] = $lpages[1];
$pageData[] = $lastPage;
}
return $pageData;
}
public function _getImages(&$html, &$tempImgArr)
{
$doc = new DOMDocument();
@$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$tags = $doc->getElementsByTagName('img');
foreach ($tags as $tag) {
$imgSrc = $tag->getAttribute('src');
//bypassing base64 encoded images
if (! strstr($imgSrc, ';base64')) {
//replacing image with new temp image, all these images will be unlinked after pdf creation
$newFile = $this->file_get_contents_by_fget($imgSrc);
//replacing old protected image path with temp image
if ($newFile != '') {
$tag->setAttribute('src', $newFile);
}
$tempImgArr[] = $newFile;
}
}
$html = @$doc->saveHTML();
}
public function file_get_contents_by_fget($url)
{
global $base_url;
//check if image is internal with full path
$internalImg = 0;
if (substr($url, 0, strlen($base_url)) == $base_url) {
$internalImg = 1;
}
//checking for external images
$checkURL = parse_url($url);
//not replacing in case of external image
if (($checkURL['scheme'] == 'https' || $checkURL['scheme'] == 'http') && ! $internalImg) {
return '';
}
if (! $internalImg) {
$url = $base_url . $url;
}
if (! file_exists('temp/pdfimg')) {
mkdir('temp/pdfimg');
chmod('temp/pdfimg', 0755);
}
$opts = ['http' => ['header' => 'Cookie: ' . $_SERVER['HTTP_COOKIE'] . "\r\n"]];
$context = stream_context_create($opts);
session_write_close();
$data = file_get_contents($url, false, $context);
$newFile = 'temp/pdfimg/pdfimg' . mt_rand(9999, 999999) . '.png';
file_put_contents($newFile, $data);
chmod($newFile, 0755);
return $newFile;
}
public function clearTempImg($tempImgArr)
{
foreach ($tempImgArr as $tempImg) {
unlink($tempImg);
}
}
public function _parseHTML(&$html)
{
//Replace all word separators as this is already fixed with CSS
$html = str_replace(["", " "], "", $html);
$doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$tables = $doc->getElementsByTagName('table');
$tempValue = [];
$sortedContent = [];
foreach ($tables as $table) {
$this->sortContent($table, $tempValue, $sortedContent, $table->tagName);
}
$xpath = new DOMXpath($doc);
//defining array of plugins to be sorted
$pluginArr = [["class","customsearch_results","div"],["id","container_pivottable","div"],["class","dynavar","a"], ["class", "tiki_sheet", "div"]];
$tagsArr = [["input","tablesorter-filter","class"],["select","tablesorter-filter","class"],["select","pvtRenderer","class"],["select","pvtAggregator","class"],["td","pvtCols","class"],["td","pvtUnused","class"],["td","pvtRows","class"],["div","plot-container","class"],["a","heading-link","class"],["a","tablename","class","1"], ["div", "jSScroll", "class"], ["span", "jSTabContainer", "class"], ["a", "tiki_sheeteditbtn", "class"],["div","comment-footer","class"],["div","buttons comment-form","class"],["div","clearfix tabs","class"],["a","pvtRowOrder","class"],["a","pvtColOrder","class"],["select","pvtAttrDropdown","class"]];
foreach ($pluginArr as $pluginInfo) {
$customdivs = $xpath->query('//*[contains(@' . $pluginInfo[0] . ', "' . $pluginInfo[1] . '")]');
for ($i = 0; $i < $customdivs->length; $i++) {
if ($pluginInfo[1] == "dynavar") {
$dynId = str_replace("display", "edit", $customdivs->item($i)->parentNode->getAttribute('id'));
$tagsArr[] = ["span",$dynId,"id"];
} else {
$customdiv = $customdivs->item($i);
$this->sortContent($customdiv, $tempValue, $sortedContent, $pluginInfo[2]);
}
}
}
$html = @$doc->saveHTML();
//replacing temp table with sorted content
for ($i = 0; $i < count($sortedContent); $i++) {
$html = str_replace($tempValue[$i], $sortedContent[$i], $html);
}
$html = cleanContent($html, $tagsArr);
//making tablesorter and pivottable charts wrapper divs visible
$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$this->checkLargeTables($doc); //hack function for large data columns
$xpath = new DOMXpath($doc);
$wrapperDefs = [["class","ts-wrapperdiv","visibility:visible"],["id","png_container_pivottable","display:none"]];
foreach ($wrapperDefs as $wrapperDef) {
$wrapperdivs = $xpath->query('//*[contains(@' . $wrapperDef[0] . ', "' . $wrapperDef[1] . '")]');
for ($i = 0; $i < $wrapperdivs->length; $i++) {
$wrapperdiv = $wrapperdivs->item($i);
$wrapperdiv->setAttribute("style", $wrapperDef[2]);
}
}
$html = @$doc->saveHTML();
//font awesome support call
$this->fontawesome($html);
//& sign added in fa unicodes for proper printing in pdf
$html = str_replace('#x', "", $html);
}
private function checkLargeTables(&$doc)
{
//new code to split table large cells
foreach ($doc->getElementsByTagName('table') as $table) {
// iterate over each row in the table
$trs = $table->getElementsByTagName('tr');
$cloneArr = [];
foreach ($trs as $tr) {
$cloned = 0;
foreach ($tr->getElementsByTagName('td') as $td) { // get the columns in this row
if (strlen($td->textContent) > 2000) {
$longValue = $td->nodeValue;
$breaktill = strpos($td->nodeValue, '.', 1000);
if ($cloned == 0) {
$cloneNode = $tr->cloneNode(true);
$cloned = 1;
$cloneArr[] = ["node" => $cloneNode,'row' => $tr,'breaktill' => $breaktill];
}
$td->textContent = substr($longValue, 0, $breaktill) . '. (cont.)';
$td->setAttribute("style:", "white-space: nowrap");
$td->setAttribute("width", "20%");
}
}
}
//here insert new nodes
foreach ($cloneArr as $cloneData) {
$this->insertNewNodes($cloneData, $table); //this will be recursive function to split row multiple times if needed
}
}
$html = @$doc->saveHTML();
}
private function insertNewNodes(&$cloneData, &$table, $start = 1000)
{
//processing cloneNodes
$cloned = 0;
foreach ($cloneData['node']->getElementsByTagName('td') as $td) {
$longValue = $td->textContent;
if (strlen($longValue) > $start) {
$breaktill = strpos($longValue, '.', $start); //starting point after first fullstop
if (strlen($longValue) > ($breaktill + 1000)) {
$endPoint = $breaktill + 1000;
$end = strpos($longValue, '.', $endPoint) - $breaktill; //end point till last sentence
} else {
$end = 1000;
}
if (strlen($longValue) > $end + $breaktill && $cloned == 0) {
$cloned = 1;
$newNode = [];
$newNode['node'] = $cloneData['node']->cloneNode(true);
$newNode['row'] = $cloneData['node'];
}
$td->textContent = '(cont\'d)' . substr($longValue, $breaktill + 1, $end);
} else {
$td->textContent = '';
}
}
try {
$cloneData['row']->parentNode->insertBefore($cloneData['node'], $cloneData['row']->nextSibling);
} catch (\Exception $e) {
$table->appendChild($cloneData['node']);
}
if ($cloned == 1) {
$this->insertNewNodes($newNode, $table, $start + 1000);
}
}
public function fontawesome(&$html)
{
$doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$xpath = new DOMXpath($doc);
//font awesome code insertion
$fadivs = $xpath->query('//*[contains(@class, "fa")]');
//loading json file if there is any font-awesome tag in html
if ($fadivs->length) {
$faCodes = file_get_contents('lib/pdf/fontdata/fa-codes.json');
$jfo = json_decode($faCodes, true);
for ($i = 0; $i < $fadivs->length; $i++) {
$fadiv = $fadivs->item($i);
$faClass = explode(" ", str_replace(["fa ","-"], "", $fadiv->getAttribute('class')));
foreach ($faClass as $class) {
if (! empty($jfo[$class]['codeValue'])) {
$faCode = $doc->createElement('span', " " . $jfo[$class]['codeValue']);
$faCode->setAttribute("style", "font-family: FontAwesome;float:left;padding-left:5px" . $fadiv->getAttribute('style'));
//span with fontawesome code inserted before fa div
$faCode->setAttribute("class", $fadiv->getAttribute('class'));
$fadiv->parentNode->insertBefore($faCode, $fadiv);
$fadiv->parentNode->removeChild($fadiv);
}
}
}
}
$html = @$doc->saveHTML();
}
public function bootstrapReplace()
{
return ".col-xs-12 {width: 100%;}.col-xs-11 {width: 81.66666667%;}.col-xs-10 {width: 72%;}.col-xs-9 {width: 64%;}.col-xs-8 {width: 62%;}.col-xs-7 {width: 49%;}.col-xs-6 {width: 45.7%;}.col-xs-5 {width: 35%;}.col-xs-4 {width: 28%;}.col-xs-3{width: 20%;}.col-xs-2 {width: 12.2%;}.col-xs-1 {width: 3.92%;} .table-striped {border:1px solid #ccc;} .table-striped td { padding: 8px; line-height: 1.42857143;vertical-align: center;border-top: 1px solid #ccc;} .table-striped th { padding: 10px; line-height: 1.42857143;vertical-align: center; } .table-striped .odd {padding:10px;} .table-striped .even {padding:10px;}.trackerfilter form{display:none;} table.pvtTable tr td {border:1px solid}.wp-sign{position:relative;display:block;background-color:#fff;color:#666;font-size:10px} .wp-sign a,.wp-sign a:visited{color:#999} .icon-link-external{margin-left:10px;font-size:10px} .ui-widget-content{width:100%} .ui-widget-content td{border:solid 1px #ccc;padding:5px} .jSBarLeft{width:30px} .dl-horizontal dt {float: left;width: 160px;clear: left;text-align: right;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.dl-horizontal dd {margin-left: 180px;}.media-left, .media-right, .media-body {border:none !important;float:left;display:inline-block;width:55px;}.media-body{width:80%}.media comment{clear:both}";
}
public function sortContent(&$table, &$tempValue, &$sortedContent, $tag)
{
$content = '';
$tid = $table->getAttribute("id");
if (file_exists("temp/#" . $tid . "_" . session_id() . ".txt")) {
$content = mb_convert_encoding(file_get_contents("temp/#" . $tid . "_" . session_id() . ".txt"), 'HTML-ENTITIES', 'UTF-8');
//formating content
$tableTag = "<" . $tag;
if ($table->hasAttributes()) {
foreach ($table->attributes as $attr) {
$tableTag .= " " . $attr->nodeName . "=\"" . $attr->nodeValue . "\"";
}
}
$tableTag .= ">";
$content = str_ireplace('yle>', '