Generate .xlsx file using fromArray for a big amount of data - php

I need to write in a .xlsx file about 111.100 rows, using fromArray() but I have a strange error
I use phpspreadsheet library
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$columnLetter = 'A';
foreach ($columnNames as $columnName) {
// Allow to access AA column if needed and more
$sheet->setCellValue($columnLetter.'1', $columnName);
$columnLetter++;
}
$i = 2; // Beginning row for active sheet
$columnLetter = 'A';
foreach ($columnValues as $columnValue) {
$sheet->fromArray(array_values($columnValue), NULL, $columnLetter.$i);
$i++;
$columnLetter++;
}
// Create your Office 2007 Excel (XLSX Format)
$writer = new Xlsx($spreadsheet);
// In this case, we want to write the file in the public directory
// e.g /var/www/project/public/my_first_excel_symfony4.xlsx
$excelFilepath = $directory . '/'.$filename.'.xlsx';
// Create the file
$writer->save($excelFilepath);
And I get the exception :
message: "Invalid cell coordinate AAAA18272"
#code: 0
#file: "./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Coordinate.php"
Can you help me please ?

Excel pages are limited. The limit is huge but still limited. This is a correct filter so you can't write if there is no space for it.
Anyway you shouldnt use excel pages for such a big amount of data, you can try fragmenting it into smaller pieces, but databases should be the way to manipulate such amount of information

Related

Phpspreadsheet Converted File should have additional new Column containing same value

Following is the code in which I am using the PhpSpreadsheet library to convert xlsx file to csv. I am trying to achieve the ability that the converted file should have one extra column called ClientID which should contain the same value for all the number of rows present in that file. Please let me know is it possible to do? Any help would be highly appreciated.
use \PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use \PhpOffice\PhpSpreadsheet\Writer\Csv;
$reader = new Xlsx();
$uploaded_xls_file = $_FILES['file']['tmp_name'];
$spreadsheet = $reader->load($uploaded_xls_file);
$loadedSheetNames = $spreadsheet->getSheetNames();
$writer = new Csv($spreadsheet);
foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) {
$writer->setSheetIndex($sheetIndex);
$writer->setPreCalculateFormulas(false);
$savingpath = $loadedSheetName.'.csv';
$writer->save($savingpath);
//$writer->save($loadedSheetName.'.csv');
}

Writing data read from Excel with Spout fails

I'm reading an excelsheet with Spout and directly writing this data to a sheet results in a error.
Trying to add a value with an unsupported type: object in vendor/box/spout/src/Spout/Writer/XLSX/Internal/Worksheet.php on line 231
Does anybody have the solution?
$reader = ReaderFactory::create(Type::XLSX);
$reader->open($sFileNameExcel);
$writer = WriterFactory::create(Type::XLSX);
$writer->openToFile($sWritePath.$sWriteFileName);
foreach ($reader->getSheetIterator() as $sheet)
{
if ($sheet->getName()=='mysheet')
{
foreach ($sheet->getRowIterator() as $row)
{
$writer->addRow($row);
}
}
}
$writer->close();
$reader->close();
My data consists of string, integer and double fields.
The sheet you're reading probably contains a date. The writer can't interpret dates though, hence the error.
Try configuring your reader this way: $reader->setShouldFormatDates(true); before calling open

php excel trying to add sheets with data dynamically in one workbook

I am trying to write the data to the multiple sheets in one excel file using phpExcel. I am getting data as array and i am looping it in that i am creating and writing the data .Problem is that it is creating the multiple sheets but it is writing all the data in one sheet. Below is my code:
function getcsv($data, $cirval, $opval)
{
global $objPHPExcel;
$myWorkSheet = new PHPExcel_Worksheet($objPHPExcel, $cirval);
$objPHPExcel->addSheet($myWorkSheet);
$objPHPExcel->setActiveSheetIndex(1);
$sheet = $objPHPExcel->getActiveSheet();
$sheet->setCellValue('A1', 'Denomination');
$sheet->setCellValue('B1', 'Validity');
$sheet->setCellValue('C1', 'Data Plan');
$rowcounter = 1;
foreach($data as $v1){
$rowcounter++;
$sheet->setCellValue('A' . $rowcounter, $v1['Denomination']);
$sheet->setCellValue('B' . $rowcounter, $v1['Validity']);
$sheet->setCellValue('C' . $rowcounter, $v1['Data Plan']);
}
}
Remove the line
$objPHPExcel->setActiveSheetIndex(1);
When you add a new worksheet using addSheet(), then PHPExcel automatically makes that the current active sheet.... you're explicitly overriding that behaviour and resetting the active sheet so that it is always sheet id #1, so it will always write everything to sheet id #1 no matter how many new sheets you add

