How to remove all merged cells from an Excel file in php? - php

I have a Excel file like this:
I wrote a code that allows me to extract all the photos from the xlsx file and insert them in a folder.
There are several merged cells in the file and before processing I would like to remove all the merged cells from the Excel file. I tried with $objPHPExcel->setActiveSheetIndex("0")->unmergeCells(); but it doesn't work.
How can I solve my problem?
<?php
//uploaded xlsx file recovery
$xlsx="C:/wamp64/www/Extract_pictures_Excel/xlsx_files/".date('Y_m_d H-i-s')."_file.xlsx";
move_uploaded_file($_FILES["mon_fichier"]["tmp_name"],$xlsx);
require_once 'PHPExcel/Classes/PHPExcel/IOFactory.php';
$objPHPExcel = PHPExcel_IOFactory::load($xlsx);
//Unique name folder for the pictures
$dirname = uniqid();
mkdir("C:/wamp64/www/Extract_pictures_Excel/pictures_folders/$dirname/");
$sheet = $objPHPExcel->getActiveSheet();
//Unmerge all cells
foreach($sheet->getMergeCells() as $cells)
{
$sheet->unmergeCells($cells);
// var_dump($cells);
}
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$objWriter->save('./unmerged_files/unmerged.xlsx');
//reading the xlsx file
foreach ($sheet->getDrawingCollection() as $drawing ) {
if ($drawing instanceof PHPExcel_Worksheet_MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG :
$extension = 'png'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg'; break;
}
} else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
$chemin = "C:/wamp64/www/Extract_pictures_Excel/pictures_folders/$dirname/";
}
//retrieving cell values for the images name
$row = (int) substr($drawing->getCoordinates(), 1);
//Condition to read merged cell
$stylecode = $sheet->getCell('H'.$row)->getValue();
$colorcode = $sheet->getCell('E'.$row)->getValue();
$finalname = $stylecode.'_'.$colorcode;
$myFileName = $chemin.$finalname.'.'.$extension;
file_put_contents($myFileName, $imageContents);
}
?>

I have changed the library to PhpOffice\PhpSpreadsheet because PHPExcel is outdated.
require_once './vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$xlsx = './test/catalogmtnwr2021202009210323241.xlsx';
$spreadsheet = IOFactory::load($xlsx);
$sheet = $spreadsheet->getActiveSheet();
Now I am testing what is merged and unmerge it
echo 'before unmerge: ', count($sheet->getMergeCells()), PHP_EOL;
foreach($sheet->getMergeCells() as $cells)
$sheet->unmergeCells($cells);
echo 'after unmerge: ', count($sheet->getMergeCells()), PHP_EOL;
before unmerge: 678
after unmerge: 0
And at last write back into file
$writer = new Xlsx($spreadsheet);
$writer->save('./test/unmerged.xlsx');
This unmerged the cells as expected

Related

Extract images or charts from XLSX with PHP?

I have been trying to extract images and charts from an Xlsx file using the phpspreadsheet libray; I have however been unsuccessful.
Indeed, the piece of code I wrote is unable to find any image or chart from my xlsx file.
However, when I convert the file from Xlsx to Xls using Excel, the same code works and manages to extract images and charts.
This is the code i use to load my spreadsheet :
$fileType = \PhpOffice\PhpSpreadsheet\IOFactory::identify($filePath);
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($fileType);
$spreadsheet = $reader->load($filePath);
And then I added the code provided by the official documentation :
$i = 0;
foreach ($spreadsheet->getActiveSheet()->getDrawingCollection() as $drawing) {
if ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_PNG :
$extension = 'png';
break;
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif';
break;
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg';
break;
}
} else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
}
$myFileName = '00_Image_'.++$i.'.'.$extension;
file_put_contents($myFileName,$imageContents);
}
The above code works with an .xls file but not with an .xlsx : the getDrawingCollection and/or getChartCollection return an empty array with .xlsx files...
Do any of you guys know how to perform this?
I'm open to any solution... even if it means converting the file via another library...
Thanks in advance,
I found the solution... one line of code, to add after initializing the reader :
$reader->setIncludeCharts(true);

