PHPExcel. How to check if current cell is merged with another? - php

I use PHPExcel to import Excel files to my site. For example, there is two cells, A1 and A2, both merged. Is there a way to to find out is A1 merged to another cell (A2 or other) or not?

$workbook = new PHPExcel;
$sheet = $workbook->getActiveSheet();
$sheet->mergeCells('A1:E1');
$cell = $sheet->getCell('A1');
// Check if cell is merged
foreach ($sheet->getMergeCells() as $cells) {
if ($cell->isInRange($cells)) {
echo 'Cell is merged!'
break;
}
}
I think there isn't better solution because of the way phpexcel stores information about merged cells.

The easiest way is to use the getMergeRange() method.
if ($cell->getMergeRange()) {
// cell is merged
}
I suspect many people will want to know the value of the merged cell, in which case you can refer to the following code:
if (($range = $cell->getMergeRange()) && !$cell->isMergeRangeValueCell()) {
$first_in_range_coordinates = strtok($range, ':');
$value = $sheet->getCell($first_in_range_coordinates)->getValue();
}

Related

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

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

Read excel sheet containing merged cells using PHPExcel

I want to read an excel sheet completely and using AJAX send each row to another page for processing. So I have used the following code for converting the excel sheet data into JSON array(Reference PHPExcel example provided in Library):
<?php
error_reporting(E_ALL);
set_time_limit(0);
date_default_timezone_set('Asia/Kolkata');
set_include_path(get_include_path() . PATH_SEPARATOR . 'PHPExcel-1.8/Classes/');
require_once 'PHPExcel/IOFactory.php';
$inputFileType = PHPExcel_IOFactory::identify($fileLocation);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objReader->setLoadSheetsOnly("SHEETNAME");
$objPHPExcel = $objReader->load($fileLocation);
$data = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true);
?>
Here $filelocation is the location of the uploaded file which is to be read for sending the rows individually using AJAX to another page.
I am using $data in javascript as
DataToBeUploaded=<?php echo json_encode($data);?>;
But the excel sheet contains some merged cells so PHPExcel is not able to read the values in these merged cells. Hence values in these cells are read as NULL.
Is there a way where I can use the merged cells' upper left cell value for all of the subsequent cells? (Actually in my case cells are merged vertically only)
Eg.
I have (Assume rows are numbered from 1 and columns from A)
Here PHPExcel reads this as:
data[1][A]='abc'
$data[1][B]='123'
$data[2][A]=''
$data[2][B]='456'
$data[3][A]=''
$data[3][B]='789'
I want the snippet to result in these values:
data[1][A]='abc'
$data[1][B]='123'
$data[2][A]='abc'
$data[2][B]='456'
$data[3][A]='abc'
$data[3][B]='789'
Referring to https://github.com/PHPOffice/PHPExcel/issues/643
I have written the following snippet:
$referenceRow=array();
for ( $row = 2; $row <= $noOfBooks; $row++ ){
for ( $col = 0; $col < 7; $col++ ){
if (!$objPHPExcel->getActiveSheet()->getCellByColumnAndRow( $col, $row )->isInMergeRange() || $objPHPExcel->getActiveSheet()->getCellByColumnAndRow( $col, $row )->isMergeRangeValueCell()) {
// Cell is not merged cell
$data[$row][$col] = $objPHPExcel->getActiveSheet()->getCellByColumnAndRow( $col, $row )->getCalculatedValue();
$referenceRow[$col]=$data[$row][$col];
//This will store the value of cell in $referenceRow so that if the next row is merged then it will use this value for the attribute
} else {
// Cell is part of a merge-range
$data[$row][$col]=$referenceRow[$col];
//The value stored for this column in $referenceRow in one of the previous iterations is the value of the merged cell
}
}
}
This will give the result exactly as required

PHPExcel excel read is not working for some cells with calculation

