PHPExcel script taking long time for large database - php

This is the PHP code, I don't know much about PHPExcel to make it run faster, ideally I don't want to limit to 10000 rows (still takes at least 5 minutes before it sends the excel file)
Any ideas?
The script basically selects all data from the sqlite database then it loops the keys of the first row to add as titles for the columns.
Then it loops all rows and sets each cell value.
After this it adds the formula columns.
Then sends the excel data to the user.
The script is run at: http://example-site.org/getStatsExcel.php - so each time a user goes to that page, it runs this script - I think I should store the database per day and if it's already stored for that day, then just return the file, else generate the excel again...
<?php
date_default_timezone_set('Europe/Zurich');
require_once 'phpexcel/Classes/PHPExcel.php';
ini_set('max_execution_time', 900);
$dbname = 'admin';
$fullPath = sprintf('/var/www/fullpathtosqlite/%s.sqlite', $dbname);
$dbh = new PDO('sqlite:' . $fullPath);
$phpExcel = new PHPExcel();
$phpExcel->getProperties()->setTitle('Export : Statistics');
$phpExcel->getProperties()->setCreator('PHPExcel Stats Script');
$sheet = $phpExcel->getActiveSheet();
$sheet->setTitle('stats');
$phpExcel->setActiveSheetIndex(0);
$sql = 'SELECT * FROM (SELECT * FROM statistics ORDER BY timestamp DESC LIMIT 10000) ORDER BY timestamp ASC';
if(!$stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR, PDO::CURSOR_SCROLL))) {
die(var_export($dbh->errorinfo(), TRUE));
}
$stmt->execute();
// Fetch the first row
$row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT);
$results = array();
// Iterate over the results and print each one in a line
while ($row != false) {
$results[] = $row;
// Fetch the next line
$row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT);
}
$row = 1;
$col = 0;
foreach ($results[0] as $key => $value) {
$sheet->setCellValueByColumnAndRow($col, $row, $key);
$col++;
}
// date
$sheet->setCellValueByColumnAndRow($col, $row, 'date');
$col++;
// time
$sheet->setCellValueByColumnAndRow($col, $row, 'time');
$col++;
// full_date
$sheet->setCellValueByColumnAndRow($col, $row, 'full_date');
$row = 2;
foreach ($results as $result) {
$col = 0;
foreach ($result as $key => $value) {
$sheet->setCellValueByColumnAndRow($col, $row, $value);
$col++;
}
// date
$sheet->setCellValueByColumnAndRow($col, $row, '=DATE(LEFT(A' . $row . ',4),MID(A' . $row . ',5,2),MID(A' . $row . ',7,2))');
$col++;
// time
$sheet->setCellValueByColumnAndRow($col, $row, '=TIME(MID(A' . $row . ',9,2),MID(A' . $row . ',11,2),MID(A' . $row . ',13,2))');
$col++;
// full_date
$sheet->setCellValueByColumnAndRow($col, $row, '=F' . $row . '+G' . $row);
$row++;
}
$sheet->getStyle('F2:F' . $row)
->getNumberFormat()
->setFormatCode('dd/mm/yyyy');
$sheet->getStyle('G2:G' . $row)
->getNumberFormat()
->setFormatCode('h:mm AM/PM');
$sheet->getStyle('H2:H' . $row)
->getNumberFormat()
->setFormatCode('dd/mm/yyyy hh:mm');
foreach(range('A','H') as $columnID) {
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=\"statistics.xls\"");
header("Cache-Control: max-age=0");
$objWriter = PHPExcel_IOFactory::createWriter($phpExcel, "Excel5");
$objWriter->save("php://output");
exit;

The more data you're working with, the longer it will take. That's why we recommend that generating large spreadsheets should be farmed off to a back-end process so that it doesn't leave the user waiting while it builds the spreadsheet.
If you can build these large data spreadsheets "offline", then do so; if you can cache them, then do so.

Related

PHPExcel verify if cell has empy value

