I need to copy the content of one sheet in an Excel Workbook to a sheet in a new excel workbook. The issue is, I have no idea what the sheets contain or their formatting. However, it will only be the first sheet every time.
I've tried an approach but I run out of memory every time. So I thought I'd do it row by row for 100 000 rows. Anyway, I started with a row, and it gets the data, but no luck in writing it to a new sheet. How would I do that?
Here is what I have so far:
// Open the current worksheet
App::import('Vendor', 'PHPExcel');
if (!class_exists('PHPExcel')) {
throw new CakeException('Vendor class PHPExcel not found!');
$this->xls = PHPExcel_IOFactory::load($path);
// Read all content
$this->xls->getActiveSheet()->rangeToArray('A1:ZZZZ1');
// Close current worksheet
$this->xls->disconnectWorksheets();
// Delete worksheet
unlink($destination);
// Open new worksheet
$this->xls = new PHPExcel();
$newWorksheet = new PHPExcel_Worksheet($this->xls, 'Sheet 1');
$this->xls->addSheet($newWorksheet);
$this->xls->setActiveSheetIndexByName('Sheet 1');
// Write all the content
$this->xls->getActiveSheet()->fromArray($array,null,'A1');
// Save current worksheet
$objWriter = PHPExcel_IOFactory::createWriter($this->xls, 'Excel2007');
$objWriter->save($destination);
What am I doing wrong?
Then also, is there an easier way to do this? I don't want to write all this code and in the end it's all reinventing the wheel?
Thanks in advance
There's a built-in method that's specifically written to do this for you:
$objPHPExcel1 = PHPExcel_IOFactory::load($path);
$objPHPExcel2 = new PHPExcel();
// Copy active worksheet from $objPHPExcel1 to $objPHPExcel2
$worksheet = $objPHPExcel1->getActiveSheet();
$objPHPExcel2->addExternalSheet($worksheet)
and if you're running out of memory, building large arrays in memory to try and copy manually isn't going to help.
There are approaches designed to reduce memory such as cell caching, look to use those to reduce memory usage
Related
I am working on a template excel file for some projects and my goal is to populate it with PHP. I create an excel document with two sheets, one is a table with all of the information that I am going to plot, and the second sheet is just a graph that is based on the table from the previous sheet.
Whenever I use (https://github.com/PHPOffice/PhpSpreadsheet) PHPSpreadsheet (since PHPExcel is deprecated) I am able to read/write/copy/etc the first sheet, but whenever I try to save the sheet without touching the graph sheet at all, nothing happens. I save the file successfully but when I try to open it I get an error stating that Excel found unreadable content in the file and to repair it. I repair it and the second sheet with the graph is empty.
https://github.com/PHPOffice/PhpSpreadsheet/issues/382
This is the closest thing I found to my issue, and I did add the setIncludeChart functions, but nothing seems to work.
I also feel that I have exhausted online searches and am now hoping that there is an alternative to PHPSpreadsheet that will allow me to use a chart in a template (supplied) excel file.
$xls = 'KPI_ReadinessTemplate.xls';
$xlsxTarget = 'NEWX_KPI_ReadinessTemplate.xlsx';
$xlsTarget = 'NEW_KPI_ReadinessTemplate.xls';
$inputFileType = 'Xlsx';
$inputFileName = $xlsx;
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
$reader->setIncludeCharts(true);
$spreadsheet = $reader->load($inputFileName);
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->getCell('A1')->setValue('Help me');
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->setIncludeCharts(true);
$fileData = $writer->save($xlsxTarget);
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$reader->setIncludeCharts(TRUE);
$workbook = $reader->load($xls);
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xls($workbook);
$writer->setIncludeCharts(TRUE);
$writer->save($xlsTarget);
I am expecting the chart to be copied, in the code from above there is no modification of the file, it should be an exact one-to-one copy of the supplied file but it isn't working at all as it seems the graph gets corrupted and I have to repair the excel the next time I open it.
EDIT: I also installed the archived PHPExcel and tried it using Graph disapear read and write excel file using PHPExcel and I still had the same issue.
I am creating an excel file with different sheets. The different sheets are created by iteration. But my iteration results in an extra sheet named worksheet. My code is:
$result = fetch results from database;
$count = COUNT($result);
foreach ( $result as $key=>$value){
$objPHPExcel->createSheet($key);
$objPHPExcel->getActiveSheet()
->setTitle($value['title']);
}
My database has got 3 results and it generates three worksheets along with a fourth one which is named as 'Worksheet'.
If I am using a checking condition with
if ($key > 0) {
execute above code
}
else {
$objPHPExcel->setActiveSheetIndex(0)->setTitle($value['title']);
}
it works fine. why is it so? Where is the mistake?
There is nothing wrong with your code. When you instantiate a new PHPExcel object using $objPHPExcel = new PHPExcel(), it is created with a single sheet called "worksheet"; delete that if you want to create only your own sheets
$objPHPExcel->removeSheetByIndex(0);
Mark Baker's accepted answer as always helped me but I want to expand and explain further on it.
I found that both $objPHPExcel = new PHPExcel() and $objPHPExcel->createSheet() create a single sheet called "worksheet". So use either one.
In the following sample which creates multiple sheets:
$objPHPExcel = new PHPExcel();
// First sheet
$objWorkSheet = $objPHPExcel->createSheet(); // NOT NEEDED
$objWorkSheet = $objPHPExcel->getActiveSheet();
// code for putting first sheet data
// Second sheet
$objWorkSheet = $objPHPExcel->createSheet();
// code for putting second sheet data
// Third, fourth sheets etc
createSheet() isn't needed for the first sheet where I've commented and it'll create that extra blank sheet. new PHPExcel() already made my first one me as he said.
So putting $objPHPExcel->removeSheetByIndex(0) at the end to remove it will work -- But just removing this unneeded line solves it the 'right' way and removes that redundancy. It seems like your code roughly does it like this.
I am trying to delete some worksheet from an Excel file (2007), i challenged to write on cells or get values from cell but i dont challenge to delete worksheet
I tried this code
$objPHPExcel = PHPExcel_IOFactory::load(PATH_FICHIER_TRAITES."CONCAT/Concat_".$file);
$nombreFeuille = $objPHPExcel->getSheetCount();
if($nombreFeuille>1){
for($i=1; $i<=$nombreFeuille; $i++){
$objPHPExcel->removeSheetByIndex($i);
}
}
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, "Excel2007");
$objWriter->save(PATH_FICHIER_TRAITES."CONCAT/Concat_".$file);
but my file remain the same after the execution
I would be thankful if u could offer me some help :)
As the worksheet index starts from 0 (not from 1), there is no sheet index that will equal the value of $nombreFeuille, so this code should be throwing and exception.
As you're not catching that exception anywhere in your code, it will never instantiate the writer, or save the file
I am using PHPExcel for editing a large XLSX file (~230kb, 20 sheets). They way I do it yet is:
load the file (create the PHPExcel object)
do the changes on the PHPExcel object
overwrite the XLSX file with a new one
This is very slow (~6 seconds), although there are only small changes (some cells in just one worksheet).
Is there a way to save just the changes in the file? Or if not, with another library?
You can try to do it with Spout: https://github.com/box/spout. It should not take more than a second and your code should look like this:
$reader = ReaderFactory::create(Type::XLSX);
$reader->open('path/to/file/to/read.xlsx');
$writer = WriterFactory::create(Type::XLSX);
$writer->openToFile('path/to/file/to/write.xlsx'); // needs to be different than the one read for now
while ($reader->hasNextSheet()) {
$reader->nextSheet();
while ($reader->hasNextRow()) {
$row = $reader->nextRow();
// change the row here if needed
$writer->addRow($row);
}
}
$reader->close();
$writer->close();
// And at the end, you can replace the old file with the new one:
rename('path/to/file/to/read.xlsx', 'path/to/file/to/write.xlsx');
Hope that helps!
I am having a .xlsx file. In the .xlsx file there are 4 sheets "activity",
"performance", "store", "display".
I want to load only one sheet in the memory at a time and after adding data to
report write it. my code is below
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$worksheet_names = $objReader->listWorksheetNames('/tmp/ac.xlsx');
$objReader->setLoadSheetsOnly('store');
$objPHPExcel = $objReader->load('/tmp/ac.xlsx');
$objPHPExcel->setActiveSheetIndexByName('store');
$sheet = $objPHPExcel->getActiveSheet();
$max_row = $sheet->getHighestRow();
$sheet->setCellValue("A$max_row", "Data");
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->setPreCalculateFormulas(false);
$objWriter->save('/tmp/ac.xlsx');
$objPHPExcel->disconnectWorksheets();
unset($objPHPExcel);
the problem is it is writing on store sheet and deleting all the other sheets.
How do i make remain all the sheets while updating 'store sheet'
is there any function which will write one sheet at a time while
retaining the other sheets.
Only what you have loaded into the PHPExcel object will be placed into your new file.
The createWriter isn't editing the file and retaining the sheets, it's just writing a fresh copy of what you pass in to the file name you give it. In this case, it will overwrite the file because it is the same file that you have just opened to read from. So, you must take some caution to grab the entire workbook first, then alter what you want (from the entire worksheet). After that, write everything to the file with the new changes.
The code below should help you out with retaining the other sheets. To edit only specific sheets just place the sheet names you want to edit in the $editable_worksheets array. I was very descriptive with the comments, so hopefully they will clarify step by step how this is done.
// Load your PHPExcel class
require_once 'classes/PHPExcel/Classes/PHPExcel.php';
// Set variables for file location and type to make code more portable and
// less memory intensive
$file = '/tmp/ac.xlsx';
$file_type = 'Excel2007';
// Open file for reading
$objReader = PHPExcel_IOFactory::createReader($file_type);
// Take all exisiting worksheets in open file and place their names into an array
$worksheet_names = $objReader->listWorksheetNames($file);
// Array of worksheet names that should be editable
$editable_worksheets = array('activity', 'store');
// You will need to load ALL worksheets if you intend on saving to the same
// file name, so we will pass setLoadSheetsOnly() the array of worksheet names
// we just created.
$objReader->setLoadSheetsOnly($worksheet_names);
// Load the file
$objPHPExcel = $objReader->load($file);
// Loop through each worksheet in $worksheet_names array
foreach($worksheet_names as $worksheet_name) {
// Only edit the worksheets with names we've allowed in
// the $editable_worksheets array
if(in_array($worksheet_name, $editable_worksheets)) {
// Take each sheet, one at a time, and set it as the active sheet
$objPHPExcel->setActiveSheetIndexByName($worksheet_name);
// Grab the sheet you just made active
$sheet = $objPHPExcel->getActiveSheet();
// Grab the highest row from the current active sheet
$max_row = $sheet->getHighestRow();
// Set the value of column "A" in the last row to the text "Data"
$sheet->setCellValue("A" . $max_row, "Data");
}
// Foreach loop will repeat until all sheets in the workbook have been looped
// through
}
// Unset variables to free up memory
unset($worksheet_names, $worksheet_name, $sheet, $max_row);
// Prepare to write a new file
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, $file_type);
// Tell excel not to precalculate any formulas
$objWriter->setPreCalculateFormulas(false);
// Save the file
$objWriter->save($file);
// This must be called before unsetting to prevent memory leaks
$objPHPExcel->disconnectWorksheets();
// Again, unset variables to free up memory
unset($file, $file_type, $objReader, $objPHPExcel);
You're loading only a single sheet, so the PHPExcel object in memory contains only that sheet. When you save, you're overwriting the exoisting file with the workbook in memory (not editing the original file). If you want to save with the same name, and retain all four worksheet; you need to lpoad all four worksheets.