How to automatically read in calculated values with PHPExcel? - php

I have the following Excel file:
I read it in by looping over every cell and getting the value with getCell(...)->getValue():
$highestColumnAsLetters = $this->objPHPExcel->setActiveSheetIndex(0)->getHighestColumn(); //e.g. 'AK'
$highestRowNumber = $this->objPHPExcel->setActiveSheetIndex(0)->getHighestRow();
$highestColumnAsLetters++;
for ($row = 1; $row < $highestRowNumber + 1; $row++) {
$dataset = array();
for ($columnAsLetters = 'A'; $columnAsLetters != $highestColumnAsLetters; $columnAsLetters++) {
$dataset[] = $this->objPHPExcel->setActiveSheetIndex(0)->getCell($columnAsLetters.$row)->getValue();
if ($row == 1)
{
$this->column_names[] = $columnAsLetters;
}
}
$this->datasets[] = $dataset;
}
However, although it reads in the data fine, it reads in the calculations literally:
I understand from discussions like this one that I can use getCalculatedValue() for calculated cells.
The problem is that in the Excel sheets I am importing, I do not know beforehand which cells are calculated and which are not.
Is there a way for me to read in the value of a cell in a way that automatically gets the value if it has a simple value and gets the result of the calculation if it is a calculation?
Answer:
It turns out that getCalculatedValue() works for all cells, makes me wonder why this isn't the default for getValue() since I would think one would usually want the value of the calculations instead of the equations themselves, in any case this works:
...->getCell($columnAsLetters.$row)->getCalculatedValue();

getCalculatedValue() seems to work for all cells, see above

If you are unsure about the content of a cell (value or formula included),
I recommend you to primarily do a check if the cell has a formula and then copy - paste accordingly. getOldCalculatedValue() is very helpful in this case. Here is an example of that:
$code = $sheet->getCell('A'.$y)->getValue();
if(strstr($code,'=')==true)
{
$code = $sheet->getCell('A'.$y)->getOldCalculatedValue();
}
$objPHPExcel4->setActiveSheetIndex(0)
->setCellValue('A'.$l, $code);
For large data sets, getCalculatedValue() function is really cumbersome and lots of memory will be required to perform correctly.

Looks like getCalculatedValue() is deprecated. Try using getFormattedValue() instead.

getCalculatedValue() seems to do the right job you wanted. It will return the correct value if the cell contains FBV ( formula based value ). If not then the normal value will be returned instead.

getCalculatedValue
seems to work for all cells
$sheets = $spreadsheet->getAllSheets();
$priceCasegetCellByColumnAndRow = $sheet->getCellByColumnAndRow(14, ($key))->getCalculatedValue()
$priceCasegetCell = $sheet->getCell('O' . $key)->getCalculatedValue();

I have never imported an excel file in PHP so this is just a stab in the dark.
Why not check the first character in the cell for an "="
If true getCalculatedValue()
if not getCell()

Related