Hello i have an import of an xls file with multiple rows on it and i want to insert them into database only if the price columns has a value different than nothing else display an error msg. It works on half it only inserts those rows that have a value for price but instead returning the html error msg it returns the sql msg, that means it goes on the else branch.
Here is my code
$exceldata = array();
$uploadFilePath = 'uploads/'.basename($_FILES['doc']['name']);
move_uploaded_file($_FILES['doc']['tmp_name'], $uploadFilePath);
$inputfilename = 'uploads/'.$_FILES['doc']['name'].'';
// Read your Excel workbook
try
{
$inputfiletype = PHPExcel_IOFactory::identify($inputfilename);
$objReader = PHPExcel_IOFactory::createReader($inputfiletype);
$objPHPExcel = $objReader->load($inputfilename);
}
catch(Exception $e)
{
die('Error loading file "'.pathinfo($inputfilename,PATHINFO_BASENAME).'": '.$e->getMessage());
}
// Get worksheet dimensions
$sheet = $objPHPExcel->getSheet(0);
$highestRow = $sheet->getHighestRow();
$highestColumn = $sheet->getHighestColumn();
$header=$_POST['membership'];
if($header==1)
{
// Loop through each row of the worksheet in turn
for ($row = 1; $row <= $highestRow; $row++)
{
// Read a row of data into an array
$rowData = $sheet->rangeToArray('A' . $row . ':' . $highestColumn . $row, NULL, TRUE, FALSE);
if ($rowData[0][9]=='')
{
echo 'No price for the product '.$rowData[0][1].'';
}
else
{
$a = array('8', '1', '2', '3', '4', '5','6');
$b = array($rowData[0][0], $rowData[0][2], $rowData[0][3],$rowData[0][5],$rowData[0][6],$rowData[0][8],$rowData[0][8]);
$c = array_combine($a, $b);
$slug = str_replace(" ", "-",$rowData[0][1]);
$slug = str_replace('"', "",$slug);
$slug = str_replace('/', "-",$slug);
$stmt=$dbh->prepare("INSERT INTO tbl_products (name,slug,description,price)
VALUES (:name,:slug,:desc,:pret)");
$stmt->bindParam(":name",$rowData[0][1]);
$stmt->bindParam(":slug",$slug);
$stmt->bindParam(":desc",$rowData[0][10]);
$stmt->bindParam(":pret",$rowData[0][9]);
$stmt->execute();
$id_product=$dbh->lastInsertId();
$stmt=$dbh->prepare("INSERT INTO tbl_products_images_gallery (id_product,name,image,sort_order)
VALUES (:id,:name,:image,100)");
$stmt->bindParam(":id",$id_product);
$stmt->bindParam(":name",$rowData[0][4]);
$stmt->bindParam(":image",$slug);
$stmt->execute();
$stmt=$dbh->prepare("SELECT id_category from tbl_catalog_categories where name=:name");
$stmt->bindParam(":name",$rowData[0][2]);
$stmt->execute();
if($row=$stmt->fetch())
{
$id_cat=$row['id_category'];
}
$stmt=$dbh->prepare("INSERT INTO tbl_products_to_categories (id_category,id_product)
VALUES (:id_cat,:id_prod)");
$stmt->bindParam(":id_cat",$id_cat);
$stmt->bindParam(":id_prod",$id_product);
$stmt->execute();
foreach($c as $key => $value)
{
$stmt=$dbh->prepare("INSERT INTO tbl_products_attributes_values (id_product,id_attribute,attribute_value)
VALUES (:id_product,:id_attribute,:value)");
$stmt->bindParam(":id_product",$id_product);
$stmt->bindParam(":id_attribute",$key);
$stmt->bindParam(":value",$value);
$stmt->execute();
}
}
}
}
if (empty($rowData[0][9])) perhaps?
Or test for null as well as for empty strings - nulls are perfectly valid response from PHPExcel...
especially as
$rowData = $sheet->rangeToArray('A' . $row . ':' . $highestColumn . $row, NULL, TRUE, FALSE);
with it's null second argument is telling PHPExcel to return a null value if the cell simply doesn't exist in the spreadsheet
Though you can change the rangeToArray() call to
$rowData = $sheet->rangeToArray('A' . $row . ':' . $highestColumn . $row, '', TRUE, FALSE);
to return an empty string instead of a null if the cell doesn't exist

How to check if column headers are correct in PHPExcel?

I'm using the column header as an array index (row 1), and I don't want to have problems when they start uploading their XLSX file with incorrect column headers (or sometimes missing).
I found this answer really useful. I can make my array indexes as column headers:
for ($row = 2; $row <= $highestRow; $row++){
// Read a row of data into an array
$rowData = $sheet->rangeToArray('A' . $row . ':' . $highestColumn . $row,
NULL,
TRUE,
FALSE);
$rowData[0] = array_combine($headings[0], $rowData[0]);
}
The code above is from https://stackoverflow.com/a/32526911/8191721
Here's what I want to happen:
Check first the column headers if they matches with the column
headers I provided (in array, so I can use in_array in a loop) before
writing it to the database.
If the headers are correct, I will now turn the array indexes to column headers (so instead of [0], it should now return [firstname]) or else throw an error message.
Write to database where the column names in my database exactly matches the column header names (or if not, at least matches the query) in their XLSX file. (I called them "column mapping").
Long story short, here's my code:
try {
$inputFileName = $_FILES['file']['tmp_name'];
$inputFileType = PHPExcel_IOFactory::identify($inputFileName);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objPHPExcel = $objReader->load($inputFileName);
//-- Get worksheet dimensions
$sheet = $objPHPExcel->getSheet(0);
$highestRow = $sheet->getHighestRow();
$highestColumn = $sheet->getHighestColumn();
$headings = $sheet->rangeToArray('A1:'.$highestColumn.'1', NULL, TRUE, FALSE);
//-- $row = 2 <- skip row 1 since this is our headers
for($row = 2; $row <= $highestRow; $row++) {
//-- Read a row of data into an array
$xlsxRow = $sheet->rangeToArray('A' . $row . ':' . $highestColumn . $row, NULL, TRUE, FALSE);
//-- Combine to replace indexes with header names
$xlsxRow[0] = array_combine($headings[0], $xlsxRow[0]);
//-- Got stucked in here..
/*
If column header fails, should exit the loop
*/
//-- SQL query follows here..
}
So can someone help me figuring this out?
To compare the header value you can use array_diff() function.
If you want to give more flexibility to user then you can use following example.
In this case use
$excelSheetHeaders = array();
for ($i = 1; $i <= 1; $i++) {
$rowData = $sheet->rangeToArray('A' . $i . ':' . $highestColumn . $i, NULL, TRUE, FALSE);
$excelSheetHeaders = $rowData[0];
$excelSheetHeaders = array_map('strtolower', $excelSheetHeaders);
$errorCount = 0;
foreach ($headerArray as $index => $value){
if(!in_array(strtolower($value), $excelSheetHeaders)){
$errorCount++;
}
}
if($errorCount > 0){
//Throw Error and exit;
}
}
for ($i = 2; $i <= $highestRow; $i++){
$rowData = $sheet->rangeToArray('A' . $i . ':' . $highestColumn . $i,NULL,TRUE,FALSE);
$spreadsheetData = array();
foreach($headerArray as $index => $value){
$spreadsheetData[$value] = $rowData[0][array_search(strtolower($value),$excelSheetHeaders)];
}
var_dump($spreadsheetData);
}
This error is exactly what you want. Now you can access $spreadsheetData['firstName'].

PHPExcel multiple foreach loops

I want to display all the rows from a table with the corresponding column names above, which works. The problem is that it removes the first row from the results below the column names. It's as if the column row is somehow counted as a row in the while loop that displays the results, but I can't figure it out.
If I remove the column names code shown below all of the results are shown.
//COLUMN NAMES
foreach($headings as $heading) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$heading);
$col++;
}
All of the code shown below.
$query = "SELECT * FROM `" . $_SESSION['sess_table'] . "` ORDER by ID ASC";
if ($result = $mysqli->query($query)) {
$objPHPExcel = new PHPExcel();
$objPHPExcel->getActiveSheet()->setTitle($excelTitle);
$headingsrow = $result->fetch_assoc();
$headings = array_keys($headingsrow);
//COLUMN NAMES
$rowNumber = 1;
$col = 'A';
foreach($headings as $heading) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$heading);
$col++;
}
//RESULTS
$rowNumber = 3;
while ($row = $result->fetch_row()) {
$col = 'A';
foreach($row as $key => $cell) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$cell);
$col++;
}
$rowNumber++;
}
$objPHPExcel->getActiveSheet()->freezePane('A2');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $excelFilename . '.xls"');
header('Cache-Control: max-age=0');
$objWriter->save('php://output');
exit();
}
In your code,
$rowNumber = 1;
$col = 'A';
foreach($headings as $heading) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$heading);
$col++;
}
you have increased the $col value instead of increasing $rowNumber value.
try this,
$rowNumber = 1;
$col = 'A';
foreach($headings as $heading) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$heading);
$rowNumber++;
}
You're fetching the first row to retrieve your headings, but then discarding it even though it contains data that you want to write as well
if ($result = $mysqli->query($query)) {
$objPHPExcel = new PHPExcel();
$objPHPExcel->getActiveSheet()->setTitle($excelTitle);
$row = $result->fetch_assoc();
$headings = array_keys($row);
//COLUMN NAMES
$rowNumber = 1;
$col = 'A';
foreach($headings as $heading) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$heading);
$col++;
}
//RESULTS
$rowNumber = 3;
do {
$col = 'A';
foreach($row as $key => $cell) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$cell);
$col++;
}
$rowNumber++;
} while ($row = $result->fetch_row());
}

