I need to import csv file with php getcsv function but the file is not well formated and cannot import it. After uploading the file, I'd like to delete all " inside the file to have a proper file with ; for each field.
This is an example of my file:
"DENO;NAME;SURNAME;""BIRTH"";""ZIP"";CITY;E-MAIL;TELEPHONE"
"M;DAVID;BON;""1959-02-12 00:00:00"";75009;PARIS;email#gmail.com;010000000"
"M;DOE;JHON;""1947-02-02 00:00:00"";75008;PARIS;email#gmail.com;060000000"
"M;DAVE;Philippe;""1950-01-01 00:00:00"";75002;""PARIS"";email#gmail.com;070000000"
I think I would need to read each line of the file,and maybe use str_replace but I don't know how to write the new file...
Assuming you can get your code into a text string, you can just replace/remove the double-quotes. Then parse the text and get it into a format that will support fputcsv().
When writing the folder, be sure to check that your user has permissions to write to this folder (for example if the parent folder has permissions drwxr-xr-x, you can fix it with chmod g+w folder_name).
<?php
// sample text to parse
$some_text = '"DENO;NAME;SURNAME;""BIRTH"";""ZIP"";CITY;E-MAIL;TELEPHONE"
"M;DAVID;BON;""1959-02-12 00:00:00"";75009;PARIS;email#gmail.com;010000000"
"M;DOE;JHON;""1947-02-02 00:00:00"";75008;PARIS;email#gmail.com;060000000"
"M;DAVE;Philippe;""1950-01-01 00:00:00"";75002;""PARIS"";email#gmail.com;070000000"';
// remove quotes
$final_text = str_replace('"', '', $some_text);
// create array of rows by searching for new lines
$data = str_getcsv($final_text, "\n");
// create an empty array to save our final csv data
$final_csv = array();
// loop thru the array and save to the final csv data
foreach ($data as $value) {
// before saving to final csv data, split row into individual column items
$value_array = explode(";", $value);
$final_csv[] = $value_array;
}
// helper debugger to show data before writing it
echo "<pre>";
print_r($final_csv);
echo "</pre>";
// create a new file for writing or open and truncate to 0
$fp = fopen('file.csv', 'w');
// write to file from final csv data
foreach ($final_csv as $fields) {
fputcsv($fp, $fields);
}
// close file
fclose($fp);
?>
Related
I'm coding a plugin that runs everyday at 5am. It combines multiple csv files (That have a txt extension).
Currently, it is working... HOWEVER, the output format is incorrect.
The input will look like this:
"","","","","email#gmail.com","PARK PLACE 109 AVE","SOME RANDOM DATA","","","",""
And so on. this is only a partial row.
The ouput of this code does not retun the same format. It produces something like this without the " in columns without data
,,,,email#gmail.com,"PARK PLACE 109 AVE","SOME RANDOM DATA",,,,
Here is the part of the function that combines everything:
function combine_and_email_csv_files() {
// Get the current time and date
$now = new DateTime();
$date_string = $now->format('Y-m-d_H-i-s');
// Get the specified directories
$source_directory = get_option('csv_file_combiner_source_directory');
$destination_directory = get_option('csv_file_combiner_destination_directory');
// Load the CSV files from the source directory
$csv_files = glob("$source_directory/*.txt");
// Create an empty array to store the combined CSV data
$combined_csv_data = array();
// Loop through the CSV files
foreach ($csv_files as $file) {
// Load the CSV data from the file
$csv_data = array_map('str_getcsv', file($file));
// Add the CSV data to the combined CSV data array
$combined_csv_data = array_merge($combined_csv_data, $csv_data);
}
// Create the combined CSV file
$combined_csv_file = fopen("$destination_directory/$date_string.txt", 'w');
// Write the combined CSV data to the file
foreach ($combined_csv_data as $line) {
fputcsv($combined_csv_file, $line);
}
// Close the combined CSV file
fclose($combined_csv_file);
}
No matter, what I've tried... it's not working. I'm missing something simple I know.
Thank you Nigel!
So this thread, Forcing fputcsv to Use Enclosure For *all* Fields helped me get there....
Using fputs instead of fputscsv and force "" on null values is the short answer for me. Works beautifully... code is below:
function combine_and_email_csv_files() {
// Get the current time and date
$now = new DateTime();
$date_string = $now->format('Y-m-d_H-i-s');
// Get the specified directories
$source_directory = get_option('csv_file_combiner_source_directory');
$destination_directory = get_option('csv_file_combiner_destination_directory');
// Load the CSV files from the source directory
$csv_files = glob("$source_directory/*.txt");
// Create an empty array to store the combined CSV data
$combined_csv_data = array();
// Loop through the CSV files
foreach ($csv_files as $file) {
// Load the CSV data from the file
$csv_data = array_map('str_getcsv', file($file));
// Add the CSV data to the combined CSV data array
$combined_csv_data = array_merge($combined_csv_data, $csv_data);
}
// Create the combined CSV file
$combined_csv_file = fopen("$destination_directory/$date_string.txt", 'w');
// Write the combined CSV data to the file
foreach ($combined_csv_data as $line) {
// Enclose each value in double quotes
$line = array_map(function($val) {
if (empty($val)) {
return "\"\"";
}
return "\"$val\"";
}, $line);
// Convert the line array to a CSV formatted string
$line_string = implode(',', $line) . "\n";
// Write the string to the file
fputs($combined_csv_file, $line_string);
}
Thank you Sammitch
After much haggling with this problem... Sammitch pointed out why not just concat the files... Simplicity is the ultimate sophistication... right?
*Note: this will only work for my specific circumstance. All I'm doing now is concating the files and checking each file ends with a new line and just plain skipping the csv manipulation.
Code below:
function combine_and_email_csv_files() {
// Get the current time and date
$now = new DateTime();
$date_string = $now->format('Y-m-d_H-i-s');
// Get the specified directories
$source_directory = get_option('csv_file_combiner_source_directory');
$destination_directory = get_option('csv_file_combiner_destination_directory');
// Load the files from the source directory
$files = glob("$source_directory/*.txt");
// Create the combined file
$combined_file = fopen("$destination_directory/$date_string.txt", 'w');
// Loop through the files
foreach ($files as $file) {
// Read the contents of the file
$contents = file_get_contents($file);
// Ensure that the file ends with a newline character
if (substr($contents, -1) != "\n") {
$contents .= "\n";
}
// Write the contents of the file to the combined file
fwrite($combined_file, $contents);
}
// Close the combined file
fclose($combined_file);
I want to be able to read a csv file, decode it with PHP base64_decode() and then write that decoded data to a new file in the same format.
I tried reading the file line by line and then decoding it while it read the file but the data kept coming out corrupt or broken (containing symbols and random characters).
My csv file has only one column of base64 encoded strings with no delimiters. Each string is on its own row and there is only one string per row.
Like so:
ZXhhbXBsZUBlbWFpbC5jb20=
ZXhhbXBsZUBlbWFpbC5jb20=
ZXhhbXBsZUBlbWFpbC5jb20=
ZXhhbXBsZUBlbWFpbC5jb20=
etc...
I want my new file to be in the same format and the same data but it should be decoded.
like so:
example#email.com
example#email.com
example#email.com
example#email.com
etc...
This is how I am reading the data. I tried using trim() inside base64_decode to get rid of any possible white space or characters but it didn't help. I haven't got to the write to csv part yet because I need proper output.
// csv file is uploaded via a form, I move it to the uploads/ directory
$csv_file = $_FILES['file']['name'];
// filename will always be the user uploaded file
$file_name = $csv_file;
// open the file in read
if (($handle = fopen("uploads/".$file_name, "r")) !== FALSE) {
// read the file line by line
while (($data = fgetcsv($handle, 0, ",")) !== FALSE) {
// display column of data
echo base64_decode($data[0]);
}
// close file
fclose($handle);
}
My expected output:
example#email.com
example#email.com
example#email.com
example#email.com
etc...
My actual output:
�XZ�˘��A͡����չ兡��������X\�\�[�\�PXZ�˘��\�\��YM�XZ�˘��G7FWfV�g&GF������6��email#example.com�]�[�ܙ[�XZ�˘��G6ӓ���#T�����6��#7C7##4�����6��ɽ���Ѽ��������兡��������ٜ̌LPXZ�˘��Aɕ�����������email#examplevV�W'6��CCT�����6��v�G7W���d�����6��v���v��&W$�����6��ݥ�����齝兡������wwwemail#exampleemail#exampleۙ�\�MLMP[����]]��NNۚ�XZ�˘��Aщɽݸ������兡������[٘[M�[����Aѡ������͕�٥���
�������ѡ����ѽ�������������[YX���ܝ
Got it working...just needed to auto-detect line endings.
// without this my code breaks, I'm assuming since my csv has no delimiter it was having issues finding the line endings
ini_set('auto_detect_line_endings', TRUE);
// Store each row in this array
$allRowsAsArray = array();
// open file
if (!$fp=fopen("uploads/".$csv_file,"r")) echo "The file could not be opened.<br/>";
// add each row from col into array
while (( $data = fgetcsv ( $fp , 0)) !== FALSE )
{
$allRowsAsArray[] = $data;
}
// decode array line by line, also add linebreaks back in
foreach($allRowsAsArray as $result) {
echo base64_decode($result[0])."\n";
}
<?php
$file = new SplFileObject("data.csv");
while (!$file->eof()) {
echo base64_decode($file->fgetcsv());
}
I have a csv file that looks something like this (there are many more rows):
Jim,jim#email.com,8882,456
Bob,bob#email.com,8882,343
What I want to do is to change all the values in the fourth column,456,343 to 500.
I'm new to php and am not sure how to do this.
I have tried
<?php
$file = fopen('myfile.csv', 'r+');
$toBoot = array();
while ($data = fgetcsv($file)) {
echo $data[3];
$data[3] = str_replace($data[3],'500');
array_push($toBoot, $data);
}
//print_r($toBoot);
echo $toBoot[0][3];
fputcsv($file, $toBoot);
fclose($file)
?>
But it prints
Jim,jim#email.com,8882,456
Bob,bob#email.com,8882,343
Array,Array
not
Jim,jim#email.com,8882,500
Bob,bob#email.com,8882,500
I've looked at this post, PHP replace data only in one column of csv but it doesn't seem to work.
Any help appreciated. Thanks
You can use preg_replace and replace all values at once and not loop each line of the CSV file.
Two lines of code is all that is needed.
$csv = file_get_contents($path);
file_put_contents($path, preg_replace("/(.*),\d+/", "$1,500", $csv));
Where $path is the path and to the CSV file.
You can see it in action here: https://3v4l.org/Mc3Pm
A quick and dirty way to way to solve your problem would be:
foreach (file("old_file.csv") as $line)
{
$new_line = preg_replace('/^(.*),[\d]+/', "$1,500", $line);
file_put_contents("new_file.csv", $new_line, FILE_APPEND);
}
To change one field of the CSV, just assign to that array element, you don't need to use any kind of replace function.
$data[3] = "500";
fputcsv() is used to write one line to a CSV file, not the entire file at once. You need to call it in a loop. You also need to go back to the beginning of the file and remove the old contents.
fseek($file, 0);
ftruncate($file, 0);
foreach ($toBoot as $row) {
fputcsv($file, $row);
}
I have a working system on which I get the data of two .csv file. And save all the data into array and then compare some of the data existing on both csv file. The system works well but later I found out that some of the rows doesn't display on the array. I think I don't use the proper code in reading a csv file. I want to edit/improve the system. This is my code on reading or getting the data from csv file.
$thedata = array();
$data = file("upload/payment.csv");
foreach ($data as $deposit){
$depositarray = explode(",", $deposit);
$depositlist = $depositarray;
$key = md5($depositlist[9] . $depositlist[10]);
$thedata[$key]['payment'] = array(
'name' => $depositlist[0],
'email' => $depositlist[1],
'modeofpayment' =>$depositlist[8],
'depositdate' => $depositlist[9],
'depositamount' => number_format($depositlist[10],2)
);
}
'<pre>',print_r($thedata),'</pre>';
//more code here for comaparing of datas...
1.) What is wrong with file("upload/payment.csv") when reading csv file?
2.) What is the best code in reading a csv file that is applicable on the
system, not changing the whole code. Should remain the foreach loop.
3.) Is fgetcsv much better for the existing code? What changes should be made?
Yes, You can use "fgetcsv" for this purpose.
The fgetcsv() function parses a line from an open file.This function returns the CSV fields in an array on success, or FALSE on failure and EOF.
check the examples given below
eg1 :
<?php
$file = fopen("contacts.csv","r");
print_r(fgetcsv($file));
fclose($file);
?>
eg 2:
<?php
$file = fopen("contacts.csv","r");
while(! feof($file))
{
print_r(fgetcsv($file));
}
fclose($file);
?>
Link : https://gist.github.com/jaywilliams/385876
So I was able to parse the txt file into a csv file
$data = array();
while ($line= fgets ($fh)) {
$stack = array($LAUS,$FIPS,$CountyName,$Date,$_CLF,$_EMP,$_UNEMP,$RATE);
array_push($data, $stack);
}
$file = fopen('file.csv','w');
foreach ($data as $fields) {
fputcsv($file, $fields,',','"');
}
fclose($file);
My question is, what is the best way to create multiple csv files that are seperated by Month (also the year, like Jan01.csv, Jan02.csv).
I'm taking a bit of a guess at the formatting of your date
while ($line = fgets ($fh)) {
// Not sure where you're getting these values, but I'm assuming it's correct
$stack = array($LAUS,$FIPS,$CountyName,$Date,$_CLF,$_EMP,$_UNEMP,$RATE);
// Assuming $Date looks like this '2011-10-04 15:00:00'
$filename = date('My', strtotime($Date)) . '.csv';
$file = fopen($filename,'a+');
fputcsv($file, $stack,',','"');
fclose($file);
}
This will be a little slow since you're opening and closing files constantly, but since I don't know the size of your original data set I don't want to use up all the memory caching the result before I write it.
Be aware that running this multiple times will end up with duplicate data being inserted into your CSV files. You may want to add some code to remove/clear out any currently existing CSV files before you run this bit of code.