Using PHP, I'm exporting results of a query to CSV. My problem comes when the data contains accent; they are not exported correctly and I lose them all in the generated file.
I used the utf8_decode() function to manually convert the headers and it worked perfectly, but I don't know how to use it for the results array.
Anyone can help me out please!?
result = db_query($sql);
if (!$result) die('Couldn\'t fetch records');
$fp = fopen('php://output', 'w');
if ($fp && $result) {
header("Content-type: application/vnd.ms-excel; charset=UTF-8");
header('Content-Disposition: attachment; filename="adp_enigmes_data.csv"');
header('Pragma: no-cache');
header('Expires: 0');
fputcsv($fp, $headerTitles);
while ($row = $result->fetch_array(MYSQLI_NUM)) {
// When I use utf8_decode here, I don't get any results, so I have
// no idea where to use it!
fputcsv($fp, utf8_decode(array_values($row)), ',', '"');
}
die;
}
Apply utf8_decode to all elements in result row, so simply array_map:
fputcsv($fp, array_map('utf8_decode',array_values($row)), ',', '"');
Related
I'm having a hard time making my CSV export function work.
I've found around plenty of examples using mysqli_* functions, but I'm actually using PDOs so I had to adapt some questions/answers to my needs.
From what I can see, I'm properly parsing and writing data to the *.csv file, but at the end I don't simply get any "Download" modal from the browser.
Again, looking around, I've understood I may have some kind of problem with my headers, so I'm asking for your help.
This is my PHP function snippet:
function downloadAsCSV($dsn, $dbUser, $dbPsw, $options) {
// New PDO connection.
$pdo = pdoConnect($dsn, $dbUser, $dbPsw, $options);
$query = ... // Not going to write it down.
// Let's query the database, ...
$stmt = $pdo->prepare($query);
// Setting up the query variables here...
[...]
// Executing the statement...
$stmt->execute();
// Headers.
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Description: File Transfer');
header("Content-Type: text/csv");
header("Content-Disposition: attachment; filename='export.csv'");
header("Pragma: no-cache");
header("Expires: 0");
// Let's open tbe "*.csv" file where we'll save the results.
$fp = fopen("php://output", "w");
if ($fp) {
$first_row = $stmt->fetch(PDO::FETCH_ASSOC);
$headers = array_keys($first_row);
fputcsv($fp, array_values($first_row));
fputcsv($fp, $headers);
// ... fetch the results...
$workpiecesArray = $stmt->fetchAll();
// ... and, finally, export them.
foreach ($workpiecesArray as $workpiece) {
fputcsv($fp, array_values($workpiece));
}
}
fclose($fp);
// Closing the connection.
$stmt = null;
$pdo = null;
}
function mysqli_field_name($result, $field_offset) {
$properties = mysqli_fetch_field_direct($result, $field_offset);
return is_object($properties) ? $properties->name : null;
}
I've taken inspiration to write the table column titles from this answer.
What you need to do is to print the file, which you're not doing right now.
See this example using readfile:
http://php.net/manual/en/function.header.php#example-5554
Simply put:
1.Replace
$fp = fopen("php://output", "w");
with
$tmpfname = tempnam("/", "");
$fp = fopen($tmpfname, "w");
2.Replace
fclose($fp);
with
fclose($fp);
readfile($tmpfname);
unlink($tmpfname);
and this will work
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="export.csv"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('export.csv'));
readfile($csvFile);
exit;
`put this after` fclose($fp);
I'm creating a function that, when you click on a button, submits datas to a this function and in return, creates a .csv file and makes the browser download it. I followed the huge amount of tutorials that can be found online, but maybe I'm mixing up things:
header("Content-Type: application/x-excel");
header("Content-disposition: attachment; filename=export".date('d-m-Y') .".csv");
header('Expires : 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
$list = array
(
"Peter,Griffin,Oslo,Norway",
"Glenn,Quagmire,Oslo,Norway",
);
$file = fopen("contacts.csv","w");
foreach ($list as $line) {
fputcsv($file,explode(',',$line));
}
die($file);
readfile($file);
Just keep in mind that these aren't my real datas, I just want to set everything up before continuing, because I have 50 lines of an array to handle.
With this code, If I keep die($file), the file gets downloaded but is empty. If I remove it, my browser tells me that the website is unavailable.
What am I missing?
try this
header('Content-Type: application/excel');
header('Content-Disposition: attachment; filename="sample.csv"');
$data = array(
"Peter,Griffin,Oslo,Norway",
"Glenn,Quagmire,Oslo,Norway",
);
$fp = fopen('php://output', 'w');
foreach ( $data as $line ) {
$val = explode(",", $line);
fputcsv($fp, $val);
}
fclose($fp);
This piece of code NEARLY solves my issue saving a query to .csv via php – however I can't understand why when it prompts me to save as export.csv, that file opens blank, while file.csv saves perfectly at the same time with the data I need. I'm sure it's something obvious going on with the headers. Can anyone help?
***EDIT below suggestions got me to this state and it no longer saves a file and prompts for a blank one but now the correct file shows with HTML crap in it. There is no other HTML in this script -- I've tried suggestions from many other posts. How can I solve?
$query = "SELECT * from Table";
$result = mysqli_query($connS, $query);
$headers = $result->fetch_fields();
foreach($headers as $header) {
$head[] = $header->name;
}
$fp = fopen('php://output', 'w');
header('Content-Disposition: attachment; filename="export.csv"');
header('Content-Description: File Transfer');
header('Content-Type: text/csv');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
fputcsv($fp, array_values($head));
while ($row = $result->fetch_array(MYSQLI_NUM)) {
fputcsv($fp, array_values($row));
}
$fp = fopen('file.csv', 'w');
readfile($fp);
fclose($fp);
end();
You're currently only saving the contents to file, not sending it to the user's browser. Perhaps try adding a call to readfile before your die statement.
So your last rows would look like this:
while ($row = $result->fetch_array(MYSQLI_NUM)) {
fputcsv($fp, array_values($row));
}
readfile($fp);
die;
}
Readfile reads a file and writes it to the output buffer. You can find more information on the readfile function here.
Note that the way you're currently doing it(saving to file before the user can download), if two users hit that page simultaneously, they would likely stomp on each others' toes(and create some odd intermix of the two created CSVs). You may want to try simply outputting the CSV contents directly to the user's browser, using the code in the accepted answer there. If you do that after your headers, it should result in the browser treating it like a file to be downloaded.
I am creating a csv file from nested array and it works fine with a download link to the csv file in the localhost, but on live host it won't download. This is what is in my php file:
The headers declared:
/**
* Declare headers for CSV
*/
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=registration.csv");
header("Pragma: no-cache");
header("Expires: 0");
The Function that outputs the csv file:
/**
* Function will output the scsv file
* #param the csv $data in nested array form array(array("","",""),array("",""...)...)
*/
function outputCSV($data) {
$outstream = fopen("php://output", "w");
function __outputCSV(&$vals, $key, $filehandler) {
fputcsv($filehandler, $vals); // add parameters if you want
}
array_walk($data, "__outputCSV", $outstream);
fclose($outstream);
}
The link that I used in local:
Download CSV
Won't work on Live site. Instead of downloading it just takes me to the csv.php page and outputs the array in a string like this.
...ID,"Coach One","Coach Two",Work,Cell,Email,...
Try hardcoding the csv into the code. Replace these lines with the ones you have to see if your data being passed has bad characters. Maybe specifying the charset will help.
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=data.csv');
$output = fopen('php://output', 'w');
fputcsv($output, array('Column 1', 'Column 2', 'Column 3'));
As described here:
http://code.stephenmorley.org/php/creating-downloadable-csv-files/
I'm not setup to really debug your code. You can try this though if you like. I know it works.
$out = fopen("php://temp", 'r+');
while (($row = $res->fetch(Zend_Db::FETCH_NUM)) != false) {
fputcsv($out, $row, ',', '"');
}
rewind($out);
$csv = stream_get_contents($out);
header("Content-Type: application/csv;");
header("Content-Disposition: attachment; filename=\"foo.csv\"");
header("Pragma: no-cache");
header("Expires: 0");
echo $csv;
exit(0);
Adjust the loop as needed to iterate on your results.
First time I've had to do this, but I need to save the results of a query to CSV and create a file on the server, prior to it being passed via SFTP to a remote server. I can successfully create the CSV which is downloaded in the browser, per the code below, but cant seem to get it to save a file on the server. I think I may need file_put_contents? If anyone can suggest a method, or indeed a better approach to sending the outputs via sftp, its much apopreciated.
$result = mysql_query("SELECT * FROM `policy_details` WHERE `policyNumber` = '848938'");
if (!$result) die('Couldn\'t fetch records');
$num_fields = mysql_num_fields($result);
$headers = array();
for ($i = 0; $i < $num_fields; $i++)
{
$headers[] = mysql_field_name($result , $i);
}
$fp = fopen('php://output', 'w');
if ($fp && $result)
{
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="export.csv"');
header('Pragma: no-cache');
header('Expires: 0');
fputcsv($fp, $headers);
while ($row = mysql_fetch_row($result))
{
fputcsv($fp, array_values($row));
}
//die;
}
Immediate thought would be that you don't need to send headers when saving a file. If you are just saving a regular csv file to the local server (and doing the FTP thing separately), I also don't see the benefit of using the 'php://' scheme. I'd use something like
$fp = fopen('/path/to/new/file.csv', 'w+');
if ($fp && $result)
{
while ($row = mysql_fetch_row($result))
{
fputcsv($fp, array_values($row));
}
}
On the other hand, you could save the file directly over FTP, and avoid a 2 stage process.
What I would do is change your php://output file pointer to the file on the server that you want to save to. Move your headers below your while loop, that way you're writing each line from the db to the file. Once you exit your while loop, read the file that you just wrote as one big variable and print echo it with your headers.
$fp=fopen('/path/to/file/on/server/','w');
while ($row = mysql_fetch_row($result))
{
fputcsv($fp, array_values($row));
}
fclose($fp);
$csvFile = fopen('/path/to/file/on/server','r');
$csvData = fread($csvFile,filesize('/path/to/file/on/server');
fclose($csvFile);
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="export.csv"');
header('Pragma: no-cache');
header('Expires: 0');
echo $csvData;
Obviously this isn't the whole script, but these are the pieces I would change to accomplish what you want to do.