Related
I am working on a CSV file upload function. The whole script is working fine and the way I am doing it is by eliminating the first line of the CSV file which is the heading and then using the data only to insert into the database. However, this adds a restriction for the CSV to be sorted always. I need to accept unsorted CSV too. For example, if a column name is in second column and of the CSV file then the array index becomes $arr[1]. Currently, I am using $arr[1] for inserting the values in the database and performing operations. This is bad. If the user uploads an unsorted CSV where name is in 4th column and say phone is in 2nd column where earlier I expected the name to be, then this will disrupt the whole operation. Therefore, how can I use the first heading line and use them as a key like $arr['name'] for performing the required operations?
My current code:
$csvFile = fopen($_FILES['file']['tmp_name'], 'r');
fgetcsv($csvFile);
$arr = [];
while($data = fgetcsv($csvFile, 100, ",")){
$arr['id'] = $data[0]; // WANT TO USE $data['id'] FROM CSV FILE's FIRST LINE
$arr['date'] = date('Y-m-d', strtotime($data[1])); // WANT TO USE $data['date'] FROM CSV FILE's FIRST LINE
$arr['stock'] = $data[2]; // WANT TO USE $data['stock'] FROM CSV FILE's FIRST LINE
$arr['price'] = $data[3]; // WANT TO USE $data['price'] FROM CSV FILE's FIRST LINE
$ar[] = $arr;
}
fclose($csvFile);
How can I get the keys from the file and use it here in the code above?
UPDATE
I see that if I store the keys in array and print it like this
$csvFile = fopen($_FILES['file']['tmp_name'], 'r');
$getFileKeys = fgetcsv($csvFile); // STORED KEYS IN ARRAY
fgetcsv($csvFile);
print_r($getFileKeys);
then I get an array like this:
Array
(
[0] => id
[1] => date
[2] => stock_name
[3] => price
)
I need to write logic in such a way that if I have 4 variables one for each of the element above, then no matter if the index changes for any element, the variable will receive the same value dynamically.
Since you already got the keys inside $getFileKeys variable you can simply use a for loop to loop through the array of keys and dynamically assign the indexes based upon the field.
$getFileKeys = fgetcsv($csvFile);
$keys = [];
for($i = 0; $i < count($getFileKeys); $i++){
if($getFileKeys[$i] == 'id'){
$keys['id'] = $i;
}else if($getFileKeys[$i] == 'date'){
$keys['date'] = $i;
}else if($getFileKeys[$i] == 'stock_name'){
$keys['stock'] = $i;
}else if($getFileKeys[$i] == 'price'){
$keys['price'] = $i;
}
}
while($getData = fgetcsv($csvFile, 100, ",")){
$arr['id'] = $getData[$keys['id']];
$arr['date'] = date('Y-m-d', strtotime($getData[$keys['date']]));
$arr['stock'] = trim($getData[$keys['stock']]);
$arr['price'] = $getData[$keys['price']];
$ar[] = $arr;
}
The $keys array now dynamically stores the indexes for each key. Therefore, this now sorts the CSV file no matter at what order which column is placed in.
You could make variables out of the first line, so that you can call them by her name.
$exampleLine=[
'id' => 1
'date' => '2022-07-01'
'stock_name' => 'stock_name'
'3' => 'price'
];
foreach($exampleLine as $name){
$$name=$name;
}
This will give you the variables with appropriate content, so that $id contains 1, $date '2022-07-01' and so on.
to prevent different spellings, you could still use lcfirst and trim.
PHP-Manual
I need to convert a CSV file into an associative array, using one column as key and another as value. For example, I have this:
Application,Warehouse,Item,UPC,MFUSA Item No.,"PRODUCT DESCR1","PRODUCT DESCR2",Warehouse ID,Qty
INVENTORY:,Muscle Foods USA,1st STEP B12 LIQUID 16oz,673131100064,8890004,1st STEP B12 LIQUID 16oz,CHERRY CHARGE,11,29
INVENTORY:,Muscle Foods USA,1st STEP B12 LIQUID 16oz,673131100316,8890007,1st STEP B12 LIQUID 16oz,TROPICAL BLAST,11,26
INVENTORY:,Muscle Foods USA,1st STEP B12 LIQUID 16oz,673131100064,8890004,1st STEP B12 LIQUID 16oz,CHERRY CHARGE,12,6
I have to use the column UPC as the key and Qty as the value, so that the array looks like..
array(
'673131100064' => '29',
'673131100316 => '26',
'673131100064' => '6',
);
I have tried several solutions found in Google as well as here, but none of them are close to what I need to achieve. This Question was something similar, but it was written in Python.
Sorry for my poor knowledge in PHP. Can you please guide me to the right direction?
With array_map you can parse the csv data and have an array to do as you wish.
Example:
// Parsing the data in csv file
$csv = array_map('str_getcsv', file('path/file.csv'));
/*At this point you already have an array with the data but
* the first row is the header row in your csv file */
//remove header row
array_shift($csv);
$data = [];
//Walk the array and add the needed data into some another array
array_walk($csv, function($row) use (&$data) {
$data[$row[3]] = $row[8];
});
And that's it.
However the data you show as an example has duplicate UPCs. You will overwrite some data if you want an array with the structure 'UPC' => 'Qty' . You can't have duplicate keys in an array.
If what you are looking for is to get the total Qty for each UPCs then you just need to add the already existing Qty with the new one if the UPC key already exists.
// Parsing the data in csv file
$csv = array_map('str_getcsv', file('file.csv'));
//remove header row
array_shift($csv);
$data = [];
//Walk the array and add the needed data into another array
array_walk($csv, function($row) use (&$data) {
$data[$row[3]] = ($data[$row[3]] ? $data[$row[3]] + (int) $row[8] : (int) $row[8]);
});
Or longer but clearer.
//Walk the array and add the needed data into another array
array_walk($csv, function($row) use (&$data) {
if(!empty($data[$row[3]]))
{
$data[$row[3]] += (int) $row[8];
}
else {
$data[$row[3]] = (int) $row[8];
}
});
Explanation in the comments of the code below
$array = [];
// Open file "$file" and checking that it is not empty
if (($handle = fopen($file, "r")) !== false) {
// loop on each csv line, stopping at end of file
while (($data = fgetcsv($handle)) !== false) {
// Excluding header row & checking data is not empty
if ($data[0] !== 'Application' && !empty($data[0])) {
// fgetcsv returns an array, on your example UPC is on key 3 and Qty on key 9
$array[] = [$data[3] => $data[9]];
}
}
fclose($handle);
}
return $array;
Here the keys are hard-coded but maybe you have a way to put it dynamically, it depends of your code & workflow. This is just a simple (I hope) demonstration.
I use the SplfileObject for reading. Then the first line is used as the key for all values. array_column with the column names can now be used for the desired result.
$csv = new SplFileObject('datei.csv');
$csv->setFlags(SplFileObject::READ_CSV
| SplFileObject::SKIP_EMPTY
| SplFileObject::READ_AHEAD
| SplFileObject::DROP_NEW_LINE
);
//Combine first row as key with values
$csvArr = [];
foreach($csv as $key => $row){
if($key === 0) $firstRow = $row;
else $csvArr[] = array_combine($firstRow,$row);
}
$arrQty = array_column($csvArr,'Qty','UPC');
There is a csv file with data about the weather. I am making something which calculates the mean of a column per station from that csv file. That column is passed in the parameters of the function.
First of all I have this list of id's from the weatherstation. The values I add to the list are arrays which contains the sum and count of a datatype.
$station_id = array("960350", "960870", "961090", "961790", "962210", "962370", "962950", "963230",
"965810", "966330", "966850", "967430", "967470", "967490", "967810",
"968050", "968810", "969330", "969350", "969870", "970140", "970480",
"970720", "971200", "971260", "971460", "971800", "971925", "972300",
"972400", "972600", "973000", "973400", "974280", "974300", "975600",
"977240", "977900", "978100", "979000");
//Every item in the array becomes a key, with an array as a value.
//StationID => [sum, count]
$station_id = array_fill_keys($station_id, []);
The function down here reads the lines of the csv file, adds the value if it is there, adds one to the counter, calculates the mean and prints it per station. Finally it clears the values of the array station_id.
function calc_average($to_be_calc){
global $station_id; //array with station_id's as keys. The value is the sum and the count. (0=sum , 1+count)
global $file; //The csv file.
while (($line = fgetcsv($file)) !== FALSE) {
list($STN, $DATE, $TIME, $TEMP, $DEWP, $STP, $SLP, $VISIB, $WDSP, $PRCP, $SNDP, $FRSHTT, $CLDC, $WNDDIR) = $line;
if (is_numeric($STN)) {
$station_id[$STN][0] += $$to_be_calc; //Sums the values of for example temp
$station_id[$STN][1] += 1; //Adds one to the counter of the station.
}
}
foreach ($station_id as $key => $value) {
if ($value[1] > 0) {
//Calculate average
$average = number_format($value[0] / $value[1], 1, ',', ' ');
//print average per station
echo "Average of station $key: $average</br>";
}
}
foreach ($station_id as $key => $value){
unset($key);
}
}
The problem I have now is that when I call it like this:
calc_average("TEMP");
echo "<br>";
calc_average("CLDC");
It prints the averages of the temperature per station twice. Instead of first TEMP, then CLDC. Like this. If I first call calc_average with CLDC as parameter it only does with CLDC.
I have no idea how this is possible. Therefore, my question is how to fix this.
SOLUTION
I didn't rewind the pointer at the end of my function. All I had to do was add rewind($file); to my function. I works great now. Thanks
Placing my answer from the comments in an actual answer:
I am assuming $file is a file pointer obtained using something like fopen(). If so, are you resetting the pointer back to the beginning of the file? If not, $line = fgetcsv($file) will always return false at the start of the second calc_average() call.
I am trying to fill a array with a csv so each field is separate part of the array, when i have filled the array and echo it out it quite literally says array for every enter.
I have a feeling that once i sort the csvfull array that the sku might need to be in loop inside the main processing loop to.
$ocuk = fopen("ocuk.csv", "r");
while (($result = fgetcsv($ocuk)) !== false)
{
$csvfull[] = $result;
}
print_r ($csvfull[0][1]);
$sku="$csvfull[1]";
while (($csv = fgetcsv($ocuk)) !== FALSE)
{
if (false === empty(array_intersect($sku, $csv)))
{
code to display the results from csv that match the $sku variable
}
}
What i need it to do is csvfull array to fill with the contents of the csv such i can then call it into the variable sku to do comparison in next part of the code.
EDIT example of what i mean
csv example
data,data2,data3,data4 etc
data10,data20,data30,data40 etc
the array would then be like this
$csvfull=array() would contain the below
array("data","data2","data3","data4");
array("data10","data20","data30","data40");
then when i call csvfull[1] it display data2 then would go onto data 20 etc
$csvfull is a 2-dimensional array. The first dimension is the rows of the CSV, the second dimension is the columns. So $csvfull[1] is an array containing all the values from the second line of the file. To get the SKU, you need to drill down to the appropriate column, e.g.
foreach ($csvfull as $row) {
$sku = $row[1];
// Do something with $sku
}
If you want to get an array of all the SKUs, you can do:
$sku = array();
foreach ($csvfull as $row) {
$sku[] = $row[1];
}
try like this:
<?php
$ocuk = fopen('clientes.csv','r');
$i=0;
while(!feof($ocuk)){
$values = fgetcsv($ocuk);
if(empty($values[1] )){ // any index which is not empty to make sure that you are reading valid row.
continue;}
$csvfull[$i] = $values;
$i++;
}
print_r($csvfull);
.
fclose($ocuk);
I need to get a count of the first column's values. These ID's might or might not exist in any given .csv file I receive. So I need to loop through the .csv file looking at the first column and either adding it to a holding array ($PWSs) if it doesn't exist or incrementing the count in this holding array if I've already added it.
I have the first loop using fgetcsv()..this works for cracking into the file:
$PWSs = array();
$handle2 = fopen ($uploadfileandpath,"r");
while ($field2array = fgetcsv ($handle2, 130000, ","))
{
// Here is where I would add value or increment $PWSs array
while (?)
{
if ($field2array[0] != ?)
{
// Add or increment
}
}
}
Here is actual data. The first column has IDs for Public Water Systems. I need to count them.
"00513","08/13/2009","090834311A","R","4","OR1000x6","N","N","E",,1,".73","COLILERT"
"00513","08/13/2009","090834312A","R","39","OR1000x6","N","N","E",,1,".35","COLILERT"
"00154","08/13/2009","090835401A","R","300 Falls Road","OR100016","N","N","E",,1,".10","COLILERT"
"95343","08/13/2009","090835601A","R","Room 1 Sink","OR1000x6","N","N","E",,1,,"COLILERT"
"94585","08/14/2009","090837701A","R","Kitchen","OR1000x6","N","N","E",,1,,"COLILERT"
"94704","08/14/2009","090837801A","R","Outside Tap","OR1000x6","N","N","E",,1,,"COLILERT"
"01430","08/14/2009","090838201A","R","100 Deer Park Ln OT","OR1000x6","N","N","E",,1,,"COLILERT"
"00625","08/14/2009","090839001A","R","Dano and N Rose","OR100016","N","N","E",,1,".35","COLILERT"
"00405","08/17/2009","090840301A","R","Westmont Drive","OR100016","N","N","E",,1,".28","COLILERT"
"01031","08/17/2009","090840401A","R","Unit 2 Faucet","OR100016","N","N","E",,1,,"COLILERT"
"00625","08/17/2009","090840601A","R","Luman Road","OR1000x6","N","N","E",,1,".35","COLILERT"
"00513","08/17/2009","090841001A","R","40","OR1000x6","N","N","E",,1,".18","COLILERT"
"00513","08/17/2009","090841002A","R","10","OR1000x6","N","N","E",,1,".16","COLILERT"
$fh = fopen('file.csv', 'rb');
$PWS = array();
while($row = fgetcsv($fh)) {
$PWS[$row[0]]++;
}
Basically it'll populate the PWS using the first column values as keys, and increment them as they come along. Afterwards, given your sample csv above, you'd end up with
$PWS = array(
'00513' => 4
'00154' => 1
'95343' => 1
'94585' => 1
etc...
);
function get_pws()
{
$PWSs = array();
$handle2 = fopen ($uploadfileandpath,"r");
while ($field2array = fgetcsv ($handle2, 130000, ","))
{
if(!in_array($field2array[0], $PWSs))
{
array_push($PWSs, array('key'=>$field2array[0], 'count'=>1));
}
else
{
foreach($PWSs as &$PWS)
{
if($PWS['key'] == $field2array[0])
{
++$PWS['count'];
}
}
}
}
return $PWSs;
}
I haven't actually run and tested this script, so hopefully it works and it's what you're looking for ;)
Edit: Thanks for pointing that out dq. Again, I haven't tested it (not on a machine with PHP installed atm), so hopefully it still works (if it worked in the first place) :P
You only need one while loop. Your outer while loop will stop when it hits the eof, because fgetcsv() will return FALSE.
Then just test for the column to be NULL or "" an empty string. If the column did not exist in the given array, you should use isset() to make sure it exists first in your conditional.