PHP - multiple function return TCPDF variables - php

I have lot of code for creating pdf (TCPDF) separate by header, body, footer...
and I need to call the code as needed with variable coordinates. Because I need use if else calls are (of course) multiple and needlessly I rewrite the same code.
For example I try this (subheader):
class invoice {
function getSubheader($disY){
$subheader = array(
$pdf->SetLineWidth(.2),
$pdf->MultiCell(190,9,'',1,'L',false,0,10,$disY,true),
$pdf->SetFont('freesans','',7),
$pdf->MultiCell(50,"",$getDesc['blabla1'],0,'L',false,0,12,$disY+2,true),
$pdf->MultiCell(15,"",$getDesc['blabla2'],0,'R',false,0,62,$disY+2,true),
$pdf->MultiCell(20,"",$getDesc['blabla3'],0,'R',false,0,77,$disY+2,true),
$pdf->MultiCell(15,"",$getDesc['blabla4'],0,'R',false,0,97,$disY+2,true),
$pdf->MultiCell(25,"",$getDesc['blabla5'],0,'R',false,0,112,$disY+2,true),
$pdf->MultiCell(15,"",$getDesc['blabla6'],0,'R',false,0,137,$disY+2,true),
$pdf->MultiCell(20,"",$getDesc['blabla7'],0,'R',false,0,152,$disY+2,true),
$pdf->MultiCell(25,"",$getDesc['blabla8'],0,'R',false,0,172,$disY+2,true),
$pdf->SetFont('freesans','B',8),
$pdf->MultiCell(180,"",$getDesc['blabla9'],0,'L',false,0,12,$disY+11,true)
);
return $subheader;
}
others functions...
}
In another class call only a function
$pdf = new TCPDF (PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->AddPage();
lot of code $pdf->...
$invoice = new invoice();
if(cond == 1){
$disY = 100;
$invoice->getSubheader($disY);
} else {
$disY = 200;
$invoice->getSubheader($disY);
}
lot of code $pdf->...
This function must return variables $pdf->SetLineWidt... etc.
But if I use this solution - error
Call to a member function SetLineWidth() on null
Any advice for a newbie?

Related

PDF data displayed but file not downloaded

I want to preview and download an order invoice pdf using this code :
public function generatePDFByIdOrder()
{
$order = new Order(1); //I want to download the invoice PDF of $order_id '1'
if (!Validate::isLoadedObject($order)) {
throw new PrestaShopException('Can\'t load Order object');
}
$order_invoice_collection = $order->getInvoicesCollection();
$this->generatePDF($order_invoice_collection, PDF::TEMPLATE_DELIVERY_SLIP);
}
public function generatePDF($object, $template)
{
$pdf = new PDF($object, $template, Context::getContext()->smarty);
$pdf->render();
}
And calling it with the following code :
$order = new order();
echo $order->generatePDFByIdOrder();
I have the pdf's data printed on the browser console but not downloaded .
How can I manipulate that data to download a pdf file ?
PrestaShop use TCPDF.
Edit generatePDF in this way:
public function generatePDF($object, $template)
{
$pdf = new PDF($object, $template, Context::getContext()->smarty);
$pdf->Output('name.pdf', 'I');
}
I guess you only have to set the proper headers before rendering the PDF with TCPDF like so :
header("Content-type:application/pdf");
But "downloading" a PDF will depend on what the user's browser settings. It might download them (in which case you'd have to set another header called Content-Disposition:attachment) or display it inside the browser.
We recommend you, to create a separate controller to render the PDF file and to always open that controller in a new tab. It will help you to have separate logic using DOMPDF library.
Invoice controller will be as follows (invoice.php)
include_once(_PS_MODULE_DIR_.'supercehckout/libraries/dompdf/dompdf_config.inc.php');
class SuperCheckoutInvoiceModuleFrontController extends ModuleFrontController
{
public function initContent()
{
parent::initContent();
$this->generateInvoice(ORDER_ID);
}
}
Note: SuperCheckout is the example module name.
generateInvoice() function will be as follows:
function generateInvoice($order_id)
{
$dompdf = new DOMPDF();
$html = utf8_decode(INVOICE_HTML);
$dompdf->load_html(INVOICE_HTML);
$dompdf->render();
}

