Why PHP continue to output to CSV file after fclose()? - php

On a web page, I am writing some data into a CSV file using the below code and finally closing with fclose();
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename='.$filename);
$out = fopen('php://output', 'w');
fputcsv($out, $cvs_cols);
fclose($out);
echo "HELLO WORLD"; // sneaks into CSV!?
Why is it that "HELLO WORLD" gets into the CSV download file when it has already fclose()? I want to output the rest of the HTML for the page to be displayed in the browser. How can I do that?

After 1 HTTP request follows 1 response. You cannot send content type text/csv and content type text/html at the same time (maybe yes with SPDY, but not with pure HTTP).
fclose closes your file descriptor but not the output to the browser.
You should also set a Content-Length header and put in the filesize.
Mark Baker already gave the most important point in the comments:
echo and writing to php://output puts content into the same stream: STDOUT. Other options would be to write the CSV to memory (but its senseless if you don't use it) or to a file. Read more about the those streams: http://www.php.net/manual/en/features.commandline.io-streams.php
Possible solution:
You need 2 HTTP requests. 1 For the download, the other for your HTML. Most popular way is it to first use the HTML response and put something in like
<meta http-equiv="refresh"
content="3; URL=http://yourserver.com/download.php?id=pdf&id=123" />
This starts the download after 3 seconds.

There is no 'CSV File' (yet).
What you are doing is sending a data stream to the client, and telling the client that this stream has a Content-Type of text/csv and a filename of $filename. The client can then chose to save this as a CSV file or just display it in the browser.
This code:
$out = fopen('php://output', 'w');
fputcsv($out, $cvs_cols);
fclose($out);
Is effectively doing the same thing that echo $cvs_cols would do (with a little extra stuff to format a csv output).
So when there is a call to echo "HELLO WORLD"; it gets sent in the same data steam as the contents of the $cvs_cols variable.
When you call fopen('php://output', 'w') you are creating a second file handle to php://output as one is created by default to output from calls to echo etc. So when you are calling fclose($out) you're only closing the second file handle.

A very old thread here but to fix this I just added a simple exit(); command. So a button calls the same page with a query string of 'action=export_csv' then that action is run with the exit(); on the last line, hope that helps out.
Export CSV
Then the 'action' on the page is:
if(isset($_GET['action']) && $_GET['action']=='export_csv'){
// output headers so that the file is downloaded rather than displayed
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=email-responses.csv');
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
// output the column headings
fputcsv($output, array('Email address'));
$db = new PDO('mysql:host=hostname_mysql;dbname=database_mysql;charset=UTF8', username_mysql, password_mysql);
$query = "SELECT XXX FROM XXXX";
$result = $db->query($query);
$data = $result->fetchAll(PDO::FETCH_ASSOC);
// loop over the rows, outputting them
foreach($data as $row){
fputcsv($output, $row);
}
fclose($output);
exit();
}

use
ob_clean() : ob_clean — Clean (erase) the output buffer
flush() : flush — Flush the output buffer(flush)
ob_start();
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename='.$filename);
$out = fopen('php://output', 'w');
fputcsv($out, $cvs_cols);
fclose($out);
ob_end_clean(); // the buffer and never prints or returns anything.
echo "HELLO WORLD"; // sneaks into CSV!?

Related

Echoing to screen when using headers to output to csv

I have a PHP application which generates a set of codes , saves them to MySQL DB and then outputs the same to the user as a downloadable csv file. I also have an echo statement after the code block to convert the PHP array to csv. The echo statement after the convert_to_csv function call instead of outputting to the browser outputs to the file instead and overwrites the first line. How do I get the echo statement to output to the browser instead? The code block is below:
convert_to_csv($newCodesArray,$fileName,',');
echo "Your file was successfully generated";
function convert_to_csv($input_array, $fileName, $delimiter)
{
header('Content-Type: text/csv');
header("Content-Disposition: attachment; filename=\"$fileName\"");
$f = fopen('php://output', 'w');
/* loop through array */
foreach ($input_array as $line) {
/* default php csv handler */
fputcsv($f, $line, $delimiter);
}
fclose($f) or die("Can't close php://output");
}
You have already defined the header as text/csv. So it wont print in the browser as it requires text/html.
Alternatively you can do as following. Copy your function to different file (Ex. csv.php).
<?php
echo "Your file was successfully generated <script> window.location = 'csv.php' </script>";
Now it will print your echo string and start download your csv file.
As Magnus Eriksson commented,
Above code does not checking its really generated successfully or not. We can extend code with AJAX.
<script>
$.ajax('csv.php', {
success: function(data) {
document.write('Your file was successfully generated.');
windows.location = 'csv.php';
},
error: function() {
document.write('Your file generation failed.');
}
});
</script>
Note:- AJAX call will generate file two times.

Temporary header for output buffer in PHP