is it possible to import and export excel file with size 70MB using PHPExcel library?

I have one excel file with 3 columns in which 2nd column contains email hyper-link. So I have to import this file and export it with only 2 columns first one should contains name and second one email means I have to split that hyper-link into name and email.
For 31MB file I changed memory limit to 2048MB and execution time 1200 in php.ini file. I can successfully imported and exported excel file of 31MB but while exporting 70MB file execution takes so much time and gives the following error message.
Fatal error: Allowed memory size of 2147483648 bytes exhausted (tried to allocate 15667514 bytes) in /var/www/html/PHPExcel/Reader/Excel2007.php on line 327
Is it possible to import and export excel file with size 70MB using PHPExcel library? And what I have to change like memory limit and max execution time etc in php.ini file.
require "PHPExcel.php";
require "PHPExcel/IOFactory.php";
$inputFileName = 'xxx.xlsx';
$inputFileType = PHPExcel_IOFactory::identify($inputFileName);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load($inputFileName);
$outputObj = new PHPExcel();
// Get worksheet dimensions
$sheet = $objPHPExcel->getSheet(0);
$highestRow = $sheet->getHighestRow();
$outputObj->setActiveSheetIndex(0);
$outSheet = $outputObj->getActiveSheet();
// Loop through each row of the worksheet in turn
for ($row = 2; $row <= $highestRow; $row++){ // As row 1 seems to be header
// Read cell B2, B3, etc.
$line = $sheet->getCell('B' . $row)->getValue();
preg_match("|([^\.]+)\ <([^>]+)>|", $line, $data);
if(!empty($data))
{
// $data[1] will be name & $data[2] will be email
$outSheet->setCellValue('A' . $row, $data[1]);
$outSheet->setCellValue('B' . $row, $data[2]);
}
}
$objWriter = new PHPExcel_Writer_CSV($outputObj);
$objWriter->save("xxx.csv");
NOTE: Can I export excel file without making any changes in php.ini file
I got solution. Successfully I have done this task in python. Hopefully it will help someone. :)
# Time taken 2min 4sec for 69.9MB file.
import csv
import re
from openpyxl import Workbook, load_workbook
location = 'big.xlsx'
wb = load_workbook(filename=location, read_only=True)
users_data = []
# pattern = '^(.+?) <([^>].+)>$' # matches "your name <email#email.com>"
# pattern_new = '^(.+?)<([^>].+)>$' # matches "your name<email#email.com>"
# pattern_email = '([\w.-]+#[\w.-]+)' # extracts email from sentence
# Define patterns to check on string.
patterns = ['^(.+?) <([^>].+)>$', '^(.+?)<([^>].+)>$']
# Loop through all sheets in XLSX
for wsheet in wb.get_sheet_names():
# Load data from Sheet.
ws = wb.get_sheet_by_name(wsheet)
# Loop through each row in current Sheet.
for row in ws.rows:
# We need column B data, so get that directly.
# Check if its not empty.
if row[1].value:
val = ""
# Get column B data, remove unnecessary data and encode using utf-8 format.
data = row[1].value.replace("(at)", "#").replace("(dot)", ".").encode('utf-8')
# Loop through all patterns to match in current data.
for pattern in patterns:
# Apply regex on data.
name_data = re.search(pattern, data)
# If match found.
if name_data:
# Create list of matched data and break loop to avoid extra searches on current row.
val = [name_data.group(1), name_data.group(2)]
# val = name_data.group()
break
# If no matches found, check for only email, if not then use data as it is.
if not val:
# val = data
name_data = re.search('([\w.-]+#[\w.-]+)', data)
# If match found, then use that, else use data.
if name_data:
val = [name_data.group(1)]
else:
val = data
# Append new data to users_data array.
users_data.append(val)
# Open CSV file for writting list.
myfile = open('big.csv', 'wb')
# Open file in write mode.
wr = csv.writer(myfile, dialect='excel', delimiter = ',', quotechar='"', quoting=csv.QUOTE_MINIMAL, lineterminator='\n')
# Loop through each value in list.
for word in users_data:
# Append data in CSV.
wr.writerow([word])
# Close CSV file.
myfile.close()
#Priyanka, you can also try using Spout: https://github.com/box/spout. It works great for large files! You won't have to change your php.ini file, as it won't require more than 10MB of memory and should finish before the default time limit.
You can do something like this:
$filePath = 'xxx.xlsx';
$reader = ReaderFactory::create(Type::XLSX);
$reader->open($filePath);
$writer = WriterFactory::create(Type::CSV);
$writer->openToFile($'xxx.csv');
$rowCount = 0;
while ($reader->hasNextSheet()) {
$reader->nextSheet();
while ($reader->hasNextRow()) {
$row = $reader->nextRow();
$rowCount++;
if ($rowCount === 1) {
continue; // that's for the header row
}
// get the values you need in the current row
// for example:
$name = $row[1];
$email = $row[2];
// write the data to the CSV file
$writer->addRow([$name, $email]);
}
}
$reader->close();
$writer->close();
Give it a try! Hopefully it will solve your problem :)
I don't see the point in loading one spreadsheet file, copying everything from that to a second, then saving the second.... that will be memory and performance intensive
why not just load the first, delete your heading row 1, then save to your CSV output
// Read the original spreadsheet
$inputFileName = 'TraiDBDump.xlsx';
$inputFileType = PHPExcel_IOFactory::identify($inputFileName);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load($inputFileName);
// Remove header row
$objPHPExcel->getSheet(0)->removeRow(1, 1);
// Save as a csv file
$objWriter = new PHPExcel_Writer_CSV($objPHPExcel);
$objWriter->save("TraiDBDump.csv");
If your original has a lot of columns, and you only need A and B, then you could use a read filter to read only those two columns

