Auto skip heading rows in csv File php - php

I am working with an problem that csv file may contain heading so, how can we skip that heading or extra information and skip to main data(csv data)
CSV Data may like :
**Heading 1**
This is some extra text before Data
date: xx-xx-xxxx
country data: A,B,C
*Then here starts the Data(comma separated values)*
Col1,col2,col3,
dataCol1,datacol2,datacol3 ....
so how can we skip to main data and process that data
any help will be appreciated.. as i tried but cant fix it
Thanks

This is by no means a perfect solution, because there are some unknowns in your question - therefore I have to make an of assumption: there will be more rows of csv column data than metadata/header lines. In order to assist in this heuristic, we will also exclude all "empty" lines.
If we can make this assumption then we can do something like the following:
<?php
// define filepath... optionally validate
// with `is_file()` and `is_writable()`
$file = __DIR__ . '/data.csv';
// create an SplFileObject
$csv = new SplFileObject($file);
// set some flags to read file transparently
// as a csv. drop `SKIP_EMPTY` will ignore all
// blank lines as specified above
$csv->setFlags(
SplFileObject::DROP_NEW_LINE |
SplFileObject::READ_AHEAD |
SplFileObject::SKIP_EMPTY |
SplFileObject::READ_CSV
);
// init an empty array to store rows
$rows = [];
// an `SplFileObject` allows iteration
// over its contents with `foreach`.
foreach ($csv as $row) {
// stash each row into a sub-array
// indexed by its length (number of columns)
$rows[count($row)][] = $row;
}
// `max()` will return the biggest sub-array
// which will be the column data according
// to our assumptions stated above
$csvData = max($rows);
var_dump($csvData);
If the contents of $file contained:
**Heading 1**
This is some extra text before Data
date: xx-xx-xxxx
country data: A,B,C
*Then here starts the Data(comma separated values)*
Col1,col2,col3
dataCol1,datacol2,datacol3
dataCol1,datacol2,datacol3
dataCol1,datacol2,datacol3
We should expect the following result:
Array
(
[0] => Array
(
[0] => country data: A
[1] => B
[2] => C
)
[1] => Array
(
[0] => Col1
[1] => col2
[2] => col3
)
[2] => Array
(
[0] => dataCol1
[1] => datacol2
[2] => datacol3
)
[3] => Array
(
[0] => dataCol1
[1] => datacol2
[2] => datacol3
)
[4] => Array
(
[0] => dataCol1
[1] => datacol2
[2] => datacol3
)
)
Which looks pretty good - except... the line country data: A,B,C has been parsed as a valid row, because it also includes two commas. That's the problem with trying to program heuristically. I don't know if this will be a problem in your specific use case. If so, some refinement of the above approach might be required.
References:
SplFileObject()
SplFileObject::setFlags()
max()
Hope this helps :)