CakePhp 3.x, TCPDF, htmlspecialchars

I´ve installed the plugin "CakePDF" following the documentation: https://github.com/FriendsOfCake/CakePdf
Now I want to build the first PDF and I´ve got the following error:
This is my configuration in the bootstrap.php:
Configure::write('CakePdf', [
'engine' => 'CakePdf.Tcpdf',
'margin' => [
'bottom' => 15,
'left' => 50,
'right' => 30,
'top' => 45
],
'download' => true,
'encoding' => 'UTF-8'
]);
The only code I´ve written is the following one in the template:
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
This is the code from line 68 in functions.php:
function h($text, $double = true, $charset = null)
{
if (is_string($text)) {
//optimize for strings
} elseif (is_array($text)) {
$texts = [];
foreach ($text as $k => $t) {
$texts[$k] = h($t, $double, $charset);
}
return $texts;
} elseif (is_object($text)) {
if (method_exists($text, '__toString')) {
$text = (string)$text;
} else {
$text = '(object)' . get_class($text);
}
} elseif (is_bool($text)) {
return $text;
}
static $defaultCharset = false;
if ($defaultCharset === false) {
$defaultCharset = mb_internal_encoding();
if ($defaultCharset === null) {
$defaultCharset = 'UTF-8';
}
}
if (is_string($double)) {
$charset = $double;
}
return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, ($charset) ? $charset : $defaultCharset, $double);
}
I´m absolutely confused and can´t find any solution. Has anyone an idea?
After trying to find and debug the same error for over an hour, I just reset the value to UTF-8 after the usage of TCPDF - and everything works like before:
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
///...create, save, display your pdf
// Reset the encoding forced from tcpdf
mb_internal_encoding('UTF-8');
I also tried resetting it directly after the call of new TCPDF and everything was fine, too. I don't know what could go wrong with this reset :) My PDFs still look the same after this but emails get send again.
As you've figured, the problem is/was that the TCPDF class messes with mb_internal_encoding(), which is used in CakePHPs h() function to determine the apps default encoding, in case no explicit one is passed as an argument.
I'm no TCPDF expert, haven't used it in ages, but from a quick look at the current source, I'm having a hard time to understand why it fiddles with the internal encoding at all, since the only mb_* function the library uses, is mb_convert_encoding(), where both encoding arguments are passed, so the internal encoding isn't being used at all. That being said, I'd report this as a bug/issue to the TCPDF developer(s).
Anyways, you are only experiencing this problem because you are using CakePDF the wrong way. There is no need to manually create PDF engine instances, that's what CakePDF automatically does for you, which is pretty much the whole point of the plugin, it abstracts the PDF creation so that you just need to build the proper HTML in your view templates. That way you'll also avoid the encoding problems with TCPDF that you are currently experiencing, as the view template is being rendered before the PDF engine instance is being created.
tl;dr
Long story short, build only the HTML in your view template, and if you actually need to have access to a PDF engine instance because there's something you need to do that can only be achieved that way, then CakePDF is not the plugin you are looking for.
I think, I´ve found the culprit. The constructor method of TCPDF sets the mb_internal_encoding to ASCII. (tcpdf.php line 1838)
I found a hint in the comments: Please note that this method sets the mb_internal_encoding to ASCII, so if you are using the mbstring module functions with TCPDF you need to correctly set/unset the mb_internal_encoding when needed.
But now I need an advice how to use tcpdf and mb_internal_encoding correctly (without issues with cake or tcpdf).
Sorry for asking, I´m an absolutely beginner. ;)
put back de initial encoding, by extending the TCPDF class, and use the new class:
class TCPDF_repaired extends TCPDF{
public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false, $pdfa=false) {
parent::__construct($orientation, $unit, $format, $unicode, $encoding, $diskcache, $pdfa);
mb_internal_encoding($this->internal_encoding);
}
};

FPDI, FPDF SetAutoPageBreak add template to page after break

