Write to .csv file with PHP (Commas in Data Error) - php

I am working on a PHP statement that runs a query and then writes the data to a .csv file. The problem I am having is that some of the data I am receiving from the server has commas in the data which causes for the .csv file to enter data in the wrong place. Below I have an example of the code.
$sql = "Select *
From table;"
$data = mysqli_query($link, $sql);
$row= ("Column One, Column Two, Column Three\n");
while ($result = $data->fetch_assoc()) {
$row .= ("$result[columnOne], $result[columnTwo], $result[columnThree]\n");
}
$fd = fopen("./filePath.csv", "w") or die ("Error Message");
fwrite($fd, $row);
fclose($fd);
Column three is where the data contains commas which causes for it to write to different cells in the .csv file. Is there any solution to make the $result[columnThree] data stay in one cell even though it contains commas in it?

You can wrap the values in double-quotes:
$row .= ('"'.$result['columnOne'].'", "'.$result['columnTwo'].'", "'.$result['columnThree'].'"\n"');
Instead of concatenating a string, I like to use arrays as much as possible:
$rawCsv = array();
while ($result = $data->fetch_assoc()) {
if (count($rawCsv) === 0)
$rawCsv[] = '"'.implode('","', array_keys($result )).'"';
$rawCsv[] = '"'.implode('","', $result ).'"';
}
$csvString = implode("\n", $rawCsv);
Both of these approaches will have a hard time with a different character in your data though -- the double quote. With that in mind, an even better alternative would be to use fopen and fputcsv to create your CSV data and you don't have to think about it.
If you plan to immediately offer the CSV data for download, you don't need a file at all, just dump it into the output butter:
ob_start();
$file_handle = fopen("php://output", 'w');
... if you do want to hang on to a file, then use fopen on the desired output file and skip the call to ob_start
Next, assemble your data:
fputcsv($file_handle, array(
'Your',
'headings',
'here'
));
while ($result = $data->fetch_assoc()) {
fputcsv($file_handle, array(
$result['Your'],
$result['data'],
$result['"here"']
));
}
fclose($file_handle);
... If you're using a file, then you're all set! If you are using the output buffer (no file used), you can grab the CSV data and send it to the browser directly:
$csv = ob_get_clean();
echo $csv; // should send headers first!
Be careful with output buffering, though, some frameworks/applications make use of it internally. If you're running in to problems with it, try using a file. If the file works, then your framework is probably already doing something with the output buffer.
Documentation
RFC 4180 Common Format and MIME Type for Comma-Separated Values (CSV) Files - https://www.rfc-editor.org/rfc/rfc4180
implode - http://php.net/function.implode
fopen - http://php.net/manual/en/function.fopen.php
fclose - http://php.net/manual/en/function.fclose.php
fputcsv - http://php.net/manual/en/function.fputcsv.php
ob_start - http://php.net/manual/en/function.ob-start.php
ob_get_clean - http://php.net/manual/en/function.ob-get-clean.php

Related

How convert a PHP array of associative array to a CSV string using a third composer vendor lib?

I must convert a php associative array to CSV like:
[
["a"=>1, "b"=>2, "c"=>3],
["a"=>5, "b"=>6, "c"=>6],
["a"=>7, "b"=>8, "c"=>9, "d"=>10]
]
must output a string like
a;b;c;d
1;2;3;
4;5;6;
7;8;9;10
I already implement this logic using only foreach and implodes. However CSV has some features like knowing when scape chars and when to quote cells.
I've been used https://www.papaparse.com/ (javascript) a lot for the front-end side.
Is there a Composer package which can do the job?
PS. I need the CVS as string not to save to a file.
You can use fputcsv to get properly formatted CSV, saving to memory and then save it to a variable:
$fh = fopen('php://memory', 'r+');
foreach($array as $row) {
fputcsv($fh, $row); // add other args as needed
}
$csv = stream_get_contents($fh, -1, 0);
//or
rewind($fh);
$csv = stream_get_contents($fh);
You can also use php://temp which will use memory up to a limit and then write to a temporary file or you can generate your own temporary file with tmpfile.

How to filter on a word in a specific column of a csv file with PHP

I'm trying to display only the rows that contain a specific word in a specific column. Basically I would like to show only the rows that have "yes" in the Display column.
First_Name, Last_Name, Display
Kevin, Smith, yes
Jack, White, yes
Joe, Schmo, no
I've been trying various things with fgetcsv & str_getcsv from other answers and from php.net but nothing is working so far.
It doesn't do anything but this is my current code:
$csv = fopen('file.csv', 'r');
$array = fgetcsv($csv);
foreach ($array as $result) {
if ($array[2] == "yes") {
print ($result);
}
}
Let's have a look at the documentation for fgetcsv():
Gets line from file pointer and parse for CSV fields
fgetcsv reads a single line, not the whole file. You can keep reading lines until you reach the end of the file by putting it in a while loop, e.g.
<?php
$csv = fopen('file.csv', 'r');
// Keep looping as long as we get a new $row
while ($row = fgetcsv($csv)) {
if ($row[2] == "yes") {
// We can't just echo $row because it's an array
//
// Instead, let's join the fields with a comma
echo implode(',', $row);
echo "\n";
}
}
// Don't forget to close the file!
fclose($csv);
You should use data tables.
https://datatables.net/examples/basic_init/zero_configuration.html
That's how I deal with my textfiles. But be carefull, with a large amount of Data (> 10000 rows) you should have a loog at the deferRender option.
https://datatables.net/reference/option/deferRender <-- JSON DATA required.