PHPExcel additional text add to column

I have PHPExcel plugin to generated excel which data came from database, how if I wanted to add in additional text into a column A during the loop, and column B remain untouched data as from DB?
For example column A in DB is
alex
andy
jennifer
when output to excel, I wanted to add #domain.com for each name behind, wich will become
alex#domain.com
andy#domain.com
jennifer#domain.com
Code:
$query = "SELECT mail_name, account_id FROM email ORDER BY mail_name ASC";
$headings = array('Email', 'Id');
if ($result = mysql_query($query) or die(mysql_error())) {
// Create a new PHPExcel object
$objPHPExcel = new PHPExcel();
$objPHPExcel->getActiveSheet()->setTitle('emailList');
$rowNumber = 1;
$col = 'A';
foreach($headings as $heading) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$heading);
$col++;
}
// Loop through the result set
$rowNumber = 1;
while ($row = mysql_fetch_row($result)) {
$col = 'A';
foreach($row as $cell) {
$objPHPExcel->getActiveSheet()->setCellValue($col.$rowNumber,$cell);
$col++;
}
$rowNumber++;
}
Keep in mind that $col++ is not going to work.
What about this way?:
// Loop through the result set
$rowNumber = 1;
while ($row = mysql_fetch_row($result)) {
$objPHPExcel->getActiveSheet()
->setCellValue('A'.$rowNumber,$row['mail_name'].'#domain.com');
$objPHPExcel->getActiveSheet()
->setCellValue('B'.$rowNumber,$row['account_id']);
++$rowNumber;
}

