I am trying to download table data into a CSV format. The data in one of the fields contains ",".
Eg: Doe, John
When I download the csv file, the data after comma is shifted to next column. But I want the entire data i.e including comma in same column.
The Code I used as follows:
<?php
include('dbconfig.php');
//header to give the order to the browser
header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename=download.csv');
//select table to export the data
$sql ="SELECT * FROM tablename";
$select_table=mysqli_query($db, $sql);
$rows = mysqli_fetch_assoc($select_table);
if ($rows)
{
getcsv(array_keys($rows));
}
while($rows)
{
getcsv($rows);
$rows = mysqli_fetch_assoc($select_table);
}
// get total number of fields present in the database
function getcsv($no_of_field_names)
{
$separate = '';
// do the action for all field names as field name
foreach ($no_of_field_names as $field_name)
{
if (preg_match('/\\r|\\n|,|"/', $field_name))
{
$field_name = '' . str_replace('<em>', '', $field_name) . '';
}
echo $separate . $field_name;
//sepearte with the comma
$separate = ',';
}
//make new row and line
echo "\r\n";
}
?>
Can someone help me get through this issue.
Thanks
Make sure you escape the ,. Typically values that contain sensitive characters (such as , and \n) are surrounded in ".
So your output can be:
"Doe, John",52,New York
You can either write your own escape function or use PHPs fputcsv. It writes to a file handler that's a bit inconvenient but you can make it stdout.
$handle = fopen("php://stdout");
fputcsv($handle, array("Doe, John", 52, "New York"));
Related
I am using phpoffice/phpspreadsheet to process .xlss the file.
As the columns order in the file may varry depending on the file sender I have a table in database, where I store the sender name (in cirilic) and the number of columns for the rest of data.
So, before processing the file I need to compare if the sender name from database is the same as the content of a field in the file to get the coresponded columns values and process the file only if name values match.
Despite the fact, that I am 100% sure they are the same, whatever comparison I try return false.
1. File processing
$allowedFileType = [
'application/vnd.ms-excel',
'text/xls',
'text/xlsx',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
];
$targetPath = './tmp/' . $_FILES['file']['name'];
move_uploaded_file($_FILES['file']['tmp_name'], $targetPath);
$filename = $_FILES['file']['name'];
$error = 0;
//Check if file is already uploaded
if (!empty($importFromFile->getImportedFileName($filename))) {
setEventMessages($langs->trans('FileExists'), null, 'errors');
$error++;
}
if (!$error) {
$Reader = new Xlsx();
$spreadSheet = $Reader->load($targetPath);
$excelSheet = $spreadSheet->getActiveSheet();
$spreadSheetAry = $excelSheet->toArray();
$sheetCount = count($spreadSheetAry);
foreach ($externalsales->getImportSettings() as $obj) {
$name1 = $obj->ref; //This is the name from the database
$name_row = $obj->distributor_name_row - 1;
$name_column = $obj->distributor_name_column - 1;
$name2 = $spreadSheetAry[$name_row][$name_column]; //this is the name from the file
//At this point, I need to compare returned names from database to the name in the file
}
}
2. Compare
print $name1 . ' - ' . $name2;
//returns ДЕЛИВЪРИ ООД - ДЕЛИВЪРИ ООД
//You can see they are same
print strcasecmp($name1, $name2);
print strcasecmp(trim($name1), trim($name2));
print strcasecmp(mb_strtolower($name1), mb_strtolower($name2));
//all 3 return "176"
print strcmp($name1, $name2);
print strcmp(trim($name1), trim($name2));
print strcmp(mb_strtolower($name1), mb_strtolower($name2));
//all 3 return "1"
print strcoll($name1, $name2) . '<br>';
//returns "1"
$coll = collator_create( 'bg_BG' );
$res = collator_compare( $coll, $name1, $name2 );
print $res;
//returns "1"
For the test, I have inserted second record in the database with random name that I am not sure is in the files.
For the first 3 options, the return is 32,32,-176, for the second 3 is 1,1,-1, 1 for strcoll and -1 for the collator.
Any help appreciated.
To check what was causing the error, I've used bin2hex() for both values. The result showed that there were some white spaces (I presume the 20 stand for space as %20 in html) in the string coming from the .xls file.
The output was:
print bin2hex($name1)
//d094d095d09bd098d092d0aad0a0d09820d09ed09ed094
print bin2hex($name1)
//d094d095d09bd098d092d0aad0a0d0982020d09ed09ed0942020
So when I strip those white spaces with str_replace(' ', '', $name1); the if condition if ($name1 === $name2) returns true, which is what I was looking for.
If anyone can explain the reasons for this difference better than me feel free to reply.
I am trying to export data from MySQL to CSV using PHP from a website. When a user clicks generate the report it will automatically create and this will be downloaded as a file on their computer. The code below I have been following an online tutorial but I have run into some issues. Currently, it will download but will only show one row with one date value from the MySQL data.
I was wondering what I need to do to show all the data in the csv file and how do I ensure that the names of the Rows are printed as well.
#header("Content-Disposition: attachment; filename=record.csv");
$select = "SELECT * FROM DBtable WHERE user_id=$id";
$result2 = $conn->query($select);
while ($row = $result2->fetch_assoc()) {
$data = $row['pain']."\n";
$data = $row['sleep']."\n";
$data = $row['mood']."\n";
$data = $row['heartrate']."\n";
$data = $row['time_of_entry']."\n";
}
echo $data;
exit();
Instead of setting the $row values to $data, you should echo instead
#header("Content-Disposition: attachment; filename=record.csv");
$select = "SELECT * FROM DBtable WHERE user_id=$id";
$result2=$conn->query($select);
while($row=$result2->fetch_assoc()){
echo $row['pain']."\n";
echo $row['sleep']."\n";
echo $row['mood']."\n";
echo $row['heartrate']."\n";
echo $row['time_of_entry']."\n";
}
exit();
Your code just keeps setting $data to a rows value, without actually doing anything with it. Each line overwrites the previous, so when you do echo $data, you are echoing the last value it was set to which in your case was the last loops "time of entry" value.
As for adding "names of the Rows", currently the code puts in a value then a new line. You probably want to replace "\n" with ",", so one loops data is one one line, then before the closing while loop, echo a "\n" to insert a new line character. You can then put the titles in the same way, using an echo, and comma seperated titles, followed by a new line character.
For example
echo $row['pain'].",";
echo $row['sleep'].",";
echo $row['mood'].",";
echo $row['heartrate'].",";
echo $row['time_of_entry'].",";
echo "\n";
Everything works perfectly but I've encountered a problem when I'm exporting data to a CSV file. I tried searching for similar problems but I didn't quite find any that could be relevant to my problem.
This code here is supposed to export the whole database table from mySQL database. It does it perfectly but the thing is, it puts all the data in the first column - in different cells.
The cell placement is alright but it's supposed to spread the data over several columns (13 in my case).
Here's the screenshot to explain what's happening:
Code:
<?php
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: filename=export.csv");
#$query=mysql_query("set names 'utf8'");
#mb_http_output('UTF-8');
#mb_http_input('UTF-8');
#mb_language('uni');
#mb_regex_encoding('UTF-8');
#ob_start('mb_output_handler');
#header('Content-type: text/html; charset=utf-8');
$conn = mysql_connect('localhost', 'root', 'asdasd') or die(mysql_error());
mysql_select_db('nooruse', $conn) or die(mysql_error($conn));
$query = sprintf('SELECT osakond as Osakond, soetusaasta as Soetusaasta, it_number as IT_Number, tooteruhm as Tooteruhm, mudeli_nimetus as Mudeli_nimetus, sn as SN, riigivara_nr as Riigivara_nr, inventaari_nr as Inventari_nr, maja as Maja, ruum as Ruum, vastutaja as Vastutaja, markus as Markus,kasutajanimi as Kasutajanimi FROM norse5_proov');
$result = mysql_query($query, $conn) or die(mysql_error($conn));
$row = mysql_fetch_assoc($result);
if ($row) {
echocsv(array_keys($row));
}
while ($row) {
echocsv($row);
$row = mysql_fetch_assoc($result);
}
function echocsv($fields)
{
$separator = '';
foreach ($fields as $field) {
if (preg_match('/\\r|\\n|,|"/', $field)) {
$field = '"' . str_replace('"', '""', $field) . '"';
}
echo $separator . $field;
$separator = ',';
}
echo "\r\n";
}
Thanks in advance.
The problem is you are assuming that Excel knows that a semicolon is the separator.
For some machines this might work, others not.
It was suggested this has to do with regional setting in the control panel under List Separator.
I found a suggestion to add the following as the first line of the CSV to tell excel what separator to use:
sep=;
Haven't tried this, but it seems legit.
Here is a link to a better description (see the 3rd comment down for the way to set the separator in the CSV file to avoid client computer changes):
Trouble with Opening CSV Files with Excel? The Comma and Semicolon Issue in Excel due to Regional Settings for Europe
I am exporting content from an MySQL database to a Word Template (RTF) via PHP.
There is a section, "Appendix B", which should display all the Acronyms found for a record. The minimum records to appear for this section is 90 (i.e. these are standard acronyms (tblAcronyms) that each record will have); however the maximum records are unknown since users can add to this listing (tblAppendixB).
The Word (i.e. RTF) document should display all the records found, however, it is only displaying the first record.
This is what I have thus far:
<?php
....
#Retrieve Appendix B records
$qry_get_AppB = "SELECT vAcronym, vAcronymDesc FROM tblAcronyms
UNION SELECT vAcronym, vAcronymDesc FROM tblAppendixB
WHERE fkID = ". $i_fk_id . " ORDER BY vAcronym ASC";
$qry_appb_result = mysql_query($qry_get_AppB);
$qryAppBno_rows = mysql_num_rows($qry_appb_result);
//Generate the headers to help a browser choose the correct location
header('Content-Type: application/msword');
header('Content-Disposition: inline; filename="'.$vProgramName.'_rec.rtf");
//Open the template file
$tfilename = 'Appb_Template.rtf';
$fp = fopen($tfilename, 'r');
//Read the template into a variable
$toutput = fread($fp, filesize($tfilename));
fclose($fp);
//Replace the place holders in the template with data
if($qryAppBno_rows > 0)
{
while($rowAppB = mysql_fetch_array($qry_appb_result))
{
$vAppB = $rowAppB['vAcronym'] . '-' . $rowAppB['vAcronymDesc'] . "\r\n";
$toutput = str_replace('<<vAppB>>', $vAppB, $toutput);
}
}
//Send the generated document to the browser
echo $toutput;
?>
I have searched this forum and others but have yet to find a solution.
Any assistance is greatly appreciated.
Okay, I'm not quite sure what your template looks like, but I guess, you only have 1 place holder named <<vAppB>>. In your 1st iteration (if there is any data available) you replace that placeholder with your 1st data entry. In this fact only one placeholder is shown.
May rewrite your code to something similar to this
... //do your stuff
$newLine = "\r\n";
$appendix = "";
while($rowAppB = mysql_fetch_array($qry_appb_result)) {
$appendix .= $rowAppB['vAcronym'] . '-' . $rowAppB['vAcronymDesc'] . $newLine;
}
$toutput = str_replace('<<vAppB>>', $appendix, $toutput);
...//do some other stuff
Just simple prototyping, so you may have to do some additional work.
The trick is to collect all entries you got and than replace it with your placeholder :)
I resolved the problem; I had to use "\par" instead of "\r\n" for MS Word (RTF) to recognize it as a paragraph mark. Here is the modified code that now works:
<?php
....
$t_newline = "\par";
#Retrieve Appendix B records
$qry_get_AppB = "SELECT vAcronym, vAcronymDesc FROM tblAcronyms
UNION SELECT vAcronym, vAcronymDesc FROM tblAppendixB
WHERE fkID = ". $i_fk_id . " ORDER BY vAcronym ASC";
$qry_appb_result = mysql_query($qry_get_AppB);
$qryAppBno_rows = mysql_num_rows($qry_appb_result);
//Generate the headers to help a browser choose the correct location
header('Content-Type: application/msword');
header('Content-Disposition: inline; filename="'.$vProgramName.'_rec.rtf");
//Open the template file
$tfilename = 'Appb_Template.rtf';
$fp = fopen($tfilename, 'r');
//Read the template into a variable
$toutput = fread($fp, filesize($tfilename));
fclose($fp);
//Replace the place holders in the template with data
if($qryAppBno_rows > 0)
{
while($rowAppB = mysql_fetch_array($qry_appb_result))
{
$vAppendixB[] = $rowAppB['vAcronym'] . '-' . $rowAppB['vAcronymDesc'] . $t_newline;
$vAppB = implode(" ", $vAppendixB);
}
}
$toutput = str_replace('<<vAppB>>', $vAppB, $toutput);
//Send the generated document to the browser
echo $toutput;
?>
Hopefully this will help someone else. :-)
I'm trying to convert some MYSQL querys to MYSQLI, but I'm having an issue, below is part of the script I am having issues with, the script turn a query into csv:
$columns = (($___mysqli_tmp = mysqli_num_fields($result)) ? $___mysqli_tmp : false);
// Build a header row using the mysql field names
$rowe = mysqli_fetch_assoc($result);
$acolumns = array_keys($rowe);
$csvstring = '"=""' . implode('""","=""', $acolumns) . '"""';
$header_row = $csvstring;
// Below was used for MySQL, Above was added for MySQLi
//$header_row = '';
//for ($i = 0; $i < $columns; $i++) {
// $column_title = $file["csv_contain"] . stripslashes(mysql_field_name($result, $i)) . $file["csv_contain"];
// $column_title .= ($i < $columns-1) ? $file["csv_separate"] : '';
// $header_row .= $column_title;
// }
$csv_file .= $header_row . $file["csv_end_row"]; // add header row to CSV file
// Build the data rows by walking through the results array one row at a time
$data_rows = '';
while ($row = mysqli_fetch_array($result)) {
for ($i = 0; $i < $columns; $i++) {
// clean up the data; strip slashes; replace double quotes with two single quotes
$data_rows .= $file["csv_contain"] .$file["csv_equ"] .$file["csv_contain"] .$file["csv_contain"] . preg_replace('/'.$file["csv_contain"].'/', $file["csv_contain"].$file["csv_contain"], stripslashes($row[$i])) . $file["csv_contain"] .$file["csv_contain"] .$file["csv_contain"];
$data_rows .= ($i < $columns-1) ? $file["csv_separate"] : '';
}
$data_rows .= $this->csv_end_row; // add data row to CSV file
}
$csv_file .= $data_rows; // add the data rows to CSV file
if ($this->debugFlag) {
echo "Step 4 (repeats for each attachment): CSV file built. \n\n";
}
// Return the completed file
return $csv_file;
The problem I am having is when building a header row for the column titles mysqli doesn't use field_names so I am fetching the column titles by using mysqli_fetch_assoc() and then implode() the array, adding the ,'s etc for the csv.
This works but when I produce the csv I am deleting the first data row when the header is active, when I remove my header part of the script and leave the header as null I get all data rows and a blank header (As expected).
So I must be missing something when joining my header to array to the $csv_file.
Can anyone point me in the right direction?
Many Thanks
Ben
A third alternative is to refactor the loop body as a function, then also call this function on the first row before entering the loop. You can use fputcsv as this function.
$csv_stream = fopen('php://temp', 'r+');
if ($row = $result->fetch_assoc()) {
fputcsv($csv_stream, array_keys($row));
fputcsv($csv_stream, $row);
while ($row = $result->fetch_row()) {
fputcsv($csv_stream, $row);
}
fseek($csv_stream, 0);
}
$csv_data = stream_get_contents($csv_stream);
if ($this->debugFlag) {
echo "Step 4 (repeats for each attachment): CSV file built. \n\n";
}
// Return the completed file
return $csv_data;
As this basically does the same thing as a do ... while loop, which would make more sense to use. I bring up this alternative to present the loop body refactoring technique, which can be used when a different kind of loop doesn't make sense.
Best of all would be to use both mysqli_result::fetch_fields and fputcsv
$csv_stream = fopen('php://temp', 'r+');
$fields = $result->fetch_fields();
foreach ($fields as &$field) {
$field = $field->name;
}
fputcsv($csv_stream, $fields);
while ($row = $result->fetch_row()) {
fputcsv($csv_stream, $row);
}
fseek($csv_stream, 0);
$csv_data = stream_get_contents($csv_stream);
if ($this->debugFlag) {
echo "Step 4 (repeats for each attachment): CSV file built. \n\n";
}
// Return the completed file
return $csv_data;
If you can require that PHP be at least version 5.3, you can replace the foreach that generates the header line with a call to array_map. There admittedly isn't much advantage to this, I just find the functional approach more interesting.
fputcsv($csv_stream,
array_map(function($field) {return $field->name},
$result->fetch_fields()));
As you observe, you're using the first row to obtain the field names but then not using the data from the row. Evidently, you need to change your code so that you get both of those things.
There are a number of ways you might do this. The most appropriate one is to use mysqli_fetch_fields() instead to get the field metadata from the result object.
http://www.php.net/manual/en/mysqli-result.fetch-fields.php
Alternatively, you could make the loop lower down in the code a do... while instead of a while.