Cells Being Cut From Right Side While Generating PDF Using PHPExcel TCPDF - php

I am Generating Reports using PHPExcel in CSV and PDF format.
CSV is being generate perfectly but PDF is behaving awkwardly.
Firstly Images are not being shown in PDF. Secondly cells are being cut from right side in PDF.
Here are the screenshots of both.
CSV:
PDF:
Here is the code
To Create PDF Write
$csv = new PHPExcel();
$rendererName = PHPExcel_Settings::PDF_RENDERER_TCPDF;
$rendererLibrary = 'tcpdf';
$rendererLibraryPath = _LIBRARIES_PATH_."/".$rendererLibrary;
PHPExcel_Settings::setPdfRenderer($rendererName,$rendererLibraryPath);
$csvWriter = PHPExcel_IOFactory::createWriter($csv, "PDF");
To Write Image
$objDrawing = new PHPExcel_Worksheet_Drawing();
$objDrawing->setName('Company LOGO');
$objDrawing->setDescription('Company LOGO');
$objDrawing->setPath($companyLogo);
$objDrawing->setWidthAndHeight(150,90);
$objDrawing->setResizeProportional(true);
$objDrawing->setCoordinates('E1');
$objDrawing->setWorksheet($csv->getActiveSheet());
To Write Values
$csv->getActiveSheet()->SetCellValue('A5', 'Sr.');
$csv->getActiveSheet()->SetCellValue('B5', 'User ID');
$csv->getActiveSheet()->SetCellValue('C5', 'Name');
$csv->getActiveSheet()->SetCellValue('D5', 'Total Hrs Worked');
$csv->getActiveSheet()->SetCellValue('E5', 'Total Break Duration');
$csv->getActiveSheet()->SetCellValue('F5', 'Rate/Hr');
$csv->getActiveSheet()->SetCellValue('G5', 'Total Cost');
To Save at the End
$csvWriter->save("php://output");

Related

Generate multiple pdf with Dompdf

I want to generate multiple PDFs in one foreach. When I run my Code, it also generates mulitple PDFs with the right name and saves it in the right folder. But the strange thing is, that only the first PDF that is generated has text in it and looks like I want it to be, and the others are all empty PDF-Files. Can someone explain, what I did wrong?
//here I get from my Database all bills, that are saved in my Database
$rgAll = $this->rechnungDatabase->getRGs();
foreach ($rgAll as $rgInfo){
$dompdf = new Dompdf();
$kundenid = $rgInfo->kundenid;
//here I get the User from my User Database
$userInfo = $this->indexDatabase->getUser($kundenid);
ob_start();
//this is a function to find my html site, the first two values are needed to find the file and the array gives the values, that are needed for the html site
$this->pageload("Rechnung", "kundenrechnung", [
'rgInfo' =>$rgInfo,
'userInfo' => $userInfo,
]);
$html = ob_get_contents();
ob_get_clean();
$dompdf->loadHtml($html);
// (Optional) Setup the paper size and orientation
$dompdf->setPaper('A4', 'portrait');
// Render the HTML as PDF
$dompdf->render();
//$dompdf->stream("Rechnung".$rgInfo->rgnummer, array("Attachment"=>1));
$output = $dompdf->output();
//the PDF is now in the right folder
$filepath= __DIR__."/../../PDFRechnung/Rechnung$rgInfo->rgnummer.pdf";
file_put_contents($filepath, $output);
unset($dompdf);
}
Thank you in advance for your kind help.

Image from database into PDF using FPDF

