Remove or Replace last row of a CSV file with PHP - php

I am trying to update last line of a csv file, I get the last line with using this code:
$f = public_path('MYCSV.csv');
$rows = file($f);
$last_row = array_pop($rows);
$data = str_getcsv($last_row);
I searched a lot but did not find any way to replace or at least to remove the last line of csv file, it will be great if do not use foreach loop as the file size is big...

Code: (I don't have Laravel to test on, but I tested with raw php)
$f = public_path('MYCSV.csv');
$rows = file($f);
array_pop($rows); // remove final element/row from $array
file_put_contents($f, implode($rows)); // convert back to string and overwrite file
Now if you want to add a new row to the end of your file, you will just need to push the new data as a comma-separated string (with a trailing newline character) into the $rows array.
If you have a .csv file with this content:
Sally Whittaker,2018,McCarren House,312,3.75
Belinda Jameson,2017,Cushing House,148,3.52
Jeff Smith,2018,Prescott House,17-D,3.20
Sandy Allen,2019,Oliver House,108,3.48
Then $rows array, after the array_pop() call, will be:
array (
0 => 'Sally Whittaker,2018,McCarren House,312,3.75
',
1 => 'Belinda Jameson,2017,Cushing House,148,3.52
',
2 => 'Jeff Smith,2018,Prescott House,17-D,3.20
')
*Notice that the newline characters are not lost when file() is used -- so no "glue" is necessary with implode().
After file_put_contents() is called, the file will be overwritten with:
Sally Whittaker,2018,McCarren House,312,3.75
Belinda Jameson,2017,Cushing House,148,3.52
Jeff Smith,2018,Prescott House,17-D,3.20

<?php try {
$csv_path = 'MYCSV.csv';
$fp = fopen($csv_path, 'r+');
if ($fp) {
$data = array();
while ($row = fgetcsv($fp)) {
$data[] = $row;
}
fclose($fp);
array_pop($data);
$fp = fopen($csv_path, 'w+');
foreach($data as $key => $value) {
fputcsv($fp, $value);
}
} else {
throw new Exception("Failed to open file");
}
} catch (Exception $e) {
echo $e -> getMessage();
}?>

Related

How to sort a CSV file by a column and then sort by a second column, then saving the CSV file

I'm looking to read a CSV export file with PHP. I have access to the File Path Variable called $file_path.
How would I sort the CSV export file by a specific column and then sort it again by a second column? and then save the CSV file to the same file name and file path.
UPDATE:
I got it to read the CSV, then sort it and also save it to the CSV. However, it's also sorting the headers. I am trying to use array_shift and array_unshift but when I use array_shift with a multi-layer array, I am getting an error. (unshift works fine though).
function wp_all_export_after_export($export_id, $exportObj)
{
// Check whether "Secure Mode" is enabled in All Export -> Settings
$is_secure_export = PMXE_Plugin::getInstance()->getOption('secure');
if (!$is_secure_export) {
$filepath = get_attached_file($exportObj->attch_id);
} else {
$filepath = wp_all_export_get_absolute_path($exportObj->options['filepath']);
}
$handle = fopen($filepath, 'r') or die('cannot read file');
$binNumber = array();
$category = array();
$rows = array();
$header = array();
//build array of binNumbers, Categories, and array of rows
while (false != ( $row = fgetcsv($handle, 0, ',') )) {
$binNumber[] = $row[3];
$category[] = $row[1];
$rows[] = $row;
}
fclose($handle);
$header = $rows[0];
array_shift($rows);
//sort array of rows by BinNumber & then Category using our arrays
array_multisort($binNumber,SORT_ASC, $category, SORT_ASC, $rows);
array_unshift($rows,$header);
$file = fopen($filepath,"w");
foreach ($rows as $line) {
fputcsv($file, $line);
}
fclose($file);
}
add_action('pmxe_after_export', 'wp_all_export_after_export', 10, 2);

PHP Parsing file into Array of Array

I have a file with many rows,each row have the following format:
1519382994.85#MSG#Something went wrong
So, for each row i have three field divided by #. A number, a message type and a string.
Now i want to read the file and split the contents.
I made it in this way:
//Opening the logger file
$myfile = file_get_contents("operations.txt", "r") or die("Unable to open file!");
$rows = explode("\n", $myfile);
$num_rows = count($rows);
$fieldList = array();
//Parsing rows using '#'
foreach ($rows as $row => $data) {
$row_data = explode('#', $data);
array_push($fieldList, (string)$row_data[0]);
array_push($fieldList, (string)$row_data[1]);
array_push($fieldList, (string)$row_data[2]);
}
The code is working well but i'd like to have an array of array and this kind of data:
0: Array [ "112323.76", "MSG", "Hello"]
1: Array [ "453435.78", "MSG", "Bye"] etc..
I tryed with this code but i'm doing something wrong.
$last=0;
$result = array();
for ($i = 0; $i < $num_rows; $i++) {
array_push($result, (string) $fieldList[$last], (string) $fieldList[$last+1],(string) $fieldList[$last+2]);
//echo $fieldList[$last].'<br>';
//echo $fieldList[$last+1].'<br>';
//echo $fieldList[$last+2].'<br>';
$last=$last+3;
}
I'm a newbie in PHP someone can help me please and tell me what i'm doing wrong? Tanx a Lot for your time
You could probably make use of the built-in fgetcsv:
array fgetcsv ( resource $handle [, int $length = 0 [, string $delimiter = "," [, string $enclosure = '"' [, string $escape = "\\" ]]]] )
This could look like:
$rows = [];
if (false !== ($handle = fopen("path/to/file", "r")))
{
while (false !== ($row = fgetcsv($handle, 1000, ",")))
{
array_push($rows, $row);
}
fclose($handle);
}
Don't know if it would be a lot faster, but looks a lot easier to me. The main benefits of this over file() and explode() are:
There is no need to have the entire file in RAM at once, processing could be done one row at a time.
it is easy to support other "Character Seperated Values" type files where fields may be quoted ($enclosure)
Just needed some modifications in your code. Added comments to modified lines-
$myfile = file_get_contents("operations.txt", "r") or die("Unable to open file!");
$rows = explode("\n", $myfile);
$num_rows = count($rows);
$finalFieldList = array(); // new array
//Parsing rows using '#'
foreach ($rows as $row => $data) {
$fieldList = array(); // temporary array
$row_data = explode('#', $data);
array_push($fieldList, (string)$row_data[0]);
array_push($fieldList, (string)$row_data[1]);
array_push($fieldList, (string)$row_data[2]);
array_push($finalFieldList, $fieldList); // it will push to final array containing all 3 values
}

deleting matches from text file in php

Consider a txt file of a list of items
qqqqqq
eeeeee
dddddd
hhhhhh
dddddd
hhhhhh
999999
And some of the items in the list are duplicates. how do I output a using php a text file where anything that is duplicated is removed.
the result:
qqqqqq
eeeeee
999999
You can use array_unique
and then right the content back
$file = fopen("filename.txt", "r");
$members = array();
while (!feof($file)) {
$members[] = fgets($file);
}
fclose($file);
$unique_members = array();
$unique_members = array_unique($members);
var_dump($unique_members);
//write the content back to the file
The above solution was for removing the duplicates only and make them unique. Thanks to nhahtdh for pointing it out.
$count_members = array_count_values($members);
foreach($count_members as $key=>$value)
{
if($value == 1)
//write it to the file
}
So you will not need the array_unique stuff
Sorry again
<?php
$file = file_get_contents('file.txt'); //get file to string
$row_array = explode("\n",$file); //cut string to rows by new line
$row_array = array_count_values(array_filter($row_array));
foreach ($row_array as $key=>$counts) {
if ($counts==1)
$no_duplicates[] = $key;
}
//do what You want
echo '<pre>';
print_r($no_duplicates);
file_put_contents('no_duplicates.txt',$no_duplicates); //write to file. If file don't exist. Create it.

PHP read in specific csv file column as an array

I am new to PHP and would like to be able to read in a csv file which has two columns, one is the number (kind of like a ID) then the other holds a integer value. I have looked up the fgetcsv function but I have not been able to find a way to read a specific column from the csv file.
I would like to get all the values from the second column only, without the heading.
Any way of doing this?
This is what I have so far:
$file = fopen('data.csv', 'r');
$line = fgetcsv($file);
And this is some sample data from the csv file:
ID,Value
1,243.00
2,243.00
3,243.00
4,243.00
5,123.11
6,243.00
7,180.00
8,55.00
9,243.00
Any help would be appreciated.
Thanks.
fgetcsv() only reads a single line of the file at a time. You'll have to read the file in a loop to get it all:
$data = array();
while($row = fgetcsv($file)) {
$data[] = $row;
}
The heading you can skip by doing an fgetcsv once outside the loop, to read/trash the header values. And if you only want the second column, you can do:
$data[] = $row[1];
However, since you've got data in there, maybe it might be useful to keep it, plus key your new array with the ID values in the csv, so you could also have:
$data[$row[0]] = $row[1];
and then your nice shiny new array will pretty much exactly match what's in the csv, but as an array keyed by the ID field.
$csv = array_map("str_getcsv", file("data.csv", "r"));
$header = array_shift($csv);
// Seperate the header from data
$col = array_search("Value", $header);
foreach ($csv as $row) {
$array[] = $row[$col];
}
// Iterate through data set, creating array from Value column
$header = fgetcsv($h);
$rows = array();
while ($row = fgetcsv($h)) {
$rows []= array_combine($header, $row);
}
$fp = fopen($filePath, "r+");
$header = fgetcsv($fp);
while ($members = fgetcsv($fp)) {
$i = 0;
foreach ($members as $mem) {
$membersArray[ $i ][ ] = $mem;
$i++;
}
}
$newArray = array_combine($header, array_map("array_filter",$membersArray));
You can also use this class http://code.google.com/p/php-csv-parser/
<?php
require_once 'File/CSV/DataSource.php';
$csv = new File_CSV_DataSource;
$csv->load('data.csv');
var_export($csv->connect());
?>

CSV to Array PHP

I know there are a lot of resources out there for putting a CSV into an associative array, but I can't find anything that helps a noob like me do exactly what I want to do.
I currently have an associative array defined inside my PHP file:
$users = array(
'v4f25' => 'Stan Parker',
'ntl35' => 'John Smith',
);
I would like to move that array into a CSV file (users.txt) so:
v4f25, Stan Parker
ntl35, John Smith
The next step is to import users.txt so I can use it precisely like I was using the array $users.
Any help here? The last code I tried returned this: (which is not what I want)
array(2) {
["v4f25"]=>
string(5) "ntl35"
["Stan Parker"]=>
string(10) "John Smith"
}
What about the following?
$data = array();
if ($fp = fopen('csvfile.csv', 'r')) {
while (!feof($fp)) {
$row = fgetcsv($fp);
$data[$row[0]] = $row[1];
}
fclose($fp);
}
$users = array(
'v4f25' => 'Stan Parker',
'ntl35' => 'John Smith',
);
$fp = fopen('users.txt', 'w');
if ($fp) {
foreach ($users as $key => $value) {
fputcsv($fp, array($key, $value));
}
fclose($fp);
} else {
exit('Could not open CSV file')
}
See: fputcsv()
UPDATE - in the comments you're interested in how to read the file and get your users back out. Here's the return trip:
$users = array();
if (($handle = fopen("my-csv-file.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$users[$data[0]] = $data[1];
}
fclose($handle);
} else {
exit('Could not open CSV file');
}
if (count($users) == 0) {
exit('CSV file empty: no users found');
}
Here's a solution using fputcsv() which flattens the key/value pairs to an array before writing to disk.
$filehandle = fopen("csvfile.csv", "w");
if ($filehandle) {
foreach ($users as $key => $value) {
fputcsv($filehandle, array($key, $value);
}
fclose($filehandle);
}
else // couldn't open file
Try this (assuming your strings contain no commas):
$users = array(
'v4f25' => 'Stan Parker',
'ntl35' => 'John Smith',
);
foreach ($users as $k => $v) {
print "$k, $v\n";
}
Obviously you could then create the CSV file like so:
php above_script.php > outfile.csv
Now, to get from CSV back into an array you could use something like:
$file = 'outfile.csv';
$arr = array();
if (file_exists($file)) {
foreach (explode("\n", file_get_contents($file)) as $l) {
list($k, $v) = explode(',', $l);
$arr[trim($k)] = trim($l);
}
}
print_r($arr, true);
NOTES:
If your strings do (or might) contain commas, then you'll probably want to use a PHP builtin function to decode them - in which case the answers by harald and artlung are useful.
RFC 4180 describes how commas (and other values) are encoded in CSV, in case you want to roll your own CSV encoding/decoding functions for whatever reason.

Categories