PHPExcel: Value not available (#N/A) from formula in Excel spreadsheet [duplicate]

I have the following Excel file:
I read it in by looping over every cell and getting the value with getCell(...)->getValue():
$highestColumnAsLetters = $this->objPHPExcel->setActiveSheetIndex(0)->getHighestColumn(); //e.g. 'AK'
$highestRowNumber = $this->objPHPExcel->setActiveSheetIndex(0)->getHighestRow();
$highestColumnAsLetters++;
for ($row = 1; $row < $highestRowNumber + 1; $row++) {
$dataset = array();
for ($columnAsLetters = 'A'; $columnAsLetters != $highestColumnAsLetters; $columnAsLetters++) {
$dataset[] = $this->objPHPExcel->setActiveSheetIndex(0)->getCell($columnAsLetters.$row)->getValue();
if ($row == 1)
{
$this->column_names[] = $columnAsLetters;
}
}
$this->datasets[] = $dataset;
}
However, although it reads in the data fine, it reads in the calculations literally:
I understand from discussions like this one that I can use getCalculatedValue() for calculated cells.
The problem is that in the Excel sheets I am importing, I do not know beforehand which cells are calculated and which are not.
Is there a way for me to read in the value of a cell in a way that automatically gets the value if it has a simple value and gets the result of the calculation if it is a calculation?
Answer:
It turns out that getCalculatedValue() works for all cells, makes me wonder why this isn't the default for getValue() since I would think one would usually want the value of the calculations instead of the equations themselves, in any case this works:
...->getCell($columnAsLetters.$row)->getCalculatedValue();
getCalculatedValue() seems to work for all cells, see above
If you are unsure about the content of a cell (value or formula included),
I recommend you to primarily do a check if the cell has a formula and then copy - paste accordingly. getOldCalculatedValue() is very helpful in this case. Here is an example of that:
$code = $sheet->getCell('A'.$y)->getValue();
if(strstr($code,'=')==true)
{
$code = $sheet->getCell('A'.$y)->getOldCalculatedValue();
}
$objPHPExcel4->setActiveSheetIndex(0)
->setCellValue('A'.$l, $code);
For large data sets, getCalculatedValue() function is really cumbersome and lots of memory will be required to perform correctly.
Looks like getCalculatedValue() is deprecated. Try using getFormattedValue() instead.
getCalculatedValue() seems to do the right job you wanted. It will return the correct value if the cell contains FBV ( formula based value ). If not then the normal value will be returned instead.
getCalculatedValue
seems to work for all cells
$sheets = $spreadsheet->getAllSheets();
$priceCasegetCellByColumnAndRow = $sheet->getCellByColumnAndRow(14, ($key))->getCalculatedValue()
$priceCasegetCell = $sheet->getCell('O' . $key)->getCalculatedValue();
I have never imported an excel file in PHP so this is just a stab in the dark.
Why not check the first character in the cell for an "="
If true getCalculatedValue()
if not getCell()

How to show 1 element of array dynamically with php?

in "file.txt" i have some numbers like 1234,123456,12345678 etc.
so i was wondering how i can get dynamically just one element, for example echo just 12345,then echo 123456, but one by one ???when user comes i want to show him one element,and then next time i want to show another element on the page, it would be good also if i could erase elements that i have echo...When i manually enter position it works... Please help...
I have a following code:
function test($n){
$file=file_get_contents("file.txt");
$array = explode(",", $file);
return print_r($array[$n]);
};
The solution will need deleting the number on your filesystem or marking it as already showed either on the filesystem or on the database, after the number gets echoed.
Shuffling the numbers or generating a random index will never quite be full proof since the same number could be shown again.
First of all, this is usually a terrible way of doing this.
It's much better to use a database, for example.
But you could do the following:
<?php
function getRandomNumber() {
// retrieve and parse the numbers
$numbers = file_get_contents('file.txt');
$numbers = explode(',' $numbers);
// select a random index
$randomIndex = array_rand($numbers);
// get the chosen number
$randomNumber = $numbers[$randomIndex];
// remove it from array
unset($numbers[$randomIndex]);
// save updated file
file_put_contents('file.txt', implode(',', $numbers));
return $randomNumber;
}

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.

php fgetcsv multiple lines not only one or all

I wand to read biiiiig CSV-Files and want to insert them into a database. That already works:
if(($handleF = fopen($path."\\".$file, 'r')) !== false){
$i = 1;
// loop through the file line-by-line
while(($dataRow = fgetcsv($handleF,0,";")) !== false) {
// Only start at the startRow, otherwise skip the row.
if($i >= $startRow){
// Check if to use headers
if($lookAtHeaders == 1 && $i == $startRow){
$this->createUberschriften( array_map(array($this, "convert"), $dataRow ) );
} else {
$dataRow = array_map(array($this, "convert"), $dataRow );
$data = $this->changeMapping($dataRow, $startCol);
$this->executeInsert($data, $tableFields);
}
unset($dataRow);
}
$i++;
}
fclose($handleF);
}
My problem of this solution is, that it's very slow. But the files are too big to put it directly into the memory... So I wand to ask, if there a posibility to read, for example 10 lines, into the $dataRow array not only one or all.
I want to get a better balance between the memory and the performance.
Do you understand what i mean? Thanks for help.
Greetz
V
EDIT:
Ok, I still have to try to find a solution with the MSSQL-Database. My solution was to stack the data and than make a multiple-MSSQL-Insert:
while(($dataRow = fgetcsv($handleF,0,";")) !== false) {
// Only start at the startRow, otherwise skip the row.
if($i >= $startRow){
// Check if to use headers
if($lookAtHeaders == 1 && $i == $startRow){
$this->createUberschriften( array_map(array($this, "convert"), $dataRow ) );
} else {
$dataRow = array_map(array($this, "convert"), $dataRow );
$data = $this->changeMapping($dataRow, $startCol);
$this->setCurrentRow($i);
if(count($dataStack) > 210){
array_push($dataStack, $data);
#echo '<pre>', print_r($dataStack), '</pre>';
$this->executeInsert($dataStack, $tableFields, true);
// reset the stack
unset($dataStack);
$dataStack = array();
} else {
array_push($dataStack, $data);
}
unset($data);
}
$i++;
unset($dataRow);
}
}
Finaly I have to loop the Stack and build in mulitiple Insert in the method "executeInsert", to create a query like this:
INSERT INTO [myTable] (field1, field2) VALUES ('data1', 'data2'),('data2', 'datta3')...
That works much better. I still have to check the best balance, but therefor i can change only the value '210' in the code above. I hope that help's everybody with a similar problem.
Attention: Don't forget to execute the method "executeInsert" again after readin the complete file, because it could happen that there are still some data in the stack and the method will only be executed when the stack reach the size of 210....
Greetz
V
I think your bottleneck is not reading the file. Which is a text file. Your bottleneck is the INSERT in the SQL table.
Do something, just comment the line that actually do the insert and you will see the difference.
I had this same issue in the past, where i did exactly what you are doing. reading a 5+ million lines CSV and inserting it in a Mysql table. The execution time was 60 hours which is
unrealistic.
My solutions was switch to another db technology. I selected MongoDB and the execution time
was reduced to 5 minutes. MongoDB performs really fast on this scenarios and also have a tool called mongoimport that will allow you to import a csv file firectly from the command line.
Give it a try if the db technology is not a limitation on your side.
Another solution will be spliting the huge CSV file into chunks and then run the same php script multiple times in parallel and each one will take care of the chunks with an specific preffix or suffix on the filename.
I don't know which specific OS are you using, but in Unix/Linux there is a command line tool
called split that will do that for you and will also add any prefix or suffix you want to the filename of the chunks.

PHP: Taking Array (CSV) And Intelligently Returning Information

Hey Everyone. I'm a first time poster, but I've browsed this site a number of times. I have a coding issue that I'm not sure exactly how to solve. First I'll explain what I need to do, and what information I have, and I hope somebody can give me a nudge in the right direction.
What I have is a spreadsheet (CSV) that has the following info: Zone Name, Zip Code, City Name. One zone should have many cities that fall under it, and every city most likely has many zip codes that fall under it. For example:
Zone H, 92603, Irvine
Zone H, 92604, Irvine
Zone J, 92625, Corona
etc.
Okay, now that that's out of the way, here's what I need to do with this info. I need to be able to input a city name and have it return to me all zip codes that fall under that city, as well as the zone that the city lies in. For example, if I input Chatsworth, it should give me (Zone X) and (12345, 12346, 12347) as the zip codes (just an example).
I'm not sure the best way to go about this. I could create a MySQL database and work from there, or just work from .csv files, or hardcode it into the PHP file. I don't know how to search for a value in an array column, and then return the other columns accordingly (especially with multiple zip codes per city).
If anybody can help me out, it would be greatly appreciated. Also, feel free to let me know if you need more information from me. Thanks in advance to everyone reading.
If you want to pursue the CSV approach, then the first step is reading the file into a 2D array:
$csv = array_map("str_getcsv", file("file.csv"));
Now this is an indexed array, where you need to know which column is which. But if you know the city is always in [2] then searching for the other information becomes simple:
foreach ($csv as $i=>$row) {
if ($row[2] == "Chatsworth") {
$zone = $row[0];
$zip = $row[1];
break;
}
}
Ideally you would put this into a function, so you can call it multiple times. It would be easiest if you make it configurable which column to search, and just have it return the complete found row.
Okay so if you don't know where the $city name is in, then I would propose following utility function:
function search_csv($city) {
global $csv; // pre-parsed array (can be parameter though)
foreach ($csv as $i=>$row) {
if (in_array($city, $row)) {
$result_rows[] = $row;
}
}
return $result_rows;
}
function search_zip($city) {
$rows = search_csv($city);
foreach ($rows as $i=>$row) {
$rows[$i] = end(array_filter($row, "is_numeric"));
}
return $rows;
}
The first one returns a list of $rows which match. I'll leave it up to you how to figure out which column contains which. Only for the zip code it's kind of possible to return the results deterministically.
Zone H, 92603, Irvine
Zone H, 92604, Irvine
Zone J, 92625, Corona
etc.
you can take the file and get all its contents. then split it up by new line:
$searchCity = 'Searched'; //or whatever city you are looking for
$file = file_get_contents('file.csv');
$results = array();
$lines = explode("\n",$file);
//use any line delim as the 1st param,
//im deciding on \n but idk how your file is encoded
foreach($lines as $line){
//split the line
$col = explode(",",$line);
//and you know city is the 3rd element
if(trim($col[2]) == $searchCity){
$results[] = $col;
}
}
and at the end u have an array of the results like this:
$results = array(
array('Zone B', '12345', 'Searched'),
array('Zone Z', '35145', 'Searched'),
array('Zone Q', '12365', 'Searched'),
)

Categories