I convert binary data to JPEG. PHP is cool for this, because I need just to send header('Content-Type: image/jpeg;'); and echo my binary.
But I have content above that binary like so:
echo 123;
header('Content-Type: image/jpeg;');
$data = hex2bin($CmnObiektZalacznik[0]->Binaria);
echo $data;
It will of course it will warn with Warning: Cannot modify header information - headers already sent by so i thought it (header and binary JPEG) could be outputed to temporary buffer something like that:
echo 123;
ob_start();
header('Content-Type: image/jpeg;');
$data = hex2bin($CmnObiektZalacznik[0]->Binaria);
echo $data;
ob_end_flush();
But I get to do it?

Exporting a javascript array as CSV

I have a javascript array which i have to save as CSV in client environment..Is that possible using jquery? I have to make in work in all major browsers too..I'm using symfony2 framework..How can this be done if I can pass this array to the server..Please explain the best possible way to pass array as I'm having a pretty large array of associativ arrays..
You can send the data to the server however you'd like (using $_POST, AJAX, etc.). Once the data arrives at the server, though, this is how I would go about sending the data to a CSV file.
$serialized_data = $_POST['some_data_array'];
if($downloadFile) // simple condition
{
$fp = fopen('php://memory', 'w+'); // open up write to memory
foreach($serialized_data as $row) // $serialized_data represents what you sent to the server from JS
{
fputcsv($fp, $row);
}
rewind($fp);
$csvFile = stream_get_contents($fp);
fclose($fp);
header('Content-Type: text/csv');
header('Content-Length: '.strlen($csvFile));
header('Content-Disposition: attachment; filename="yourFile.csv"');
exit($csvFile);
}

reading a large file and forcing download

$name = 'mybigfile.csv';
$fp = fopen(...);
while($row = mysql_fetch_assoc($sql_result)) {
fputcsv($fp, $row);
}
fclose($fp);
// send the correct headers
header("Content-Type: application/csv etc ....");
header("Content-Length: " . filesize($name));
// dump the file and stop the script
readfile($name);
exit;
this method works fine but some of the files are quite big so which makes it quite slow process ... I was thinking - maybe if I could avoid the process of creating a file first and then write data and THEN read the data and output .... .i.e. if I send headers before the while loop and echo line in the while loop (instead of writing it in a line) or something like this. Would this be more efficient process? What would you suggest me to improve this process? thanks
Write directly to the output:
header("Content-Type: application/csv etc ....");
while ($row = mysql_fetch_assoc($sql_result)) {
fputcsv(STDOUT, $row);
}
See here for reference: http://www.php.net/manual/en/wrappers.php.php

fputcsv Inserting HTML code into a csv file

I have problem with writing csv file using fputcsv. Its putting the page html also into the csv file. Whats wrong with my code ?
//Excel header
header("Content-Disposition: attachment; filename=\"Delivery_Reports.csv\";" );
header("Content-type: application/vnd.ms-excel");
$out = fopen("php://output", 'w');
$flag = false;
// $result = mysql_query("SELECT * FROM senderids ") or die('Query failed!');
//$sel="SELECT number as MobileNumber ,snum as Sender , msg as Subject ,crdate as Date ,status FROM savemsg WHERE userID='".$_SESSION['id']."' ".$str." ORDER BY sn DESC ";
$result = mysql_query("SELECT `count`, `dnd`, `credit`, `sender_id`, `to`, `message`, `status` FROM `reports` WHERE `unq_id` = '$dlr_id'");
while(false !== ($row = mysql_fetch_assoc($result))){
if(!$flag){
$list = array(
"Total"=>"Total",
"DND"=>"DND",
"Credits"=>"Credits",
"From"=>"From",
"To"=>"To",
"Message"=>"Message",
"Status"=>"Status"
);
// display field/column names as first row
fputcsv($out, array_keys($list), ',', '"');
$flag = true;
}
// array_walk($row, 'cleanData');
fputcsv($out, array_values($row), ',', '"');
}
fclose($out);
You can't guarantee, from within a snippet of code, that nothing else will be output. If the code before this snippet is using output buffering, you can discard the HTML using ob_end_clean. If the code after this snippet is causing the problem, you can simply call die to keep it from running at all. However, if the code before this snippet is outputting HTML directly to the browser, or the code after it outputs HTML and absolutely has to run, then you'll have to modify that code in order to solve your problem.
As Tim mentioned, print, echo and outputting to the pseudo-file php://output do exactly the same thing.
You can also use the keyword continue just before you close the file (fclose($f);). This also works lovely.
You can also use exit; after fclose($out); which stopped the output from scraping my html.
I know it's an old question but it gets found in Google so adding this.
If the HTML is being output by the CMS such as WordPress etc. before you try to create the file, it might help to add ob_clean(); and ob_start(); before you output the header.
For example:
function create_csv($records, $columns){
ob_clean();
ob_start();
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="Export.csv"');
$fp = fopen('php://output', 'w+');
// Generate the file content.
fclose($fp);
die();
}

Categories