I've created a form that allows users to create a pdf that has an unlimited number of pages, I've got SetAutoPageBreak set so that it continues onto a second page however I cannot get the pages created after the page break to continue to use the original template file. The basic code can be seen below.
require('fpdf.php');
require('fpdi.php');
$pdf = new FPDI('P','mm','A4');
$pageCount = $pdf->setSourceFile("source_file.pdf");
$tplIdx = $pdf->importPage(1);
$pdf->AddPage();
$pdf->useTemplate($tplIdx);
$pdf->SetTextColor(63,76,89);
$pdf->SetMargins(5,39,5,20);
$pdf->SetAutoPageBreak(true,22); //page created doesn't have template attached
$pdf->SetDrawColor(225,225,225);
$pdf->SetFillColor(248,248,248);
$pdf->SetLineWidth(1);
$pdf->SetXY(82, 40);
$pdf->MultiCell(165,5,$company.$block,0,L,false);
$pdf->SetXY(19, 45);
$pdf->MultiCell(165,5,$date.$block,0,L,false);
$pdf->Output();
Having looked around, this question is the closest I can find however I'm not sure whether it is even relevant: FPDF/FPDI UseTemplate
Thanks
Just place the imported page in the Header method:
class PDF extends FPDI
{
protected $_tplIdx;
public function Header()
{
if (null === $this->_tplIdx) {
$this->_tplIdx = $this->importPage(1);
}
$this->useTemplate($this->_tplIdx);
}
}
$pdf = new PDF('P','mm','A4');
$pdf->AddPage();
...
...and everything should work as expected.
in addition to #JanSlabon`s answer: (i dont have the needed reputation to write a comment, so i´ll post this here, hope that´s ok)
If you only want to use a certain template for the first page and a different one for all other pages, you can do so as follows:
class PDF extends FPDI
{
protected $_tplIdx;
public function Header()
{
if (null === $this->_tplIdx) {
$this->setSourceFile('paper1.pdf');
$this->_tplIdx = $this->importPage(1);
} else {
$this->setSourceFile('paper2.pdf');
$this->_tplIdx = $this->importPage(1);
}
$this->useTemplate($this->_tplIdx);
}
}
i know its not exactly what #Searlee was looking for, but maybe it helps someone else.

Is there a way to hide header and footer in a pdf file created with FPDF in PHP?

I have created a pdf file with FPDF in PHP. When i insert the header and footers in it, they automatically gets displayed on all the pages of the pdf file. But i want to stop these header and footer from getting displayed on the first page and display them starting from the second page of the pdf file. I have searched the net but unable to find a solution.
In other words i want to dynamically create a cover page for the pdf report i have created with FPDF.
Can anybody give me some tips on how to perform this task of hidinh header and footer from the first page in pdf file!
Any help will be appreciated!
That's an easy task. Try the following:
class PDF extends FPDF {
...
function Header() {
if ( $this->PageNo() !== 1 ) {
// Add your stuff here
}
}
function Footer() {
if ( $this->PageNo() !== 1 ) {
// Add your stuff here
}
}
}
The problem is the Footers are created in Close() method at line 288 which is called from Output() at line 987 what means you're effectively turning the Footer off and then on just to display it anyways. What I would do if I needed the flexibility is something like:
class PDF extends FPDF {
function Header() {
if (!isset($this->header[$this->page]) || !$this->header[$this->page]) {
// ...
}
}
function Footer() {
if (!isset($this->footer[$this->page]) || !$this->footer[$this->page]) {
// ...
}
}
}
and then use it like:
$pdf->header[1] = false;
$pdf->footer[1] = false;
$pdf->AddPage();
$pdf->header[2] = true;
$pdf->footer[2] = true;
$pdf->AddPage();
It might be not the most elegant solution, but it works and it effectively allows you to change the visibility of the footers dynamically (p.s.: not specifying the state would also leave you with headers on effectively reducing the amount of code you need)
I'd like to add an answer for people coming here that don't want to skip the first, but the last (or any) page. Especially handy if you have dynamically changing text and cant foresee page numbers.
This can be done by setting a boolean while adding the page to the PDF.
Define your Header / Footer as
class PDF extends FPDF {
function Header() {
if (!$this->skipHeader) {
// ...
}
}
function Footer() {
if (!$this->skipFooter) {
// ...
}
}
}
Then, when initializing the pdf make sure to set these bools to false, so you will get headers/footers in general.
$pdf = new PDF();
$pdf->skipHeader = false;
$pdf->skipFooter = false;
Once you actually want to skip a Header or Footer, set the respective bool to true
$pdf->AddPage();
$pdf->skipHeader = true;
$pdf->AddPageContents();
Remember to set them back to false if you want headers/footers on the next page!
As an extension of what Paul's said, the footer is rendered after any content, so set skipFooter to true after rendering content.
$pdf->AddPage();
$pdf->skipHeader = true;
$pdf->AddPageContents();
$pdf->skipFooter = true;