PHPExcel : Image is not inserting in excel file

This is my code,
Please tell me what am I missing?
// Field names in the first row
$sql1 = "SELECT `COLUMN_NAME`
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`='test'
AND `TABLE_NAME`='user_tab'";
$res1 = mysql_query($sql1);
while ($row2 = mysql_fetch_assoc($res1)) {
$fields[] = $row2['COLUMN_NAME'];
}
//Data
$sql = "SELECT * FROM user_tab";
$res = mysql_query($sql);
echo date('H:i:s'), " Load from Excel5 template", EOL;
$objReader = PHPExcel_IOFactory::createReader('Excel5');
$objPHPExcel = $objReader->load("mytest.xls");
$logo = new PHPExcel_Worksheet_HeaderFooterDrawing();
$logo->setName('Logo');
$logo->setPath('image.jpg'); //Path is OK & tested under PHP
$logo->setHeight(38); //If image is larger/smaller than that, image will be proportionally resized
$objPHPExcel->getActiveSheet()->getHeaderFooter()->addImage($logo, PHPExcel_Worksheet_HeaderFooter::IMAGE_HEADER_LEFT);
echo date('H:i:s'), " Add new data to the template", EOL;
$col = 0;
foreach ($fields as $key => $value) {
$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($col, 1, $value);
$col++;
}
$row = 2;
while ($row_data = mysql_fetch_assoc($res)) {
$col = 0;
foreach ($row_data as $key => $value) {
$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($col, $row, $value);
$col++;
}
$row++;
}
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save(str_replace('.php', '.xls', __FILE__));

Categories