How to read a excel file with merged cells in php?

I wrote a php script that allows me to read an uploaded excel file and insert all the images contained in a folder by renaming them with the cell values "style" and "color" to have style_color.jpg. The script works fine but if I upload an xlsx file containing merged cells like this:
images with the same "style" doesn't work.The tool will just put the style on the first image. I would like the first two images to be called :
SCJEG4_1041
SCJEG4_0049
How can I read these merged cells?
<?php
//uploaded xlsx file recovery
$xlsx="C:/wamp64/www/Extract_pictures_Excel/xlsx_files/".date('Y_m_d H-i-s')."_images.xlsx";
move_uploaded_file($_FILES["mon_fichier"]["tmp_name"],$xlsx);
require_once 'PHPExcel/Classes/PHPExcel/IOFactory.php';
$objPHPExcel = PHPExcel_IOFactory::load($xlsx);
//Unique name folder for the pictures
$dirname = uniqid();
mkdir("C:/wamp64/www/Extract_pictures_Excel/pictures_folders/$dirname/");
//reading the xlsx file
$sheet = $objPHPExcel->getActiveSheet();
foreach ($sheet->getDrawingCollection() as $drawing ) {
if ($drawing instanceof PHPExcel_Worksheet_MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG :
$extension = 'png'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg'; break;
}
} else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
$chemin = "C:/wamp64/www/Extract_pictures_Excel/pictures_folders/$dirname/";
}
//retrieving cell values for the images name
$row = (int) substr($drawing->getCoordinates(), 1);
$stylecode = $sheet->getCell('H'.$row)->getValue();
$colorcode = $sheet->getCell('E'.$row)->getValue();
$finalname = $stylecode.'_'.$colorcode;
$myFileName = $chemin.$finalname.'.'.$extension;
file_put_contents($myFileName, $imageContents);
}
?>
If you can assume that you read the rows in sequence, you can get the cell value and if the cell is blank, use the previous value. This code use ?: to say if it's blank, use $stylecode ...
$stylecode = $sheet->getCell('H'.$row)->getValue() ?: $stylecode;

Load graphics with phpSpreedSheet

I am using PhpSpreedSheet to load an excel, update it and save it again ... The problem I find is that it does not save it well for the graphics, and when you open the excel it tells you the typical thing that there has been a problem and "Do you want that we try to recover as much content as possible? " and remove the graphics.
Excel has completed validation and repair at the file level. Some parts of this book may have been repaired or discarded. Part removed: Part Properties of the document. (Drawing form) Part removed: Drawing form. Removed part: Drawing form.
$reader = IOFactory::createReader('Xlsx');
$reader->setIncludeCharts(true);
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($this->spreadsheet);
$writer->setIncludeCharts(true);
To include a drawing you should use something like this:
$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$drawing->setName('Logo');
$drawing->setDescription('Logo');
$drawing->setPath('./images/officelogo.jpg');
$drawing->setCoordinates('B15');
$drawing->setHeight(36);
$drawing->setWorksheet($spreadsheet->getActiveSheet());
For reading out of all images you should use the code from the documentation:
$i = 0;
foreach ($spreadsheet->getActiveSheet()->getDrawingCollection() as $drawing) {
if ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_PNG :
$extension = 'png';
break;
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif';
break;
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg';
break;
}
} else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
}
$myFileName = '00_Image_'.++$i.'.'.$extension;
file_put_contents($myFileName,$imageContents);
}

Update .xlsx file