I use PHPExcel lib for read the excel file in Codeigniter project. It is not read some cells with calculation. It show as #VALUE! But some values with calculation is reading in same excel sheet. Whats wrong with those cells?
Cells with have following calculation is not reading
=+D109*1000
=+B16/B13
=+D23/$D$109
Cells with have following calculation is reading
=+B10-B11
=+C10-C11
But all cells are reading for some excel sheet. This issue come with xlsx format
This is my code
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setReadDataOnly(true);
$this->excel = $objReader->load($path);
$this->excel->setActiveSheetIndex($sheet);
$data = $this->excel->getActiveSheet()->toArray(null, true, true, true);
print_r($data);
I check with google. getCalculatedValue() should use for read calculated values. But i can't use it one by one. Is it has a method to read all sheet as array?
How ever i checked some cells with following way
$this->excel->getActiveSheet()->getCell('B18')->getCalculatedValue() // return #VALUE!
$this->excel->getActiveSheet()->getCell('B18')->getOldCalculatedValue() //return 0.4211
How i use old calculated value using toArray?
Finally I get old getOldCalculatedValue using loop.
$data = $this->excel->getActiveSheet()->toArray(null, true, true, true);
//This code add for some calculated cells were not reading in xlsx format
foreach ($data as $no => $row) {
foreach ($row as $key => $value) {
if (isset($value) && $value == '#VALUE!') {
$data[$no][$key] = $this->excel->getActiveSheet()->getCell($key.$no)->getOldCalculatedValue();
}
}
}

PHPExcel How to get only 1 cell value?

I would think that a getCell($X, $y) or getCellValue($X, $y) would be available for one to easily pick a a certain value. This can be usefully, as example crosscheck data prior to a larger process.
How do you get a specific value from say cell C3.
I do not want an array of values to sort through.
Section 4.5.2 of the developer documentation
Retrieving a cell by coordinate
To retrieve the value of a cell, the cell should first be retrieved from the worksheet using the getCell method. A cell’s value can be read again using the following line of code:
$objPHPExcel->getActiveSheet()->getCell('B8')->getValue();
Section 4.5.4 of the developer documentation
Retrieving a cell by column and row
To retrieve the value of a cell, the cell should first be retrieved from the worksheet using the getCellByColumnAndRow method. A cell’s value can be read again using the following line of code:
// Get cell B8
$objPHPExcel->getActiveSheet()->getCellByColumnAndRow(1, 8)->getValue();
If you need the calculated value of a cell, use the following code. This is further explained in 4.4.35
// Get cell B8
$objPHPExcel->getActiveSheet()->getCellByColumnAndRow(1, 8)->getCalculatedValue();
By far the simplest - and it uses normal Excel co-ordinates:
// Assuming $sheet is a PHPExcel_Worksheet
$value = $sheet->getCell( 'A1' )->getValue();
You can separate the co-ordinates out in a function if you like:
function getCell( PHPExcel_Worksheet $sheet, /* string */ $x = 'A', /* int */ $y = 1 ) {
return $sheet->getCell( $x . $y );
}
// eg:
getCell( $sheet, 'B', 2 )->getValue();
This is a source based answer feel free to improve or comment.
function toNumber($dest)
{
if ($dest)
return ord(strtolower($dest)) - 96;
else
return 0;
}
function myFunction($s,$x,$y){
$x = toNumber($x);
return $s->getCellByColumnAndRow($x, $y)->getFormattedValue();
}
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objPHPExcel = $objReader->load($inputFileName);
$objPHPExcel->setActiveSheetIndex(0);
$sheetData = $objPHPExcel->getActiveSheet();
$cellData = myFunction($sheetData,'B','2');
var_dump($cellData);
This does not work past the letter Z, and could be improved but works for my needs.

To upload Excel and store it in database?