I have an image that is sent from an iPad app to an SQL database. I can retrieve this image and display in a web page using the following php:
$img = base64_encode($row['photoData']);
echo "<img src=\"data:image/jpg;charset=utf8;base64, $img\"/>";
This displays fine. What I want to do now is put this image into a PDF document using FPDF however I am struggling to do this.
This:
$img = base64_encode($row['photoData']);
$pdf->Image($img);
give this error:
FPDF error: Image file has no extension and no type was specified:
So I tried this (although I realise I will then have to look at how to get the size of the image sorted):
$pdf->Image($img, 20, 20, 20, 20 'JPG');
which give me:
FPDF error: Missing or incorrect image file:
What is the correct way to do this?
Or would it be easier to temporarily save the image to the server and then place the saved image into the PDFdoc?
As mentioned in the comments above this is possible by using a stream ("data url") to hand over the image data to the fpdf library without writing physical files to disk:
<?php
// load the 'fpdf' extension
require('fpdf.php');
// just for demonstration purpose, the OP gets the content from a database instead
$h_img = fopen('img.jpg', "rb");
$img = fread($h_img, filesize('img.jpg'));
fclose($h_img);
// prepare a base64 encoded "data url"
$pic = 'data://text/plain;base64,' . base64_encode($img);
// extract dimensions from image
$info = getimagesize($pic);
// create a simple pdf document to prove this is very well possible:
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello Image!');
$pdf->Image($pic, 10, 30, $info[0], $info[1], 'jpg');
$pdf->Output();
If this is a good advice is another question, this is merely meant to prove that this is possible...
According to the Docs FPDF::Image accepts a filename as the first argument, not a binary blob.
If you want to use FPDF specifically, save the image to a temporary file first, and then pass that to FPDF::Image.
To do that, something like this should work:
$tmpFile = tempnam(sys_get_temp_dir(), 'fpdfimg');
if (file_put_contents($tmpFile, $row['photoData'])) {
$fpdf->Image($tmpFile);
// save/display image
unlink($tmpFile);
}
Alternatively, if you want to just serve the image as a PDF (with no other content) you could use Imagick:
$im = new \Imagick();
$im->readImageBlob($row['photoData']);
$im->setImageFormat('pdf');
header('Content-Type: application/pdf');
echo $im;
Since FPDF cannot use base64 data to produce images on the PDF, I would recommend saving the file to the disk permanently as opposed to writing a temp file for every PDF operation.
This will save you a lot of I/O overhead.
Assuming your table has unique photo_id or photo_name to accompany photoData then you can use something like this to create your images and use them in FPDF.
I will also assume you have a last_update and photo_extension column.
<?php
$path = '/path/to/fpdf/images/';
$filename = $row['photo_id'].'.'.$row['photo_extension'];
$filepath = $path.$filename;
// If a physical file is not available then create it
// If the DB data is fresher than the file then make a new file
if(!is_file($filepath) || strtotime($row['last_update']) > filemtime($filepath))
{
$result = file_put_contents($filepath, $row['photoData']);
if($result === FALSE)
{
die(__FILE__.'<br>Error - Line #'.__LINE__.': Could not create '.$filepath);
}
}
$pdf->Image($filepath);
If you plan on updating the photoData which is stored in your DB then you will have to make sure to also have a timestamp column and compare that timestamp against the filemtime($filepath) of the image on your disk.
Another solution for this ;)
Make a new php by copying and pasting this (piece of fpdf's code edited):
require('fpdf.php');
class DATAIMAGE extends FPDF
{
protected function _parsedata($file)
{
// Extract info from a JPEG file
$a = getimagesizefromstring($file);
if(!$a)
$this->Error('Missing or incorrect image file: '.$file);
if($a[2]!=2)
$this->Error('Not a JPEG file: '.$file);
if(!isset($a['channels']) || $a['channels']==3)
$colspace = 'DeviceRGB';
elseif($a['channels']==4)
$colspace = 'DeviceCMYK';
else
$colspace = 'DeviceGray';
$bpc = isset($a['bits']) ? $a['bits'] : 8;
return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$file);
}
}
Then call this php instead of fpdf.php in your main php.
You'll now be able to display an image simply by adding 'data' to the end of the function:
$pdf->Image($mysqlrow["blob"],0,0,40,0,'data');

PHPExcel removes Data Validation Option of Excel sheet after editing existing Excel Sheet

I am using PHPExcel for editing existing excel sheets.
I had already set up a Data Validation method in my excel sheet as below.
When i edit this excel using PHPExcel, this Excel Specific Data Validation vanishes.
Can anyone help me to overcome this issue. I need to edit the excel without changing its functionality.
My PHP code:
//load existing template..
$objPHPExcel = PHPExcel_IOFactory::load('www/PHPExcelReader/Excel_Uploads/sample.xls');
// Set document properties
$objPHPExcel->getProperties()->setCreator("Logic Item")
->setLastModifiedBy("Logic")
->setTitle("List");
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('AZ1', $combination);
// Set active sheet index to the first sheet, so Excel opens this as the first sheet
$objPHPExcel->setActiveSheetIndex(0);
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$file_name='sample.xls';
$objWriter->save($file_name);
echo "Excel is ready to download now...";
From spreadsheet files that I've just created with data validation on cell A1 applying values from a list in $G1:$G4 and the following code:
$inputFileType = 'Excel5';
$inputFileName = './15datavalidationUnpopulated.xls';
$outputFileType = 'Excel5';
$outputFileName = './15datavalidationPopulated.xls';
$objPHPExcelReader = PHPExcel_IOFactory::createReader($inputFileType);
$objPHPExcel = $objPHPExcelReader->load($inputFileName);
$objPHPExcel->getActiveSheet()->setCellValue('G1', "India")
->setCellValue('G2', "America")
->setCellValue('G3', "China")
->setCellValue('G4', "Russia");
$objPHPExcelWriter = PHPExcel_IOFactory::createWriter($objPHPExcel,$outputFileType);
$objPHPExcel = $objPHPExcelWriter->save($outputFileName);
works with both .xls and .xlsx files, showing India, America, China and Russia in the data validation dropdown list for cell A1