PHPexcel CSV master file

I would like to have multiple csv's and add them in a master csv file. It when I add an extra csv file in the array it throws a exception error.
Uncaught exception 'Exception' with message 'Workbook already contains a worksheet named 'Worksheet'. Rename the external sheet first.' in
Please find below my code
include'../Classes/PHPExcel.php';
include'../Classes/PHPExcel/IOFactory.php';
$filenames = array('Sheet1.csv','Sheet2.csv');
$bigExcel = new PHPExcel();
$bigExcel->removeSheetByIndex(0);
$reader = new PHPExcel_Reader_CSV();
foreach ($filenames as $filename) {
$excel = $reader->load($filename);
foreach ($excel->getAllSheets() as $sheet) {
$bigExcel->addExternalSheet($sheet);
}
foreach ($excel->getNamedRanges() as $namedRange) {
$bigExcel->addNamedRange($namedRange);
}
}
$writer = new PHPExcel_Writer_CSV($bigExcel);
$writer->save('2007-write.csv');
The problem is with the following code:
foreach ($excel->getAllSheets() as $sheet) {
$bigExcel->addExternalSheet($sheet);
}
For file 1 you add a sheet called worksheet, and then for file two you try to add a sheet with the same name.
I suggest you check if a sheetname has already been added, and if so you can use "setActiveSheetIndex" to switch to the existing sheet.
Another option is to change the name to worksheet(2) if you find one that already exists.
But since you called it CSV I dont think you can use worksheets. So in the end it should all just go in a single worksheet, so no need to keep adding new workheets. Just create one and add all the data to that one.

Categories