From 6456360eff5b14dbe109d903ce508a25c85f1567 Mon Sep 17 00:00:00 2001 From: Eunice Remoquillo Date: Fri, 1 Mar 2024 10:52:18 +0800 Subject: [PATCH 1/9] Initial commit for pdf alternative This commit uses tcpdf instead of wkhtmltopdf library. Still missing updates for running scripts on tcpdf and code snippets for logs. --- modules/reports/controllers/base_reports.php | 144 +++++++++++-------- 1 file changed, 85 insertions(+), 59 deletions(-) diff --git a/modules/reports/controllers/base_reports.php b/modules/reports/controllers/base_reports.php index dd9f46704..268b33674 100644 --- a/modules/reports/controllers/base_reports.php +++ b/modules/reports/controllers/base_reports.php @@ -87,71 +87,97 @@ protected function generate_toolbar() { */ protected function generate_pdf() { + // Require tcpdf + require Kohana::find_file('vendor', 'tcpdf/tcpdf'); + $resource = ObjectPool_Model::pool('hosts')->all()->mayi_resource(); $this->_clear_print_notification(); $this->_verify_access($resource.':read.report.'.$this->type.'.pdf'); $this->template->base_href = 'https://localhost'.url::base(); - # not using exec, so STDERR (used for status info) will be loggable - $pipe_desc = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w')); - $pipes = false; - - $command = Kohana::config('reports.pdf_command'); - $brand = brand::get('http://localhost', false); - $command .= ' --replace brand "' . $brand . '"'; - $command .= ' - -'; - - $this->log->log('debug', "Running pdf generation command '$command'"); - $process = proc_open($command, $pipe_desc, $pipes, DOCROOT); - - if (is_resource($process)) { - // Render and store output - $content = $this->template->render(); - $this->log->log('debug', "HTML: $content"); - $this->auto_render = false; - - $filename = $this->type; - if ($this->options['schedule_id']) { - $schedule_info = Scheduled_reports_Model::get_scheduled_data($this->options['schedule_id']); - if ($schedule_info) - $filename = $schedule_info['filename']; - } - $months = date::abbr_month_names(); - $month = $months[date('m')-1]; // January is [0] - $filename = preg_replace("~\.pdf$~", null, $filename)."_".date("Y_").$month.date("_d").'.pdf'; - - fwrite($pipes[0], $content); - fclose($pipes[0]); - - $out = stream_get_contents($pipes[1]); - $err = stream_get_contents($pipes[2]); - if (trim($out)) { - header("Content-disposition: attachment; filename=$filename"); - header('Content-Type: application/pdf'); - header("Pragma: public"); - header("Expires: 0"); - header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); - header("Cache-Control: private", false); - header("Content-Transfer-Encoding: binary"); - echo $out; - } else { - $this->log->log('error', "Pdf command " . $command . "resulted in no output. stderr:"); - $this->log->log('error', $err); - } - fclose($pipes[1]); - fclose($pipes[2]); - $return_value = proc_close($process); - if ($return_value != 0) { - $this->log->log('debug', "Pdf command " . $command . " returned $return_value:"); - $this->log->log('debug', "stderr: $err"); - } - } else { - $this->log->log('error', "Tried running the following command but was unsuccessful:"); - $this->log->log('error', $command); + // Set filename + $filename = $this->type; + if ($this->options['schedule_id']) { + $schedule_info = Scheduled_reports_Model::get_scheduled_data($this->options['schedule_id']); + if ($schedule_info) + $filename = $schedule_info['filename']; + } + $months = date::abbr_month_names(); + $month = $months[date('m')-1]; // January is [0] + $filename = preg_replace("~\.pdf$~", null, $filename)."_".date("Y_").$month.date("_d").'.pdf'; + + // Get Contents + $content = $this->template->content->render(); + + // Fix HTML Query - Ongoing + + // Use a regular expression to: + // match image tags + $img_pattern = '/]*src="([^"]+)"[^>]*>/'; + preg_match_all($img_pattern, $content, $img_matches); + + // Iterate through matched image tags + foreach ($img_matches[1] as $index=>$src) { + // Check if the image exists + if (file_exists($src)===false) + // Replace the image tag with a placeholder // Temporary - Ongoing + $content = str_replace($img_matches[0][$index],'[IMG]', $content); + } + + // match form tags + $form_pattern = '/]*>(.*?)<\/div>/s'; + preg_match_all($form_pattern, $content, $form_matches); + + // remove the hidden form + foreach ($form_matches[0] as $i=>$x) { + $content = str_replace($form_matches[0][$i], '', $content); } + + //prepare css file - Ongoing - Test + $prep_css = 'application/media/css/jquery.filterable.css'; + $contentwithcss = '' . $content; + + //============================================================+ + // START OF DOCUMENT + //============================================================+ + + // Create PDF Document + $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); + + // Set document information + $pdf->SetTitle($filename); + $pdf->SetSubject($filename); + + // set margins + $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); + + // set auto page breaks + $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + + // set image scale factor + $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + + // set font + // $pdf->SetFont('opensans', 'R', 10); + + // add a page + $pdf->AddPage(); + + // Set header and footer - Ongoing + + // print HTMLstring + $pdf->writeHTML($contentwithcss, false, false, false, false, 'UTF-8'); + + // $pdf->IncludeJS($content_script); + + //Close and output PDF document + $pdf->Output($filename, 'I'); + + //============================================================+ + // END OF FILE + //============================================================+ + + // Create logs - Ongoing } /** From 8a6575d9cb39f5b089b3465bc11c3528d5ccbf13 Mon Sep 17 00:00:00 2001 From: Eunice Remoquillo Date: Fri, 1 Mar 2024 13:49:28 +0800 Subject: [PATCH 2/9] Open form in new tab This commit enables opening the form in new tab for pdf download. --- modules/reports/controllers/base_reports.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/reports/controllers/base_reports.php b/modules/reports/controllers/base_reports.php index 268b33674..e9801a175 100644 --- a/modules/reports/controllers/base_reports.php +++ b/modules/reports/controllers/base_reports.php @@ -51,7 +51,7 @@ protected function generate_toolbar() { $this->template->toolbar = new Toolbar_Controller('Report'); if($this->type != 'histogram') { - $pdf_button = form::open($this->type.'/generate'); + $pdf_button = form::open($this->type.'/generate', array('target'=>'_blank')); $pdf_button .= $this->options->as_form(); $pdf_button .= ''; $pdf_button .= sprintf('', _('As PDF')); From a10c43f1b6d324880608ebc9d9b76ac22ab96a2c Mon Sep 17 00:00:00 2001 From: Eunice Remoquillo Date: Tue, 5 Mar 2024 20:57:24 +0800 Subject: [PATCH 3/9] Fetch html strings instead or template object Removed check patterns that replaces images and forms. Initial update on script that captures the report elements and should be sent to the controller using ajax. This way, regenerating the content for a pdf file will not be needed in downloading more accurate report data. --- modules/reports/controllers/base_reports.php | 58 +++++++------------- modules/reports/views/reports/index.php | 30 ++++++++++ 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/modules/reports/controllers/base_reports.php b/modules/reports/controllers/base_reports.php index e9801a175..0fb9eddd0 100644 --- a/modules/reports/controllers/base_reports.php +++ b/modules/reports/controllers/base_reports.php @@ -51,7 +51,8 @@ protected function generate_toolbar() { $this->template->toolbar = new Toolbar_Controller('Report'); if($this->type != 'histogram') { - $pdf_button = form::open($this->type.'/generate', array('target'=>'_blank')); + $pdf_button = form::open($this->type.'/generate', array('target'=>'_blank') + ); $pdf_button .= $this->options->as_form(); $pdf_button .= ''; $pdf_button .= sprintf('', _('As PDF')); @@ -106,36 +107,24 @@ protected function generate_pdf() $month = $months[date('m')-1]; // January is [0] $filename = preg_replace("~\.pdf$~", null, $filename)."_".date("Y_").$month.date("_d").'.pdf'; - // Get Contents - $content = $this->template->content->render(); - - // Fix HTML Query - Ongoing - - // Use a regular expression to: - // match image tags - $img_pattern = '/]*src="([^"]+)"[^>]*>/'; - preg_match_all($img_pattern, $content, $img_matches); - - // Iterate through matched image tags - foreach ($img_matches[1] as $index=>$src) { - // Check if the image exists - if (file_exists($src)===false) - // Replace the image tag with a placeholder // Temporary - Ongoing - $content = str_replace($img_matches[0][$index],'[IMG]', $content); - } - - // match form tags - $form_pattern = '/]*>(.*?)<\/div>/s'; - preg_match_all($form_pattern, $content, $form_matches); - - // remove the hidden form - foreach ($form_matches[0] as $i=>$x) { - $content = str_replace($form_matches[0][$i], '', $content); + // GET contents from _POST + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + if (isset($_POST['content'])) { + // Retrieve the HTML content sent from JavaScript + $content = $_POST['htmlContent']; + } else { + // 'content' key is not set in the POST data + echo "Error: 'content' key not found in POST data"; + } + } else { + echo "Error!"; } - //prepare css file - Ongoing - Test - $prep_css = 'application/media/css/jquery.filterable.css'; - $contentwithcss = '' . $content; + //prepare css file - Ongoing : Still looking for styles for tables and graphs + $contentwithcss = '' . $content; //============================================================+ // START OF DOCUMENT @@ -149,16 +138,13 @@ protected function generate_pdf() $pdf->SetSubject($filename); // set margins - $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); + $pdf->SetMargins(10, 10, 10); // set auto page breaks - $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + $pdf->SetAutoPageBreak(TRUE, 10); // set image scale factor - $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); - - // set font - // $pdf->SetFont('opensans', 'R', 10); + $pdf->setImageScale(1.13); // add a page $pdf->AddPage(); @@ -167,8 +153,6 @@ protected function generate_pdf() // print HTMLstring $pdf->writeHTML($contentwithcss, false, false, false, false, 'UTF-8'); - - // $pdf->IncludeJS($content_script); //Close and output PDF document $pdf->Output($filename, 'I'); diff --git a/modules/reports/views/reports/index.php b/modules/reports/views/reports/index.php index 09842d0f5..43174e767 100644 --- a/modules/reports/views/reports/index.php +++ b/modules/reports/views/reports/index.php @@ -54,3 +54,33 @@ } ?> + From 29dff921f962ad7de15fc06a775660ac1ba91fd5 Mon Sep 17 00:00:00 2001 From: Eunice Remoquillo Date: Wed, 6 Mar 2024 11:06:58 +0800 Subject: [PATCH 4/9] Log encountered error This commit logs encountered error instead of displaying it. --- modules/reports/controllers/base_reports.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/reports/controllers/base_reports.php b/modules/reports/controllers/base_reports.php index 0fb9eddd0..8f8d67f49 100644 --- a/modules/reports/controllers/base_reports.php +++ b/modules/reports/controllers/base_reports.php @@ -112,12 +112,12 @@ protected function generate_pdf() if (isset($_POST['content'])) { // Retrieve the HTML content sent from JavaScript $content = $_POST['htmlContent']; + $this->log->log('debug', "HTML: $content"); } else { - // 'content' key is not set in the POST data - echo "Error: 'content' key not found in POST data"; + $this->log->log('debug', "Error: 'htmlContent' key not found in POST data"); } } else { - echo "Error!"; + $this->log->log('debug', "Error: No POST data found"); } //prepare css file - Ongoing : Still looking for styles for tables and graphs From 0ce245ce5946d603189c6e249dcb5b18354c241b Mon Sep 17 00:00:00 2001 From: Eunice Remoquillo Date: Wed, 6 Mar 2024 13:09:53 +0800 Subject: [PATCH 5/9] Added id and name reference for div Added id and name reference for div to be able to use identify html parts on scripts. --- modules/reports/views/reports/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/reports/views/reports/index.php b/modules/reports/views/reports/index.php index 43174e767..5167b7a34 100644 --- a/modules/reports/views/reports/index.php +++ b/modules/reports/views/reports/index.php @@ -1,5 +1,5 @@ -
+
Date: Wed, 6 Mar 2024 23:33:09 +0800 Subject: [PATCH 6/9] Use report js instead of script tags This commit captures the html strings using a function instead of script tags. --- modules/reports/controllers/base_reports.php | 8 ++---- modules/reports/src/js/reports.js | 30 ++++++++++++++++++++ modules/reports/views/reports/index.php | 30 -------------------- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/modules/reports/controllers/base_reports.php b/modules/reports/controllers/base_reports.php index 8f8d67f49..dcd3185ef 100644 --- a/modules/reports/controllers/base_reports.php +++ b/modules/reports/controllers/base_reports.php @@ -53,10 +53,8 @@ protected function generate_toolbar() { if($this->type != 'histogram') { $pdf_button = form::open($this->type.'/generate', array('target'=>'_blank') ); - $pdf_button .= $this->options->as_form(); - $pdf_button .= ''; - $pdf_button .= sprintf('', _('As PDF')); - $pdf_button .= ''; + $pdf_button = ''; + $pdf_button .= sprintf('', _('As PDF')); $this->template->toolbar->html_as_button($pdf_button); $csv_button = form::open($this->type.'/generate'); @@ -160,8 +158,6 @@ protected function generate_pdf() //============================================================+ // END OF FILE //============================================================+ - - // Create logs - Ongoing } /** diff --git a/modules/reports/src/js/reports.js b/modules/reports/src/js/reports.js index 8237f35a9..85e15da79 100644 --- a/modules/reports/src/js/reports.js +++ b/modules/reports/src/js/reports.js @@ -92,8 +92,38 @@ $(document).ready(function() { dataType: 'json' }); }); + + $("#generate_pdf_file").click(run_generation_pdf); + }); +function run_generation_pdf() +{ + var htmlString = document.getElementById('report-page').innerHTML; + + var parser = new DOMParser(); + var doc = parser.parseFromString(htmlString, 'text/html'); + // remove div that contains links + var divToRemove = doc.getElementById('report-links-internal'); + if (divToRemove) { + divToRemove.parentNode.removeChild(divToRemove); + } + var source = doc.documentElement.innerHTML; + + $.ajax({ + url: _site_domain + _index_page + '/base_reports/generate_pdf/', + type: 'post', + data: {content:source}, + success: function(response) { + console.log('Response from PHP Controller:', response); + }, + error: function(xhr, status, error) { + console.error('Error: ', error+' Status: '+status); + }, + dataType: 'json' + }); +} + // Propagate sla values function set_report_form_values(the_val) { diff --git a/modules/reports/views/reports/index.php b/modules/reports/views/reports/index.php index 5167b7a34..cca49c072 100644 --- a/modules/reports/views/reports/index.php +++ b/modules/reports/views/reports/index.php @@ -54,33 +54,3 @@ } ?>
- From 2caa85d7588a24fc8b40d5c25cc51b89deb34540 Mon Sep 17 00:00:00 2001 From: Eunice Remoquillo Date: Wed, 6 Mar 2024 23:46:12 +0800 Subject: [PATCH 7/9] Update base_reports.php --- modules/reports/controllers/base_reports.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/reports/controllers/base_reports.php b/modules/reports/controllers/base_reports.php index dcd3185ef..40c018d16 100644 --- a/modules/reports/controllers/base_reports.php +++ b/modules/reports/controllers/base_reports.php @@ -51,8 +51,7 @@ protected function generate_toolbar() { $this->template->toolbar = new Toolbar_Controller('Report'); if($this->type != 'histogram') { - $pdf_button = form::open($this->type.'/generate', array('target'=>'_blank') - ); + $pdf_button = form::open($this->type.'/generate', array('target'=>'_blank')); $pdf_button = ''; $pdf_button .= sprintf('', _('As PDF')); $this->template->toolbar->html_as_button($pdf_button); From 45751777e90f2eae8d3690e5dd07481426aa7a5b Mon Sep 17 00:00:00 2001 From: Eunice Remoquillo Date: Thu, 7 Mar 2024 12:44:14 +0800 Subject: [PATCH 8/9] Fix undefined htmlContent This commit sets the right variable name to be retrieved. --- modules/reports/controllers/base_reports.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/reports/controllers/base_reports.php b/modules/reports/controllers/base_reports.php index 40c018d16..e8dbafba1 100644 --- a/modules/reports/controllers/base_reports.php +++ b/modules/reports/controllers/base_reports.php @@ -107,8 +107,7 @@ protected function generate_pdf() // GET contents from _POST if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_POST['content'])) { - // Retrieve the HTML content sent from JavaScript - $content = $_POST['htmlContent']; + $content = $_POST['content']; $this->log->log('debug', "HTML: $content"); } else { $this->log->log('debug', "Error: 'htmlContent' key not found in POST data"); From c714f21763dce7eac0197eaba1480c1cb0d86dad Mon Sep 17 00:00:00 2001 From: Eunice Remoquillo Date: Thu, 14 Mar 2024 12:07:37 +0800 Subject: [PATCH 9/9] Moved ajax request to common.js --- modules/reports/controllers/base_reports.php | 2 +- modules/reports/src/js/common.js | 33 ++++++++++++++++++++ modules/reports/src/js/reports.js | 27 ---------------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/modules/reports/controllers/base_reports.php b/modules/reports/controllers/base_reports.php index e8dbafba1..e435b05f4 100644 --- a/modules/reports/controllers/base_reports.php +++ b/modules/reports/controllers/base_reports.php @@ -83,7 +83,7 @@ protected function generate_toolbar() { * * Assumes that $this->template is set up correctly */ - protected function generate_pdf() + public function generate_pdf() { // Require tcpdf require Kohana::find_file('vendor', 'tcpdf/tcpdf'); diff --git a/modules/reports/src/js/common.js b/modules/reports/src/js/common.js index 3d2811442..da452c6bf 100644 --- a/modules/reports/src/js/common.js +++ b/modules/reports/src/js/common.js @@ -444,3 +444,36 @@ function filter_mapping_mapping() if (!$(this).siblings('.configure_mapping').find('.filter_map:visible').length) $(this).siblings('.configure_mapping').hide(); } + +function run_generation_pdf() +{ + var htmlString = document.getElementById('report-page').innerHTML; + + var parser = new DOMParser(); + var doc = parser.parseFromString(htmlString, 'text/html'); + // remove div that contains links + var divToRemove = doc.getElementById('report-links-internal'); + if (divToRemove) { + divToRemove.parentNode.removeChild(divToRemove); + } + var source = doc.documentElement.innerHTML; + + $.ajax({ + url: _site_domain + _index_page + '/' + _controller_name + '/generatepdf', + type: 'post', + data: {content:source}, + success: function(response) { + console.log('Request Successful! :', response); + }, + error: function(xhr, status, error) { + var msg; + if (xhr.status === 403) { + msg ='You do not have permission to access this resource.'; + } else { + msg ='An error occurred. '+error; + } + $.notify("Failed to generate report: " + msg, {'sticky': true}); + }, + dataType: 'json' + }); +} diff --git a/modules/reports/src/js/reports.js b/modules/reports/src/js/reports.js index 85e15da79..92f9e61c0 100644 --- a/modules/reports/src/js/reports.js +++ b/modules/reports/src/js/reports.js @@ -97,33 +97,6 @@ $(document).ready(function() { }); -function run_generation_pdf() -{ - var htmlString = document.getElementById('report-page').innerHTML; - - var parser = new DOMParser(); - var doc = parser.parseFromString(htmlString, 'text/html'); - // remove div that contains links - var divToRemove = doc.getElementById('report-links-internal'); - if (divToRemove) { - divToRemove.parentNode.removeChild(divToRemove); - } - var source = doc.documentElement.innerHTML; - - $.ajax({ - url: _site_domain + _index_page + '/base_reports/generate_pdf/', - type: 'post', - data: {content:source}, - success: function(response) { - console.log('Response from PHP Controller:', response); - }, - error: function(xhr, status, error) { - console.error('Error: ', error+' Status: '+status); - }, - dataType: 'json' - }); -} - // Propagate sla values function set_report_form_values(the_val) {