Change top margin on second page with tcpdf AcceptPageBreak()

I am using TCPDF to generate PDFs. The PDF uses a PDF-template via the fpdi-class. Some of the generated PDFs are onepaged. But sometimes I have a second page. I use $pdf->MultiCell to output my content. The page-break works fine via $pdf->SetAutoPageBreak(true).
Now my problem: I need a different top-margin on the second page. What I tried so far is the use of the AcceptPageBreak()-function - unfortunaly with no success.
With the following code-snipped I managed to change the margin on the second page. But it adds one empty page at the end of the PDF.
public function AcceptPageBreak() {
$this->SetMargins(24, 65, 24, true);
$this->AddPage();
return false;
}
I tried to remove the last page with $pdf->deletePage but it does not work.
I tried to insert some conditions into the function:
public function AcceptPageBreak() {
if (1 == $this->PageNo()) {
$this->SetMargins(24, 65, 24, true);
$this->AddPage();
return false;
} else {
return false;
}
}
This works fine for PDFs with text for 2 pages. But now I get allways two paged PDFs - even if I have just a small text. It seems that the function "AcceptPageBreak()" is called every time the PDF is generated.
How can I prevent the empty page at the end of my PDF?
Using some of your code and the original function, I found out a way where it doesn't add an unneccessary blank page at the end of the file.
public function AcceptPageBreak() {
if (1 == $this->PageNo()) {
$this->SetMargins($left_margin, $top_margin, $right_margin, true);
}
if ($this->num_columns > 1) {
// multi column mode
if ($this->current_column < ($this->num_columns - 1)) {
// go to next column
$this->selectColumn($this->current_column + 1);
} elseif ($this->AutoPageBreak) {
// add a new page
$this->AddPage();
// set first column
$this->selectColumn(0);
}
// avoid page breaking from checkPageBreak()
return false;
}
return $this->AutoPageBreak;
}
I finally found a solution to my own question.
Maybe it's interesting for someone else with the same problem.
I took the function AcceptPageBreak() like posted above (Version 1). After saving the PDF I import the PDF into a new PDF without the last page and save the new PDF.
Here the code:
$pdf = new MYPDF();
$pdf->SetMargins(24, 54);
$pdf->AddPage();
...
$pdf->MultiCell('0', '', $text, '', 'L');
$pdf->lastPage();
$lastPage = $pdf->PageNo() + 1;
$pdf->Output($filePath, 'F');
// remove last page
$finalPdf = new FPDI();
$finalPdf->setSourceFile($filePath);
for ($i=1; $i < $lastPage; $i++) {
$finalPdf->AddPage();
$tplIdx = $finalPdf->importPage($i);
$finalPdf->useTemplate($tplIdx);
}
$finalPdf->Output($filePath, 'F');
Hope it helps.
TCPDF Automatic Page Breaks cause some inconsistency in rendering of content. Elements that may inadvertantly extend out of the boundaries of the page can cause additional pages to be generated. It is better to only autopage break when you are adding your content using:
$pdf->SetAutoPageBreak(true, $margin_bottom);
Then disable it when there it is not needed.
$pdf->SetAutoPageBreak(false);

Categories