phpexcel read 18 digitals long number from cell - php

I use phpexcel read and import a CSV file one of which cells is a 18 digits long, like 123456789123456789, though I use ini_set("precision", "18"); but the value I get is not correct. How to solve this problem?
ini_set("precision", "20");
$objReader = PHPExcel_IOFactory::createReader('CSV')
->setDelimiter(',')
->setInputEncoding('GBK')
->setEnclosure('"')
->setLineEnding("\r\n")
->setSheetIndex(0);
$objPHPExcel = $objReader->load($file);
$worksheet = $objPHPExcel->getActiveSheet();
foreach ($worksheet->getRowIterator() as $row) {
echo 'Row number: ' . $row->getRowIndex() . "\r\n<br>";
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set
foreach ($cellIterator as $cell) {
if (!is_null($cell)) {
echo 'Cell: ' . $cell->getCoordinate() . ' - ' . (string)$cell->getValue() . "\r\n<br>";
}
}
}

In comments you mentioned that the wrong output has two additional zeroes. This is surely caused by a wrong interpretation of a decimal separator, so that it is treated as a thousands separator.
Change your PHP server's regional settings so it uses the point as the decimal separator -- you might need to change your thousands separator as well (if it currently is a point).

Convert the long integer to string you can read the value
$value = 123456789123456789;
$value = (string)$value;

Last Try
$keyCell = $sheet->getCellByColumnAndRow(1,5)->getFormattedValue();
now replace the $cell->getvalue() into $keyCell
and
Here 1,5 is static column and row, In your code you have to use it dynamically

Related

csv file semicolon separated - issue with comma in field