You need to find some kind of delimiter or pattern you can use to indicate where the data starts. For example:
Do you know if the header will always be a certain number of lines?
Will it always have a blank line after it like in your example?
etc.
Once you know that, you can test to see if the file contains that pattern/delimiter, and then skip to the csv part.
thanks, but it is uncertain, heading section may be or not present... – Abzkn
That's the trick - you need to find out what conditions would be there if it was present. Then test for those conditions. For example, if you know the header is always 4 lines and the next one is a blank line, you could do something like this:
<?php
$f = file_get_contents($filename); //get everything in the file being processed
$file_lines = explode("\n", $f); //break up each line into an array we can process
$start_line = 0; //assume the header is not present and we'll start processing from line 1
if($file_lines[4] == ''){
//header is present, so start processing from line 5
$start_line = 5;
}
for($l = $start_line;$l < count($file_lines;$l++){
//process each line
}
?>

Related

warning: fputcsv() expects parameter 2 to be array, boolean. when writing to new csv file. php

I have a CSV file called employee_data.csv. It contains employee records formatted like so:
JANE WILLIAMS,6/8/1998,55846874E,4323
PETER JONES,15/01/1982,56897547Q,1234
JAMES O'BRIEN,09/05/2001,25689514W,3432
I want to delete a selected row within the csv file. To achieve this, I will simply copy the 2 rows within the csv file that I do not want to delete to a new_employee_data.csv file and delete the old one.
<?php
$dataSrc = "persistence/employee_data.csv";
$dataDest = "persistence/new_employee_data.csv";
$dataFile = fopen($dataSrc, "r") or die("Unable to open file!");
$outFile = fopen($dataDest, "w") or die("Unable to open file!");
$i=0; //index for the array
while(!feof($dataFile)) {
$csv = fgetcsv($dataFile); //read a line from the CSV file
//$csv = [ANE WILLIAMS,6/8/1998,55846874E,4323];
//add check to remove row
print_r($csv);
if($csv[2] == '55846874E') continue; //skip to next itteration
fputcsv($outFile, $csv);
}
fclose($dataFile);
fclose($outFile);
?>
The code above takes the contents of $dataFile and writes it to $outFile line by line, if the 3rd column = '55846874E' it will skip writing that line. The csv array contains the rows within the employee_data.csv file.
The elements in the $csv array are as follows.
Array ( [0] => JANE WILLIAMS [1] => 6/8/1998 [2] => 55846874E [3] => 4321 )
Array ( [0] => PETER JONES [1] => 15/01/1982 [2] => 56897547Q [3] => 1234 )
Array ( [0] => JAMES O'BRIEN [1] => 09/05/2001 [2] => 25689514W [3] => 8475 )
It removes the first row of the file - JANE WILLIAMS,6/8/1998,55846874E,4323
Now in the new_employee_data.csv is the two undeleted records.
"PETER JONES",15/01/1982,56897547Q,1234
"JAMES O'BRIEN",09/05/2001,25689514W,8475
This is exactly what I want it to do however I received this warning when I run it in the browser:
fputcsv() expects parameter 2 to be array, boolean given in line 25
It's having a problem with fputcsv($outFile, $csv); and I've no idea why, any suggestions of how to fix this?
I would change the while loop So instead of
while(!feof($dataFile)) {
$csv = fgetcsv($dataFile);
like this
while(false !== ($csv = fgetcsv($dataFile))){
You can see an example of this usage on the PHP website here
What probably happens is there is a extra return at the end of the file, so the feof doesn't catch it, and then you get boolean false for the fgetcsv. For example like this (where \n is a new line):
JANE WILLIAMS,6/8/1998,55846874E,4323\n
PETER JONES,15/01/1982,56897547Q,1234\n
JAMES O'BRIEN,09/05/2001,25689514W,3432\n
\n
\eof
So we can combine these (so you wont need the line under the while loop) and just get the data from the same place we do the loop condition, this way when it returns false it will just drop the loop. It's important to be careful with the number of = in this as a single one is assignment and the !== is strict type comparison. So we can break this down a bit and in English what this says.
pull a row and process it with fgetcsv setting $csv to it's value, parentheses get priority
if $csv is boolean false then the loop condition is false an it ends. So basically if false(boolean) not equal to the result of fgetcsv($dataFile) then it's true otherwise it's false.
It would work basically the same like this
while($csv = fgetcsv($dataFile)){
I tend to like the long hand version, because it's easier to see that we are assigning and not comparing. For example you could glance at the above version and then think it should be == instead of = so the first version just makes that a bit more obvious. Putting the false on the left hand side is basically done for the same reason (and because it's essentially a constant, so putting it on the left avoids mistakes like below false = $csv wont work).
Misplacing an = in a condition can actually be one of the harder bugs to figure out, because it's completely legal. So that is kind of a "pro tip" to put function calls and constants on the left when doing comparison.
hope that helps!

PHP - strtok(), associative array relationship

I'm pretty familiar with the Strtok() function in PHP, and I have had no problem getting the function to work properly for strings in the past. However, I currently have to read a .csv text file (which I've done successfully) where each line is made of 6 fields like so: last name, first name, address, city, district, postal code\r\n <--carriage return and linefeed at the end
I have to use Strok() to split these by the delimiters and token the words as fields (i.e. last, first, address, etc.). I plan to use an associative array using the last name as the primary key so that I can plug the data into an HTML Table, which is created and working. My issue right now is splitting the file correctly, as it has about 200 lines made of those 6 fields, and storing the strings as fields properly for an array, so the data structure is where I'm having some issues. Here's what I have so far:
$inputFile = fopen("input.csv","r");
$delimiters = ",";
$token = strtok($inputFile, $delimiters);
$n=1;
while ($token){
echo "Token $n: $token <br>";
$token = strtok($delimiters);
$n++;
}
Obviously, the table is created below it but since I haven't done the data structure quite yet, I don't have the fields for it. I think my token loop may be incorrect for this issue, but I pulled some from an earlier example in my book and an exercise I did where my token process worked but the file structure was different. Thanks for any direction or help on this.
There are CSV functions in PHP, like fgetcsv, so it really is the wrong approach to reinvent the wheel.
Note that in your code you don't actually read the content of the file, as you only get a file pointer.
If you really need to do this with strtok, and your CSV is simple, in the sense that it does not have quoted strings, which could have embedded delimiter characters, you could use:
file_get_contents() to read the file content in one string. Of course, file() would make it easier for you, as it would already split lines. But I assume that if CSV functions are not allowable for you, then this will neither.
strtok for getting the fields, but at the end of the loop, not at the start, since the initial call with the double arguments already retrieves the first value before the loop.
Code:
$input = file_get_contents("input.csv");
$delimiters = ",\n\r";
$token = strtok($input, $delimiters);
$result = [];
$row = [];
while ($token){
echo "Token $token <br>";
$row[] = $token;
if (count($row) == 6) { // write record
$result[] = $row;
$row = [];
}
$token = str_replace('\r', '', strtok($delimiters));
}
print_r($result);
Note that this does not create an associative array. If you need that, then use this code:
$columns = ['last', 'first', 'address1', 'address2', 'address3', 'zip'];
and then in your loop, replace $row[] = $token by:
$row[$columns[count($row)]] = $token;
You can see that version run on eval.in. The output for the data you provided in comments is:
Array (
[0] => Array (
[last] => SELBY
[first] => AARON
[address1] => 1519 Santiago de los Caballeros Loop
[address2] => Mwene-Ditu
[address3] => East Kasai
[zip] => 22025
)
[1] => Array (
[last] => GOOCH
[first] => ADAM
[address1] => 230 Urawa Drive
[address2] => Adoni
[address3] => Andhra Pradesh
[zip] => 2738
)
)
Again, this is not advisable. You should use fgetcsv. That also deals better with strings that could have commas, double quotes or even newlines in them.
Well, I was going to skip this question because fgetcsv(), but I was bored:
$lines = file($inputFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$delimiters = ",";
foreach($lines as $line) {
$values = array(strtok($line, $delimiters));
while($token = strtok($delimiters)){
$values[] = $token;
}
$result[] = $values;
}
Read the file lines into an array
Loop to get each line and put the first token of the line into a values array
Loop the line and get all tokens and add to values array
Add values array to result array
I added an array_combine() because you said something about an associative array. You can use something like this if needed:
$result[] = array_combine(array('last name',
'first name',
'address',
'city',
'district',
'postal code'), $values);
If you wanted last name to be the key for each result line, which is not advisable as keys are unique and I don't think you can guarantee last names being unique:
$result[$values[0]] = $values;
//or to remove it from the array but use as the key
$result[array_unshift($values)] = $values;

PHP storing array column output from a function i call upon multiple times

I am trying to merge two parts of a code. To do that i have to store the echo'd array column output from a function which i call on
multiple times into an array or arrays on which I can perform computations.
Here's what i'm trying to do:
<?php
$searchquery[1] ="jupiter";
$searchquery[2] ="venus";
//can be multiple queries
include ('find.php');
for($i=0;$i<count($searchquery);$i++)
{
find($searchquery[$i]);
}
/find.php echoes back to me a MySQL query which then
creates a 2 dimensional array for me called
/$searchresult which looks like this as an example
t x (let's call first column t for example, and second x)
|1|3|
|1|4|
|2|6|
|4|8|
|7|1|
and it echoes it back to me, this works.
But, i need to use the first column (t) (11247) output from find.php
which was the result of the searchquery "jupiter",
and i need to store it as some sort of array in this current sheet,
theni need to store the "venus" searchquery which is let's say
t x
|1|3|
|2|4|
|3|4|
|4|6|
|5|4|
and store the first column (t) as an array in this current sheet.
I am trying to store the echos from the find.php function as arrays so that
i can perform the following operation in the current sheet:
$venusarrayt = array(1, 1, 2, 4, 7); //the manually defined
//$searchresult first column output from find.php which echos to me (t) (11247)
$jupiterarrayt = array(1, 2, 3,4,5); //the manually defined
//$searchresult first column output from find.php which echos to me (t) (12345)
//I need to perform the following operation and sum all of the t combinations
for($l=0;$l<count($venusarrayt);$l++){
for($s=0;$s<count($jupiterarrayt);$s++){
echo $venusarrayt[$l]+$jupiterarrayt[$s];
This part works! But i am having trouble though merging the echo'd $searchresult output into an array on which i can perform the above
for loops. In this example i am doing it by hand by typing into the php sheet "venusarrayt and jupiterarrayt".
I am sure there is some way to store echo'd array column results from a function which i call upon multiple times into an array, but i
haven't figured out yet how. Please help.
I hope this helps:
<?php
$searchquery[0] ="jupiter";
$searchquery[1] ="venus";
//can be multiple queries
include ('find.php');
$results=null;
for($i=0;$i<count($searchquery);$i++)
{
$temp=find($searchquery[$i]);
$results[$i]=$temp[t];
}
for($l=0;$l<count($results[1]);$l++){
for($s=0;$s<count($results[0]);$s++){
echo $results[1][$l]+$results[0][$s];
}
}
Clear solution for anyway of further working with your searched data can looks something like this:
$searchquery[1] ="jupiter";
$searchquery[2] ="venus";
$search_result = array(); $i=0;
foreach($searchquery as $current_query){
$current_result = FindResul($current_query);
// FindResult will be your function which process single query and returns result of it
$search_result[$i]['query'] = $current_query;
$search_result[$i]['result'] = $current_result;
$i++;
}
After the execution the code above you will have array 2-lvl array with clear and easy to work with structure. You can use it how you'd like to compare data or show it in the way you want.
Resulting array will have such structure:
$search_result[0]['query'] = 'jupiter';
$search_result[0]['result'] = '...jupiter resul';
$search_result[1]['query'] = 'venus';
$search_result[1]['result'] = '...venus result';
You have to create nested array to resolve the issue I would give a little example how to do?
$searchquery[1] ="jupiter";
$searchquery[2] ="venus";
for($i=1;$i<=count($searchquery);$i++){
$temp=find($searchquery[$i]);
$results[$i]=$temp[t];
}
$k=$i;
for($z=0;$z<=$i;$z++){
$total='';
for($p=0;$p<=$k;$p++){
$total=$total+$results[$p][$z];
}
echo $total;
echo "\n";
}
function find($word){
return array('t' => array('1', '2', '4', '7'));
}
and answer would be something like this:
Array
(
[1] => Array
(
[0] => 1
[1] => 2
[2] => 4
[3] => 7
)
[2] => Array
(
[0] => 1
[1] => 2
[2] => 4
[3] => 7
)
)
2
4
8
14
This solution will add all the n number of queries first result, second result and so on.......

Export Subarray and email each section

I have a multidimensional array that is like this:
Array (
[email1#fake.com] => Array (
[0] => Array (
[asin] => B004HFS6Z0
[title] => Kindle, Wi-Fi, Graphite, 6" Display
[price] => 114.00
[map] => 125.00 ) )
[email2#fake.com] => Array (
[0] => Array (
[asin] => B004CYX17O
[title] => Rizzy Home Apple 10-Piece Comforter Set, King
[price] => 502.80
[map] => 520.00 ) ) )
What I am trying to do is export the sub array under the email address into a file, then email it to the email address. So far, I've only been able to export both subarrays into a single file and haven't been able to get it to overwrite the file for the second sub array.
Here is the code I am working with:
require('export-xls.class.php');
$filename = 'email.xls';
$xls = new ExportXLS($filename);
$header[] = "ASIN";
$header[] = "Title";
$header[] = "Retail";
$header[] = "MAP";
$xls->addHeader($header);
//create temp csv file and email from subarray
foreach($map_check2 as $email => $value) {
//$fp = fopen('uploads/email.csv', 'w+');
foreach($value as $subkey => $subvalue) {
//echo $email . "<br>";
//print_r($subvalue) . "<br>";
//fputcsv($fp, $subvalue);
$xls->addRow($subvalue);
}
$xls->emailFile();
}
I need to export it to an excel file and have been using the export-xls.class to do so. I would have used the csv but periodically there will be commas in values in the array.
emailFile() is:
public function emailFile() {
#build the xls
$xls = $this->buildXLS();
$fp = fopen("uploads/email.xls", "w+");
fwrite($fp, $xls);
fclose($fp);
}
Does anyone have any thoughts? Or does that make sense?
It seems in your inner foreach loop, where you are doing $xls->addRow($subvalue), it keeps on adding all email sub-arrays. I think you should call some function inside the outer foreach but before the inner one, to clean the rows that have already been added to $xls.
Here is a test run that I could think of:
first call to the outer foreach is made - $email = email1#fake.com
first call to the inner foearch is made - calls $xls->addrow() for each of the values of the "email1#fake.com" array
first call to $xls->emailFile() is called that opens "email.xls" in w+ mode and writes the contents to the file
second call to the outer foreach is made - $email = email2#fake.com
second call to the inner foearch is made - calls $xls->addrow() for each of the values of the "email2#fake.com" array. Note - I think at this point the rows added earlier to $xls in step 2 still exist and this might be the issue. If yes, you need to some cleanup either before the inner foreach starts or in the $this->buildXLS() method
second call to $xls->emailFile() is called that opens "email.xls" in w+ mode and writes the contents to the file that includes values for both the subarrays.
I'm not sure what is the purpose of $this->buildXLS() and have ignored it for my explanation above.
Does the above make sense?

foreach loop corrupting my array?

Explanation
I have a multidimensional array that is iterated over to created a categorized view of people with different research interests. The main array look something like this:
Array
(
...
['Cell Biology'] => Array(4 elements)
['Molecular'] => Array(6 elements)
['Biology Education'] => Array(14 elements)
['Plant Biology'] => Array(19 elements) <--- Last element in array
)
I know that the entire array is intact and correctly structured. The only information that is inside these array is an user id, like so:
Array ('Plant Biology') 19 elements
(
[0] => 737
[1] => 742
[2] => 748
...
)
My problem is that after i run the main array through a foreach loop the last 'sub-array' gets messed up. By messed up I mean that what you see about instead look like:
String (13 characters) 'Plant Biology'
This is without doing at all anything inside the loop with to the array that gets corrupted.
Any tips to what it might be?
PHP Code
// ---> Array is OK here
echo "<h2>Research divided</h2>";
// Loop areas and list them in 2 columns
foreach($research['areas'] as $area => $areaArray) {
// ---> Here it is already corrupted
$count = count($areaArray);
if($count > 0) {
echo "<h3>$area</h3><hr/>";
echo "<ul>";
// Loop users within areas, divided up in 2 columns
for($i=0 ; $i<$count ; $i++) {
$uid = $areaArray[$i];
echo "<li>$uid</li>";
}
echo "</ul>";
}
}
Are $area or $areaArray being used in different function elsewhere in your script? Wht happens if you rename them to $loop_area and $loop_areaArray to prevent accidental overwriting of variables?
It looks like an error that can occur if you loop over the array previously by referance using the same variable name for the value.
So if earlier in your code $areaArray is used in a foreach by referance it might corrupt your data.
Make sure both variables in your foreach are not used previously or unset them before the loop.
Check out:
http://bugs.php.net/29992
For more info on this kind of problem.

Categories