I am using PHPExcel_1.8.0.
I have many input files and I want to read each file and to save them run time into a single output file.
I have tried but the output file is overwriting for each file.
Let me explain in brief:
I have 5 files having records of 5 different employees and I want to put these records in a single file through php. I have set a loop, so the output file is saving only the last employee record due to overwriting.
I want something like append in php.
Here is my code:
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
define('EOL', (PHP_SAPI == 'cli') ? PHP_EOL : '<br />');
date_default_timezone_set('Europe/London');
require_once 'index.php';
require_once dirname(__FILE__) . '/Classes/PHPExcel.php';
$dirlist = dirToArray('input');
foreach ($dirlist AS $value) {
$info = new SplFileInfo($value);
$vFileExtension = $info->getExtension();
if ($vFileExtension == 'xlsx' || $vFileExtension == 'xls') {
$inputFileName = "input/".$value;
$objReader = new PHPExcel_Reader_Excel5();
$objPHPExcel = $objReader->load($inputFileName);
$sheetData = $objPHPExcel->getActiveSheet()->toArray(null, true, true, true);
$objPHPExcel = new PHPExcel();
$i = 1;
foreach ($sheetData AS $key => $row) {
foreach ($row AS $index => $rec) {
$objPHPExcel->getActiveSheet()->setCellValue($index . $i, $newtext);
}
$i++;
}
$objDrawing = new PHPExcel_Worksheet_HeaderFooterDrawing();
$objDrawing->setName('PHPExcel logo');
$objDrawing->setPath('./images/phpexcel_logo.gif');
$objDrawing->setHeight(36);
$objPHPExcel->getActiveSheet()->getHeaderFooter()->addImage($objDrawing, PHPExcel_Worksheet_HeaderFooter::IMAGE_HEADER_LEFT);
$objPHPExcel->getActiveSheet()->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE);
$objPHPExcel->getActiveSheet()->getPageSetup()->setPaperSize(PHPExcel_Worksheet_PageSetup::PAPERSIZE_A4);
$objPHPExcel->getActiveSheet()->setTitle('Data');
$objPHPExcel->setActiveSheetIndex(0);
$callStartTime = microtime(true);
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save("output/result.xlsx");
$callEndTime = microtime(true);
$callTime = $callEndTime - $callStartTime;
$callStartTime = microtime(true);
echo $value . ' has been generated!' . EOL;
}
}
?>

PHPExcel input has 2 sheets, output only has 1 of them saved

I am having admins update a website by uploading .xlsx .xls or .csv files into an HTML form. The issue is that the second worksheet, NORTH, isn't being saved into the server with the first worksheet, SOUTH.
My Code:
<?php
require('./Classes/PHPExcel/IOFactory.php');
ini_set('max_execution_time', 800);
ini_set('memory_limit', 200M);
$inputFileType = 'Excel2007';
$inputFileName = $_FILES['uploaded']['tmp_name'];
class MyReadFilter implements PHPExcel_Reader_IReadFilter {
public function __construct($fromColumn, $toColumn) {
$this->columns = array();
$toColumn++;
while ($fromColumn !== $toColumn) {
$this->columns[] = $fromColumn++;
}
}
public function readCell($column, $row, $worksheetName = '') {
// Read columns from 'A' to 'AF'
if (in_array($column, $this->columns)) {
return true;
}
return false;
}
}
$filterSubset = new MyReadFilter('A', 'AF');
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objReader->setReadFilter($filterSubset);
$objReader->setLoadSheetsOnly( array("SOUTH", "NORTH") );
$objPHPExcelReader = $objReader->load($inputFileName);
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcelReader, 'CSV');
$objWriter->save('abc.csv');
$files = fopen('abc.csv', 'r');
while (($line = fgetcsv($files)) !== FALSE) {
$csv_array[] = array_combine(range(1, count($line)), array_values($line));
}
?>
What have I done wrong that won't allow my code to save both worksheets? TIA!
A CSV file can only hold a single worksheet, so you need to save each worksheet to a separate file
$objReader->setLoadSheetsOnly( array("SOUTH", "NORTH") );
$objPHPExcelReader = $objReader->load($inputFileName);
for ($ws = 0; $ws < $objPHPExcelReader->getSheetCount(); $ws++) {
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcelReader, 'CSV');
$objWriter->setSheetIndex($ws);
$objWriter->save('abc' .$ws. '.csv');
}

Categories