I have a csv file where fields are separated by semicolons. Inside each field we can have comma (decimal separator for numbers in italy is comma).
a sample data is:
15/01/2021;15/01/2021;ADDEBITO SDD;PAGAMENTO NEXI 8000640000030620818186 NEXI S.P.A. CORSO SEMP - ADDE BITO SPESE CARTA DI CREDITO ESTRATTO CONTO DEL : 31/ 12/2020 - UNCRITMMXXX IT500040000004107060966;1.501,2;;Uscita;
I explode this line by semicolon and then build a table row out of it:
while (($line = fgetcsv($f)) !== false) {
$row = $line[0];
$cells = explode(";",$row);
echo "<tr>";
foreach ($cells as $cell) {
echo "<td>";
echo htmlspecialchars($cell);
echo "</td>";
$cur_col_num+=1;
}
echo "</tr>\n";
The issue I have is that the string "1.501,2" is echoed as 1.501 loosing the decimals.
If the source is "1501.2" this is echoed correctly as "1501.2".
How do I keep the decimal if the separator is a comma? I have no control over the content of the csv that is coming from different sources and so I need to handle both situations.
EDIT: after some more tests I realized that actually for any line containg the comma it stops processing the line after the comma (ignoring the following fields). So in the example I never see "Uscita" in its table cell
EDIT 2: this is the output of my code on the browser for this specific line
CSV means "comma separated values", so fgetcsv() splits the line at , characters by default. Your file uses ; as the field separators, so you should tell fgetcsv() to use that instead.
Then you don't need to call explode() yourself.
while ($cells = fgetcsv($f, null, ';')) {
echo "<tr>";
foreach ($cells as $cell) {
echo "<td>";
echo htmlspecialchars($cell);
echo "</td>";
$cur_col_num+=1;
}
echo "</tr>\n";
}

CSV generated file in PHP : last value is truncated

In CodeIgniter 2, I'm generating a CSV file from fetching data from my Oracle Database (volume of data can be a less than 10 lines to hundreds of thousands of lines, this is why I "unset" each $line) using the following code :
$conn = $this->db;
$stid = oci_parse($conn->conn_id, $sql);
oci_execute($stid);
// Header extraction
$headers = "";
$values = "";
$row = oci_fetch_array($stid, OCI_ASSOC + OCI_RETURN_NULLS );
foreach($row as $key => $value) {
$headers = $headers.$key.';';
$values = $values.$value.';';
}
// Remove of last comma and adding in a line break
$headers = substr($headers,0,-1). "\r\n";
$values = substr($values,0,-1). "\r\n";
$data = $headers . $values;
$values = "";
// Parsing all data to concatenate the values
while (($row = oci_fetch_array($stid, OCI_ASSOC + OCI_RETURN_NULLS)) != false) {
$line = "";
foreach ($row as $key => $value) {
$line .= $value . ';';
}
$line = substr($line, 0, -1) . "\n";
$data = $data . $line;
// Freeing memory for the line
unset($line);
}
return $data;
Using this piece code, my CSV file is properly generated except for one thing.
When I'm exporting just a small number of lines, everything is fine. I have all the values, for ALL lines, comma seperated.
However, when I'm exporting a few hundred or thousand of lines, the LAST value from the LAST line is always truncated by 5 characters (data in the database is OK).
HEADER1;HEADER2;HEADER3;HEADER4;HEADER5
1-XXXXXX;F1;IDX1;ERR_IDX_CAX_0001
1-XXXXXX;F1;IDX1;ERR_IDX_CAX_0001
1-XXXXXX;F1;IDX1;ERR_IDX_CAX_0001
1-XXXXXX;F1;IDX1;ERR_IDX_CAX_0001
1-XXXXXX;F1;IDX1;ERR_IDX_CAX_0001
[.......]
1-XXXXXX;F1;IDX1;ERR_IDX_CAX_0001
1-XXXXXX;F1;IDX1;ERR_IDX_CAX
I thought maybe it was some cache limitation or something, but it happens after a few hundred lines exported and wether it's just a few hundred or several hundred thousand lines.
I can't figure this one out ...
Can anybody help ?
Thanks in advance.
Original issue described in this post not related to the code.
The issue comes from the Header Content Length passed by CodeIgniter force_download() function (from CI download helper).
header("Content-Length: ".strlen($data));
strlen($data) doesn't return (in my case) the correct length of data and my browser then only downloads the amount of data that was passed in the header, hence truncating a few characters at the end.
Not finding anything on this "issue", I decided to comment out the header Content length line

PHPEXCEL get formatted date as is visible in excel file [duplicate]

This question already has answers here:
how to get date from excel using PHPExcel library
(5 answers)
Closed 3 years ago.
I am trying to import a excel file using PhpExcel lib
for all other fields the getValue() function works but when it encounters a field with format date as set in ms-excel2013
the date field in exel file is in format d-m-Y like 16-11-2014
but when I try to import it's value the getValue() returns 11-16-14 which when passed to strtotime further returns false in turn causing the date('Y-m-d',strtotime($date)) to return 1970-01-01.
I searched whole of web and stackoverflow but none solution fixed my problem.
In excel file i see the date as 16-11-2014 and want it to be imported as is.
Here's the code
protected function importExcel($filePath) {
$excelData = array();
if ($filePath) {
$objPHPExcel = PHPExcel_IOFactory::load($filePath);
$objPHPExcel->setReadDataOnly(true);
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
$worksheetTitle = $worksheet->getTitle();
$highestRow = $worksheet->getHighestRow(); // e.g. 10
$highestColumn = $worksheet->getHighestColumn(); // e.g 'F'
$highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn);
$nrColumns = ord($highestColumn) - 64;
$data = array();
for ($row = 1; $row <= $highestRow; ++$row) {
$values = array();
for ($col = 0; $col < $highestColumnIndex; ++$col) {
$cell = $worksheet->getCellByColumnAndRow($col, $row);
if (PHPExcel_Shared_Date::isDateTime($cell))
throw new Exception("is date time"); // just a check
$val = $cell->getValue();
if (isset($val) && $val)
$data[$row][$col] = $val;
}
}
$excelData[$worksheetTitle] = $data;
}
return $excelData;
}
return FALSE;
}
A getValue() call on a field containing a date should return a value like 41959.00 if that field really does contain an MS Excel date value.... that is, an MS Excel serialized datetime stamp based on the number of days since 1st January 1900 (or 1st January 1904 if the file was created using the Mac version of MS Excel)
To get a formatted date string, you need to call getFormattedValue() instead; and PHPExcel then uses the number format mask for that cell to format the date according to that mask.
To identify if a cell contains an MS serialized datetime stamp, you can use a call to PHPExcel_Shared_Date::isDateTime() first.
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
echo 'Worksheet - ' , $worksheet->getTitle() , EOL;
foreach ($worksheet->getRowIterator() as $row) {
echo ' Row number - ' , $row->getRowIndex() , EOL;
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set
foreach ($cellIterator as $cell) {
if (!is_null($cell)) {
echo ' Cell - ' , $cell->getCoordinate() , ' - ';
if (PHPExcel_Shared_Date::isDateTime($cell)) {
echo $cell->getFormattedValue() , EOL;
} else {
echo $cell->getValue() , EOL;
}
}
}
}
}
Rather than returning a formatted data value, you can also ask PHPExcel to return the date as a Unix timestamp, or as a PHP DateTime object instead; and then you'll be able to format it however you want using PHP's built-in date functions or DateTime methods.
if (PHPExcel_Shared_Date::isDateTime($cell)) {
$unixTimeStamp = PHPExcel_Shared_Date::ExcelToPHP($cell->getValue());
echo date('d-M-Y H:i:s', $unixTimeStamp), PHP_EOL;
}
or
if (PHPExcel_Shared_Date::isDateTime($cell)) {
$dateTimeObject = PHPExcel_Shared_Date::ExcelToPHPObject($cell->getValue());
echo $dateTimeObject->format('d-M-Y H:i:s'), PHP_EOL;
}
I've checked the file that you provided, looking at your date issue.
The format that you're using for those dates in your spreadsheet is a locale-aware date format, flagged by MS Excel with an asterisk (*) if you look at the cell format
This means (quoting from Excel's notes on the format mask display):
Date formats that begin with an asterisk (*) respond to changes in regional date and time settings that are specified for the Operating System.
Because PHPExcel is not locale-aware, but does recognise the format mask as a date value, it uses a generic formatting.
Running the following code
var_dump($objPHPExcel->getActiveSheet()->getCell('I5')->getValue());
var_dump(PHPExcel_Shared_Date::isDateTime($objPHPExcel->getActiveSheet()->getCell('I5')));
var_dump($objPHPExcel->getActiveSheet()->getCell('I5')->getStyle()->getNumberFormat()->getFormatCode());
var_dump($objPHPExcel->getActiveSheet()->getCell('I5')->getFormattedValue());
gives
float(42062)
bool(true)
string(8) "mm-dd-yy"
string(8) "02-27-15"
So (as long as you've removed that setReadDataOnly(true) call from the Reader, call from the Reader, you can still identify date cells as dates, and format them manually, overriding the default locale-formatting
if (PHPExcel_Shared_Date::isDateTime($objPHPExcel->getActiveSheet()->getCell('I5'))) {
$dateTimeObject = PHPExcel_Shared_Date::ExcelToPHPObject($objPHPExcel->getActiveSheet()->getCell('I5')->getValue());
echo $dateTimeObject->format('d-m-Y'), PHP_EOL;
}
I have found out the solution:
Method _formatAsDate in the file PHPExcel/Style/NumberFormat.php
if the date is like 16/11/2014, when passed to strtotime will result in false as the date is supposed to be in format m/d/Y by strtotime. So if you change the format to m/d/Y if it's d/m/Y then the solution will always be correct.
Earlier:
16/11/2014==1970-01-01 (Row: 1)
16/11/2014==1970-01-01 (Row: 2)
23/12/2014==1970-01-01 (Row: 3).
Now:
11/16/2014==2014-11-16 (Row: 1)
11/16/2014==2014-11-16 (Row: 2)
12/23/2014==2014-12-23 (Row: 3)
Code is still the same and simple to import the file:
protected function importExcel($filePath) {
$excelData = array();
if ($filePath) {
$objPHPExcel = PHPExcel_IOFactory::load($filePath);
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
$worksheetTitle = $worksheet->getTitle();
$highestRow = $worksheet->getHighestRow(); // e.g. 10
$highestColumn = $worksheet->getHighestColumn(); // e.g 'F'
$highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn);
$nrColumns = ord($highestColumn) - 64;
$data = array();
for ($row = 1; $row <= $highestRow; ++$row) {
$values = array();
for ($col = 0; $col < $highestColumnIndex; ++$col) {
$cell = $worksheet->getCellByColumnAndRow($col, $row);
$val = $cell->getValue();
if (isset($val) && $val)
$data[$row][$col] = $val;
}
}
$excelData[$worksheetTitle] = $data;
}
return $excelData;
}
return FALSE;
}