I want to upload an Excel file into our webpage, then corresponding data store it in database. And then I want to retrieve all data and display it in table format. I have one code but using that I can't upload all Excel files. Only a single format can be upload.
Below is the function. But there is some restriction.
public function check_excel($filename)
{
$path='./assets/uploads/excel/'.$filename;
$this->load->library('excel');
$inputFileType = PHPExcel_IOFactory::identify($path);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objPHPExcel = PHPExcel_IOFactory::load($path);
$sheet = $objPHPExcel->getSheet(0);
$highestRow = $sheet->getHighestRow();
$highestColumn = $sheet->getHighestColumn();
$xf[]='';
$result[]='';
$first_check='';
$var_check=0;
for ($row = 13; $row <= $highestRow; $row++)
{
$xf[$row]=$objPHPExcel->getActiveSheet()->getCell('A'.$row)->getXfIndex(); // Get sheet index value
if($row>13 && $row<16) //This block check first kpi data expand or not
{
if($xf[$row-1]==$xf[$row]) //check parent and child sheet index value same
$first_check='false';
if ($row==15)
{
if($xf[$row]==$xf[$row-1] || $xf[$row]==$xf[$row-2]) // check the grand-child sheet index value same in parent and child
$first_check='false';
else
{
$first_check='true';
$a=$row-2;
$b=$row-1;
$check_kpi=$objPHPExcel->getActiveSheet()->getCell('A'.$a)->getXfIndex();
$check_unit=$objPHPExcel->getActiveSheet()->getCell('A'.$b)->getXfIndex();
$check_sub_unit=$objPHPExcel->getActiveSheet()->getCell('A'.$row)->getXfIndex();
}
}
}
if($first_check=='true') //This block check second kpi to upto last kpi data expand or not
{
if($row>15)
{
if($var_check==1) // This block check the child data expand or not
{
if($check_unit!=$objPHPExcel->getActiveSheet()->getCell('A'.$row)->getXfIndex())
{
$result[$row]='false';
break;
}
}
if($var_check==2) // this block check the grand - child data expand or not
{
if($check_sub_unit!=$objPHPExcel->getActiveSheet()->getCell('A'.$row)->getXfIndex())
{
$result[$row]='false';
break;
}
}
if($xf[$row]!=$check_sub_unit)
{
if($xf[$row]!=$check_unit)
$var_check=1; // var_check value is one, the kpi is present
else
$var_check=2; // var_check value is two, the unit is present
}
else
$var_check=0; // var_check value is zero, the sub_unit is present
}
}
else if($first_check=='false')
{
$result[$row]='false';
break;
}
}
$return='true';
for ($row = 13; $row <= $highestRow; $row++)
{
if(!empty($result[$row]))
{
if($result[$row]=='false'){
$return='false';
break;
}
}
}
return $return;
}
It sounds like you are using a relational DB (e.g. MySQL, Postgres, etc), which uses fixed column tables.
You should probably use a Document-based DB (e.g. CouchDB, Mongo, etc). This would be the best solution.
But, if you're stuck using a relational DB, you can use an EAV model.
Here is a basic example:
Create a table for the entity (excel file): EntityID, ExcelFileName
Create a table for the attribute (column info): AttributeID, EntityID, AttributeName
Create a table for the value (excel row/column): ValueID, RowNumber, AttributeID, AttributeValue
The downside is that the AttributeValue isn't specifically typed (it's just varchar/text). You can solve this by adding a "AttributeType" to the attribute table that is then used in your code to know what type of data that column should contain. BUT, unless you know the contents/format of the Excel file in advance, you'll probably have to GUESS what the type of a column is...which isn't hard as long as the excel file isn't messed up.
If you're just displaying the data that was imported, this probably isn't a big deal.
There are other (more complex) ways to implement EAV, including one with typed columns, if you have such a need.
Have you tried PHPExcel?
They also have a codeigniter library.
And this post might interest you : how to use phpexcel to read data and insert into database?
You can use PHPExcel of course, but have a look at other data format. Using comma-separated or tab-separated values can help you to solve your problem easily. Excel can save datasheets in these simple formats. Anyway, you cannot save formulas or conditional formatting in you database Moreover, it is much faster and robust and you can import CSV files with LOAD DATA INFILE query.

Categories