php file() function creates quotation marks and commas

I'm trying to write some php-code that takes $_GET-data as an input and saves it into a csv-file.
When running the code more than once my csv-file looks like this:
Date,Time,Temperature,"Air Humidity","Soil Humidity",Light,"Wind Direction","Wind Speed",Rain
2013-03-16,16:24:27,12,80,40,82,255,10,0
"2013-03-16,16:24:26,12,80,40,82,255,10,0
","""2013-03-16,16:24:26,12,80,40,82,255,10,0
",""",""""""2013-03-16,16:24:25,12,80,40,82,255,10,0
",""","""""",""""
",""",""""""
","""
"
As you can see, the program adds quotation marks and commas into my data that I don't want. This is apparently done by 'file("weather_data.csv")' but I don't know how to disable or work around this.
This is my code for now:
<?php
// Save received data into variables:
$temperature = $_GET["t"];
$airHumidity = $_GET["ha"];
$soilHumidity = $_GET["hs"];
$light = $_GET["l"];
$windDir = $_GET["wd"];
$windSpeed = $_GET["ws"];
$rain = $_GET["r"];
// Arrays for the column descriptor (first line in the csv-file) and the recent data:
$columnDescriptor = array("Date","Time","Temperature","Air Humidity","Soil Humidity","Light","Wind Direction","Wind Speed","Rain");
$recentData = array(date("Y-m-d"),date("H:i:s"),$temperature,$airHumidity,$soilHumidity,$light,$windDir,$windSpeed,$rain);
$fileContents = file("weather_data.csv");
array_shift($fileContents); // removes first field of $fileContents
$file = fopen("weather_data.csv","w");
fputcsv($file,$columnDescriptor);
fputcsv($file,$recentData);
fputcsv($file,$fileContents);
fclose($file);
?>
$fileContents is read as an array of strings, one entry per line of the CSV file but the actual CSV data is not parsed. The last fputcsv tries to write this data as CSV and escapes it (adding quotes and stuff). You need to add the old file contents ($fileContents) to your file with fwrite instead of fputcsv:
fwrite($file, implode("\n", $fileContents));

How to concatenate two strings using fgetcsv and fputcsv?

I'm creating a script that will read a csv file and display it on a textarea using fgetcsv.
$handle = #fopen($filePath, "r");
if ($handle)
{
while (($buffer = fgetcsv($handle, 1000,",")) !== false)
{
foreach($buffer as $buff){
echo $buff."\n";
}
}
}
The format of the csv is
"line1-content1","line1-content2"
"line2-content1","line2-content2"
Using fgetcsv, the content will display inside the textarea without double-quote and comma. Can I format it so that it will also display the duoble quotes and comma?
Then upon saving it using fputcsv
$file_to_load = $_GET['filepath'];
$filePath = $dir.$file_to_load;
$trans = trim($_POST['txtarea']);
$keyarr = split("\n",$trans);
$fp = fopen($filePath, 'w');
foreach (array ($keyarr) as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
Looking on the csv file, it saved the csv but displays it like this
"line1-content1
","line1-content2
","line2-content1
","line2-content2"
It separates the "line1-content1" and "line1-content2" into two lines and put a comma after the end of every line.
Now I want to keep the formatting of #2. How will I code it?
Can you guide me into the right direction? Thanks!
Sounds like you want to display the actual raw CSV text, not the parsed data within the CSV. Instead of using fgetcsv(), just use fgets() and you'll get the text line without any parsing, preserving the quotes and commas.
As for fputcsv, it's going to write out what you pass into it, so make sure that whatever's coming back from the form is cleaned up (e.g. extra line breaks stripped out).

Is there a function that can read a php function post-parsing?

I've got a php file echoing hashes from a MySQL database. This is necessary for a remote program I'm using, but at the same time I need my other php script opening and checking it for specified strings POST parsing. If it checks for the string pre-parsing, it'll just get the MySQL query rather than the strings to look for.
I'm not sure if any functions do this. Does fopen() read the file prior to parsing? or file_get_contents()?
If so, is there a function that'll read the file after the php and mysql code runs?
The file with the hashes query and echo is in the same directory as the php file reading it, if that makes a difference.
Perhaps fopen reads it post-parse, and I've done something wrong, but at first I was storing the hashes directly in the file, and it was working fine. After I changed it to echo the contents of the MySQL table, it bugged out.
The MySQL Query script:
$query="SELECT * FROM list";
$result=mysql_query($query);
while($row=mysql_fetch_array($result, MYSQL_ASSOC)){
echo $row['hash']."<br>";
}
What I was using to get the hash from this script before, when it was just a list of hashes:
$myFile = "hashes.php";
$fh = fopen($myFile, 'r');
$theData = fread($fh, filesize($myFile));
fclose($fh);
$mystring = $theData;
$findme = $hash;
$pos = strpos($mystring, $findme);
The easiest thing to do would be to modify your first php file which echoes everything, along these lines:
change every instance of echo to e.g. $data[] =
at the bottom, do foreach($data as $d) echo $d (this will produce the same result as you have right now)
you now still have your $data array which you can loop through and do whatever you like with it.
To provide working code examples, it would be great if you could post the current code of your file.
EDIT
If you change your script like so:
$query="SELECT * FROM list";
$result=mysql_query($query);
while($row=mysql_fetch_array($result, MYSQL_ASSOC)){
$data[] = $row['hash']."<br />";
}
foreach($data as $d) {
echo $d;
}
...you'll have the array $data that contains each hash in a key. You can then loop through this array like so:
foreach($data as $d) {
//do something
}

Categories