How to load excel template and write to it in PHPExcel?

How do I load an Excel Template with PHPExcel and write to its cells and also insert images to cells dynamically?
You can read your excel template like this with PHPExcel:
$objPHPExcel = PHPExcel_IOFactory::load("./forms/english/cash.xlsx");
and you can write to cells like this:
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A2', "No")
->setCellValue('B2', "Name")
->setCellValue('C2', "Email")
->setCellValue('D2', "Phone")
->setCellValue('E2', "Address");
see the example, 30template.php in github site
https://github.com/PHPOffice/PHPExcel/blob/develop/Examples/30template.php
load template :
$objReader = PHPExcel_IOFactory::createReader('Excel5');
$objPHPExcel = $objReader->load("templates/30template.xls");
see in the example write via
$objPHPExcel->getActiveSheet()->setCellValue()
to add image use PHPExcel_Worksheet_Drawing :
// Add an image to the worksheet
$objDrawing = new PHPExcel_Worksheet_Drawing();
$objDrawing->setName('My Image');
$objDrawing->setDescription('The Image that I am inserting');
$objDrawing->setPath('./images/myImage.png');
$objDrawing->setCoordinates('B2');
$objDrawing->setWorksheet($objPHPExcel->getActiveSheet());
Now you don't need load templates. Try to use the PHP Excel templator:
https://github.com/alhimik1986/php-excel-templator

PHPExcel Mulitple excel file in one HTML page

I have 2 xls, i want to plot this information into one HTML Page.
Note: For assumption i mentioned as xls. actual xls positions are already in the database table. i will just render these position and plot into HTML Page.
include_once("Classes/PHPExcel/IOFactory.php");
// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
//first excel file
$objPHPExcel->getActiveSheet()
->setCellValue('c5','10');
$objPHPExcel->getActiveSheet()
->setCellValue('c6','20');
$objPHPExcel->getActiveSheet()
->setCellValue('c7','30');
$objPHPExcel->getActiveSheet()
->setCellValue('c8','40');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'HTML');
//second excel file
$objPHPExcel->getActiveSheet()
->setCellValue('c5','50');
$objPHPExcel->getActiveSheet()
->setCellValue('c6','60');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'HTML');
$objWriter->save('combinedexcelpage.html');
I'm not going to go through a long explanation of why this doesn't work, because it would take too long to explain; but there are a couple of solutions that you could take to achieve what you want:
Option #1
An Excel workbook comprises one or more worksheets, so you could create each "file" as a separate worksheet, rather than a separate file.
// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
// First excel worksheet, (created when you instantiate a new PHPExcel object)
$objPHPExcel->getActiveSheet()
->setCellValue('c5','10');
$objPHPExcel->getActiveSheet()
->setCellValue('c6','20');
$objPHPExcel->getActiveSheet()
->setCellValue('c7','30');
$objPHPExcel->getActiveSheet()
->setCellValue('c8','40');
// Second excel worksheet
// Add new sheet, which should also set it as the new "active" sheet
$objPHPExcel->createSheet()
$objPHPExcel->getActiveSheet()
->setCellValue('c5','50');
$objPHPExcel->getActiveSheet()
->setCellValue('c6','60');
By default, the HTML Writer will only write a single worksheet (the first), but you can set it to write all sheets:
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'HTML');
$objWriter->writeAllSheets();
$objWriter->save('combinedexcelpage.html');
Option #2
The HTML Writer save() method will always generate a file stream (whether a filesystem file or php://output), but rather than using save(), you can call individual methods in the class to generate a string containing the formatted worksheet data, and build your own output from those "blocks".
$data = '';
// First excel file
$objPHPExcel1 = new PHPExcel();
$objPHPExcel1->getActiveSheet()
->setCellValue('c5','10');
$objPHPExcel1->getActiveSheet()
->setCellValue('c6','20');
$objPHPExcel1->getActiveSheet()
->setCellValue('c7','30');
$objPHPExcel1->getActiveSheet()
->setCellValue('c8','40');
$objWriter1 = PHPExcel_IOFactory::createWriter($objPHPExcel, 'HTML');
$objWriter1->generateStyles(false);
$data .= $objWriter1->generateHTMLHeader();
$data .= $objWriter1->generateSheetData();
// Second excel file
$objPHPExcel2 = new PHPExcel();
$objPHPExcel2->getActiveSheet()
->setCellValue('c5','50');
$objPHPExcel2->getActiveSheet()
->setCellValue('c6','60');
$objWriter2 = PHPExcel_IOFactory::createWriter($objPHPExcel2, 'HTML');
$objWriter2->generateStyles(false);
$data .= $objWriter2->generateSheetData();
$data .= $objWriter2->generateHTMLFooter();
file_put_contents('combinedexcelpage.html', $data);
Both of these options are described in section 6.8 of the developer documentation

Categories