PHPExcel calculate formula cell and format currency

Now I'm reading an excel file and showing it on a html table.
like this:
<?php
function load_table(){
require_once('Classes/PHPExcel.php');
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load("SampleData.xlsx");
$objWorksheet = $objPHPExcel->getActiveSheet();
$highestRow = $objWorksheet->getHighestRow(); // e.g. 10
$highestColumn = $objWorksheet->getHighestColumn(); // e.g 'F'
$highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn); // e.g. 5
echo '<table>' . "\n";
for ($row = 1; $row <= $highestRow; ++$row) {
echo '<tr>' . "\n";
for ($col = 0; $col <= $highestColumnIndex; ++$col) {
echo '<td>';
echo $objWorksheet->getCellByColumnAndRow($col, $row)->getValue();
echo '</td>' . "\n";
}
echo '</tr>' . "\n";
}
echo '</table>' . "\n";
}
?>
Sometimes the cell content is a formula. I'd like to calculate it and echo the result (just like excel does). I tried the code below but I got the following error:
Warning: Illegal string offset 'value' in...
echo $objWorksheet->getCellByColumnAndRow($col, $row)->getCalculatedValue();
I also tried something like:
echo $objWorksheet->getCellByColumnAndRow($col, $row)->getOldCalculatedValue();
This one worked, but I do not want to use GetOldCalculatedValue because:
getOldCalculatedValues() reads the value as it was last calculated by MS Excel (if available) though you can't guarantee it will always be there, or be correct if it is (you can disable autocalculation in MS Excel, or it won't be set if loading a CSV file); while getCalculatedValue() actually recalculates the value within PHPExcel itself.
Also I used echo to print just the formula string and it appears to be just fine:
echo $objWorksheet->getCellByColumnAndRow($col, $row)->getValue();
Fórmula printed:
=F2*E2
=F3*E3
=F4*E4
=F14*E14 ...
So how could I get the result of the formula and ALSO format it as currency ?
As regards cell formatting:
The cell won't have any format if you use
$objReader->setReadDataOnly(true);
because you're specifically telling PHPExcel not to load cell formats. Don't set readDataOnly to true if you want to read formats
As regards the other part of your question, if you're getting an error when you call
echo $objWorksheet->getCellByColumnAndRow($col, $row)->getCalculatedValue();
then it might be useful to say what the formula is
echo $objWorksheet->getCellByColumnAndRow($col, $row)->getValue();
should tell you the formula, so perhaps you might consider adding that to your question, because it's quite useful to know if you want help

PHPExcel Sumif and Skip

I just want to ask if there's a function in excel/phpexcel that can SUM a range of
cells but skip to add every one cell.
Ex. Range is A1:G1 and it will only sum A1+C1+E1+G1 skipping every 1 cell.
Or how can I do that? Please take note that range is dynamic. It could be a1:g1 or further or less.
Build the formula dynamically in your PHP script:
$startCell = 'A';
$endCell = 'H';
$row = 1;
$formula = '=' . $startCell . $row;
while ($startCell++ != $endCell && $startCell++ != $endCell) {
$formula .= '+' . $startCell . $row;
}
EDIT
Note that I've also added a pure Excel formula answer to your previous question

Categories