I'm trying to understand how to get data from cells in PHPExcel but I have no idea. I read all documentation and I made this:
<?php
include('PHPExcel/Classes/PHPExcel/Reader/Excel2007.php');
class MyReadFilter implements PHPExcel_Reader_IReadFilter
{
public function readCell($column, $row, $worksheetName = '') {
// Read title row and rows 20 - 30
if ($row == 1 || ($row >= 20 && $row <= 30)) {
return true;
}
return false;
}
}
$objReader = new PHPExcel_Reader_Excel2007();
$objReader->setReadFilter( new MyReadFilter() );
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load("sample_mymails222.xlsx");
print_r($objPHPExcel);
?>
print_r show very big array.
I think there is some functions to get data from cell in $objPHPExcel.
How to do it?
Thanx!
For anyone else who wants a more helpful answer, following the code in the example above, here is a quick snippet that will parse the active worksheet into a multi-dimensional array (this example ignores the ReadFilter that the OP created).
$data = array();
$worksheet = $objPHPExcel->getActiveSheet();
foreach ($worksheet->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
foreach ($cellIterator as $cell) {
$data[$cell->getRow()][$cell->getColumn()] = $cell->getValue();
}
}
var_dump($data);
BTW The reason I say "more helpful answer" is that I also had a hard time figuring out the PHPExcel documentation (which consists of 6 separate documents and no real API-like reference) the first time around.
The OP says he "read all the docs", but I am guessing that, like me, he read through the file called PHPExcel User Documentation - Reading Spreadsheet Files.doc which explains how to read in a spreadsheet, but does not cover using the contents.
To find that out, you have to dig into PHPExcel developer documentation.doc and get down to part 4 (which is where I found the example above).
Yup, my fault for not being thorough, but clearly this is a recurring issue. :-)
for reading excel file you can use this
require_once('PHPExcel.php');
$input_file_type = PHPExcel_IOFactory::identify($excel_file);
$obj_reader = PHPExcel_IOFactory::createReader($input_file_type);
$obj_reader->setReadDataOnly(true);
$objPHPExcel = $obj_reader->load($excel_file);
$objWorksheet = $objPHPExcel->setActiveSheetIndex(0);
$highest_row = $objWorksheet->getHighestRow();
$highest_col = $objWorksheet->getHighestColumn();
//$highest_col_index = PHPExcel_Cell::columnIndexFromString($highest_col);
// start $row from 2, if you want to skip header
for ($counter = 2; $counter <= $highest_row; $counter++)
{
$row = $objWorksheet->rangeToArray('A'.$counter.':'.$highest_col.$counter);
$row = reset($row);
}
Please read the documentation chapter 4.5 (included in the PHPExcel download package)
Related
The problem I'm facing is that I have a SplFileObject that reads a CSV file, then I wrap it into a LimitIterator.
The CSV file has 2 rows, header, and 1 row, I set the LimitIterator offset to 1 and I can't reach over it, seems some internal problems with the indexing.
here is the code:
$csvFile = new \SplFileObject($fileName);
$csvFile->setFlags(\SplFileObject::READ_CSV);
$iterator = new \LimitIterator($csvFile, 1);
/** #var \LimitIterator $it */
foreach ($iterator as $it) {
list($.., $.., $..) = $it;
$result[] = [
...
];
}
return $result;
The code works well if the CSV has 3 lines (header and 2 rows), but only with header and 1 row, it doesn't work.
Any Idea?
Thanks.
This is related to PHP bug 65601, which suggests adding the READ_AHEAD flag will fix this. Tested and works as you expected it to.
$csvFile->setFlags(\SplFileObject::READ_CSV | \SplFileObject::READ_AHEAD);
See also SplFileObject + LimitIterator + offset
Personally, I would use the fopen and fgetcsv functions for this as below;
<?php
$handle = fopen("myFile.csv", "r");
if ($handle != false)
{
$header_row_handled = false;
while ($datarow = fgetcsv($handle, 0, ",")
{
if (!$header_row_handled)
{
$header_row_handled = true;
}
else
{
/* Whatever you need */
$dataparta = $datarow[0];
$datapartb = $datarow[1];
$datapartc = $datarow[2];
}
}
}
Looping means you can just skip the first row each time and perhaps use less resource for this as you don't have as many objects floating around
The php.net page should help you out too
Trying to maintain some old dusty code, I am facing a problem with phpexcel in a import symfony command.
It seems that the library cannot calculate the formula correctly which is linked to another sheet of the same document as the active sheet.
The error I get is :
[PHPExcel_Calculation_Exception]
Price Template Map!B2 -> Invalid cell coordinate A
My code is :
try {
$inputFileType = \PHPExcel_IOFactory::identify($filePath);
$objReader = \PHPExcel_IOFactory::createReader($inputFileType);
$objReader->setLoadSheetsOnly(array($this->getListName(), 'Template Info'));
$objReader->setIncludeCharts(true);
$objPHPExcel = $objReader->load($filePath);
} catch (\Exception $e) {
throw new \Exception("Invalid file");
}
$sheet = $objPHPExcel->getActiveSheet();
$highestRow = $sheet->getHighestRow();
$highestColumn = $sheet->getHighestColumn();
$fieldsNumber = array();
$filterData = array();
$templateIdList = array();
for ($i = 1; $i <= $highestRow; $i++) {
$rowData = $sheet->rangeToArray('A' . $i . ':' . $highestColumn . $i, null, true, false);
$rowData = $rowData[0];
var_dump($rowData);
}
The first line with the headers is read correctly, but the rest is not.
My formula is :
=VLOOKUP(A18,'Template Info'!A:C,3,FALSE)"
Do not hesitate to ask me more informations if you need it !
Thank you all in advance :) !
The problem is the column reference: the PHPExcel Calculation Engine supports range references (even to other worksheets), but not row or column references
so
=VLOOKUP(A18,'Template Info'!A1:C100,3,FALSE)
would be valid, but
=VLOOKUP(A18,'Template Info'!A:C,3,FALSE)
can't be calculated
Use the getCalculatedValue() function.
How to get Excel data into an array in PHP local site. I want to print data in Excel as array in my practice site. I have created Excel in htdocs as test.xlsx. How can I print it's data in PHP?
First include PhpExcel library into your code then use this
PHPExcel_IOFactory::addSearchLocation($filepath, $savedfilename);
$objReader = PHPExcel_IOFactory::load($filepath);
$data = array();
$worksheet = $objReader->getActiveSheet();
foreach ($worksheet->getRowIterator(2) as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
foreach ($cellIterator as $cell) {
$data[$cell->getRow()][$cell->getColumn()] = $cell->getValue();
}
}
print_r($data);
Can you please look at this link once, I think you can get more idea for your question.
http://www.phpgang.com/how-to-read-excel-file-insert-data-into-mysql-database-using-php_609.html
I'm using Symfony2.3.4, PHP5.6.3 and PHPExcel 1.8.0.
When I tried to read an excel file it works OK for almost all cells.
If the cell contains a very large number, when I read it and show the value in an html view it outputs false.
I tried to use a custom value binder like Mark Baker instructed here but I couldn't make it work, it just comes as a boolean right from the beginning.
IMPORTANT:
The excels I'm trying to load in the html are downloaded(generated) from another site and I noticed when you try to open them with Microsoft Excel, it first prompts you with a warning window telling the user that the FILE EXTENSION AND THE FILE FORMAT DO NOT MATCH, although if you choose to open it anyway, it opens fine.
I think that's what's causing the problem, I'm almost sure(I can't contact the guys who implemented the other site's download function) they did something like this:
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, $ext == 'xlsx' ?
'Excel5' : 'Excel2007');
when they should have done something like this:
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, $ext == 'xls' ?
'Excel5' : 'Excel2007');
making the EXTENSION and the FORMAT match, as instructed in the PHPExcel's docs.
If you need any specific clarification please ask.
My code to load the file into the html:
public function uploadAction() {
$request = $this->getRequest();
$form = $this->createFormBuilder()
->add('file', 'file')
->getForm();
if ($request->getMethod() == 'POST'){
$form->submit($request);
$file = $form['file'];
$file->getData()->move(
'uploads', $form['file']->getData()->getClientOriginalName());
$ext = pathinfo($file->getData()->getClientOriginalName(), PATHINFO_EXTENSION);
$name = pathinfo($file->getData()->getClientOriginalName(), PATHINFO_BASENAME);
//$objReader = \PHPExcel_IOFactory::createReader('xlsx' == $ext ? 'Excel2007' : 'Excel5');
$objReader = \PHPExcel_IOFactory::createReaderForFile('uploads/' . $name);
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load('uploads/' . $name);
$activeSheet = $objPHPExcel->getActiveSheet();
$rowIter = $activeSheet->getRowIterator();
foreach ($rowIter as $key => $row) {
$columns = array();
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
foreach ($cellIterator as $cell)
$columns[] = $cell->getCalculatedValue();
}
}
}
NOTE: I really don't know the difference between:
$objReader = \PHPExcel_IOFactory::createReader('xlsx' == $ext ? 'Excel2007' : 'Excel5');
and
$objReader = \PHPExcel_IOFactory::createReaderForFile('uploads/' . $name);
I DO know I can't use the first because of the problem I described above about the files being ill-generated and so. If I try to use it, the browser goes:
The filename uploads/<name>.xls is not recognised as an OLE file.
Can anyone point me to a workaround, because it's now me on the hook and I'm supposed to make it work somehow. Maybe there's nothing wrong with the files and it's me doing something wrong. Please help, this is causing me problems with dates too but one step at a time.
EDIT:
This is but the read function in OLERead.php.
I was browsing it and var_dump-ing all I could get my hands on.
As you can see there are two var_dumps in the code below, those output:
string '<div>
' (length=8)
string '��ࡱ�' (length=8)
Which doesn't happen when I try it with a regular .xls file created manually:
string '��ࡱ�' (length=8)
string '��ࡱ�' (length=8)
I guessed you could use this better than me if it helps at all. Thanks again.
public function read($sFileName) {
// Check if file exists and is readable
if (!is_readable($sFileName)) {
throw new PHPExcel_Reader_Exception("Could not open " . $sFileName . " for reading! File does not exist, or it is not readable.");
}
// Get the file identifier
// Don't bother reading the whole file until we know it's a valid OLE file
$this->data = file_get_contents($sFileName, FALSE, NULL, 0, 8);
////VAR_DUMPSSSSSSSSSSSS
var_dump($this->data);
var_dump(self::IDENTIFIER_OLE);
die();
// Check OLE identifier
if ($this->data != self::IDENTIFIER_OLE) {
throw new PHPExcel_Reader_Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');
}
// Get the file data
$this->data = file_get_contents($sFileName);
// Total number of sectors used for the SAT
$this->numBigBlockDepotBlocks = self::_GetInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
// SecID of the first sector of the directory stream
$this->rootStartBlock = self::_GetInt4d($this->data, self::ROOT_START_BLOCK_POS);
// SecID of the first sector of the SSAT (or -2 if not extant)
$this->sbdStartBlock = self::_GetInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
// SecID of the first sector of the MSAT (or -2 if no additional sectors are used)
$this->extensionBlock = self::_GetInt4d($this->data, self::EXTENSION_BLOCK_POS);
// Total number of sectors used by MSAT
$this->numExtensionBlocks = self::_GetInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
$bigBlockDepotBlocks = array();
$pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;
$bbdBlocks = $this->numBigBlockDepotBlocks;
if ($this->numExtensionBlocks != 0) {
$bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;
}
for ($i = 0; $i < $bbdBlocks; ++$i) {
$bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos);
$pos += 4;
}
for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
$pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
$blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
$bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos);
$pos += 4;
}
$bbdBlocks += $blocksToRead;
if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
$this->extensionBlock = self::_GetInt4d($this->data, $pos);
}
}
$pos = 0;
$this->bigBlockChain = '';
$bbs = self::BIG_BLOCK_SIZE / 4;
for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
$pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
$this->bigBlockChain .= substr($this->data, $pos, 4 * $bbs);
$pos += 4 * $bbs;
}
$pos = 0;
$sbdBlock = $this->sbdStartBlock;
$this->smallBlockChain = '';
while ($sbdBlock != -2) {
$pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
$this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs);
$pos += 4 * $bbs;
$sbdBlock = self::_GetInt4d($this->bigBlockChain, $sbdBlock * 4);
}
// read the directory stream
$block = $this->rootStartBlock;
$this->entry = $this->_readData($block);
$this->_readPropertySets();
}
The difference between
$objReader = \PHPExcel_IOFactory::createReader('xlsx' == $ext ? 'Excel2007' : 'Excel5');
and
$objReader = \PHPExcel_IOFactory::createReaderForFile('uploads/' . $name);
The first is trusting that the extension is correct for the actual format of the file, that a file with an extension of .xlsx really is an OfficeOpenXML-format file or an extension of .xls really is a BIFF-format file, and then telling PHPExcel to use the appropriate reader.
This isn't normally a problem unless it isn't (for example) just HTML markup in a file with an .xls or .xlsx extension.... then you're selecting the wrong Reader for the actual format of the file; and this is what MS Excel itself is telling you with its message that "FILE EXTENSION AND THE FILE FORMAT DO NOT MATCH"
The second is using PHPExcel's identify() method to work out what format the file really is (irrespective of what it claims to be based on a false extension), and then selecting the appropriate Reader for that format.
EDIT
Unsure exactly how large your large numbers are, but I'll take a look at the HTML Reader and see if I can identify why it should be giving a boolean false instead of an actual numeric value
I'm using the following to convert CSV to JSON (https://gist.github.com/robflaherty/1185299). I need to need to modify it so that instead of using the exact file url path, it's pulling the newest file url in the directory as it's "source" in $feed.
Any help would be great! I've tried using the code found here PHP: Get the Latest File Addition in a Directory, but can't seem to figure how modify it so that it would work.
<?php
header('Content-type: application/json');
// Set your CSV feed
$feed = 'http://myurl.com/test.csv';
// Arrays we'll use later
$keys = array();
$newArray = array();
// Function to convert CSV into associative array
function csvToArray($file, $delimiter) {
if (($handle = fopen($file, 'r')) !== FALSE) {
$i = 0;
while (($lineArray = fgetcsv($handle, 4000, $delimiter, '"')) !== FALSE) {
for ($j = 0; $j < count($lineArray); $j++) {
$arr[$i][$j] = $lineArray[$j];
}
$i++;
}
fclose($handle);
}
return $arr;
}
// Do it
$data = csvToArray($feed, ',');
// Set number of elements (minus 1 because we shift off the first row)
$count = count($data) - 1;
//Use first row for names
$labels = array_shift($data);
foreach ($labels as $label) {
$keys[] = $label;
}
// Add Ids, just in case we want them later
$keys[] = 'id';
for ($i = 0; $i < $count; $i++) {
$data[$i][] = $i;
}
// Bring it all together
for ($j = 0; $j < $count; $j++) {
$d = array_combine($keys, $data[$j]);
$newArray[$j] = $d;
}
// Print it out as JSON
echo json_encode($newArray);
?>
It's a difficult question to answer because there isn't enough detail.
Here are some questions that need answered.
1). Are you creating the csv files that are being read? If you are, you just make sure that the file you want to read is called "latest.csv" and when you go to create "latest.csv" you check for an existing "latest.csv" and rename/archive it first. Your directory then contains archives but the latest one is always of the same name.
2). If you are not creating the csv files then you might want to ask the provider of the csv files if there's a way for you to identify the latest one, as surely, if they are providing them they'd expect to be providing everyone the latest feed and have a mechanism of doing that.
3). If you don't know the provider and want to take a guess, have a look at how the files are named and try to predict the latest one. Eg, if they appear to be including a month and year in them do a file_exists() (if you can) on the predicted next latest file. Again, just a possibility.
Based on your comments, if the files reside on the same server or are accessible on a filesystem that supports the file functions, then:
array_multisort(array_map('filemtime', $files=glob('/path/to/*.csv')), SORT_DESC, $files);
$newest = $files[0];
For remote access you could look at something like this: How can I download the most recent file on FTP with PHP?