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.
Related
I am trying to make a file manager with php , so when I open it in browser it would give a list of the current directory and the file would be clickable using the anchor tag in html (which I have done so far) , and when the file is clicked , it would open it in the text mode and shows whatever the source code inside the file is.
I am facing two problems which I couldn't figure out
Problem #1:
The first problem is that I want my file manager to read any source code weather its an image or pdf , just like the tinyfilemanager that I found here this master piece can read any file, even if you open an image with a notepad and insert some php code at the very end of the file it will read render that too, so here's my source code:
<?php
function list_all_files($directory){
//opening the dir
if($handle=opendir($directory.'/')){
echo "looking inside '$directory'"."<br>";
}
while($file=readdir($handle)){
//listing all the directories without ".." (dots)
if($file!='.'&&$file!='..') {
echo ''.$file.'<br>';
} //if ends here
} //while loop endds here
} //list_all_files ends here
function read_file($file)
{
$handle = fopen($file, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
echo($line);
}
fclose($handle);
} else {
echo "error opening the file";
}
}
//main function
if(!isset($_GET['dir'])) {
$dir='images';
}else{
$dir=$_GET['dir'];
}
list_all_files($dir);
if(isset($_GET['read'])){
$file1 = $_GET['read'];
read_file($file1);
}
?>
the above program I made can also read files code but when I click on any PHP file that contains an html code, it just displays it rather than giving its source code in text mode, image below:
and not only this, if I put some php code at the very end of the image file using a notepad it wouldn't display it. check this:
I did a lot of research on why my code isn't working while the tinyFilemanager is perfect with any of the above mention cases , and I found that the whenever I execute the page file via browser it by default uses this
header("Content-Type: text/html");
so If I wanted to do what I wanted , then I would have to use this:
header("Content-Type: text/x-php");
which covers both of the above cases, but leads to the 2nd problem.
Problem #2:
<?php
function list_all_files($directory){
//opening the dir
if($handle=opendir($directory.'/')){
echo "looking inside '$directory'"."<br>";
}
while($file=readdir($handle)){
//listing all the directories without ".." (dots)
if($file!='.'&&$file!='..') {
echo ''.$file.'<br>';
} //if ends here
} //while loop endds here
} //list_all_files ends here
function read_file($file)
{
$handle = fopen($file, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
echo($line);
}
fclose($handle);
} else {
echo "error opening the file";
}
}
//main function
if(!isset($_GET['dir'])) {
$dir=getcwd();
}else{
$dir=$_GET['dir'];
}
//listing all the directories and files in text/html format so that our anchor tag would be available.
ob_start();
header('Content-Type: text/html; charset=UTF-8');
list_all_files($dir);
ob_end_flush();
if(isset($_GET['read'])){
//changing the header to text/php-x so that the php code in any jpg file can be viewed clearly
ob_clean();
header('Content-Type: text/x-php; charset=UTF-8');
ob_start();
$file1 = $_GET['read'];
read_file($file1);
ob_end_flush();
}
?>
The above codes works perfectly fine, but there is this one problem. since its content-type is not text/html anymore, it wouldn't display the html content on the web page. which is good but bad at the same time because then I wouldn't get the list of directory in the anchor tag form, because I thought ob_start and ob_end_flush(). if I use these two, it would just solve the problem by creating a buffer for each of the function separately and executes it. so when it executes it the above function would be render with the content-type text/html and would show the directory listing with anchor tag, and the 2nd would just be in text/x-php which would solve the above two cases, but I was soooooo wrong.
With the grace and help of God , and suggestion from kikoSoftware in the Comments , the Problem is solved, there's a function name show_source(); ,which takes two arguement , the 2nd argument however is optional , hence we don't need to do filing or send a content-type response with the header() function , we can just use that function , source codes are below.
<?php
function list_all_files($directory){
//opening the dir
if($handle=opendir($directory.'/')){
echo "looking inside '$directory'"."<br>";
}
while($file=readdir($handle)){
//listing all the directories without ".." (dots)
if($file!='.'&&$file!='..') {
echo ''.$file.'<br>';
} //if ends here
} //while loop endds here
} //list_all_files ends here
function read_file($file)
{
$handle = fopen($file, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
echo($line);
}
fclose($handle);
} else {
echo "error opening the file";
}
}
//main function
if(!isset($_GET['dir'])) {
$dir=getcwd();
}else{
$dir=$_GET['dir'];
}
//listing all the directories and files in text/html format so that our anchor tag would be available.
list_all_files($dir);
if(isset($_GET['read'])){
//changing the header to text/php-x so that the php code in any jpg file can be viewed clearly
$file1 = $_GET['read'];
show_source($file1);
}
?>
appreciate ya guys for helping out ♥
I'm imagining a user going to page and having a download automatically initiate. The page they visit will have instructions on what to do with the file. Right now, the text of the page is being included in the csv file instead of echoing to the page. Can this even be down in one script? Here is my code...
<?php
function databaseConnection() {
$conn = new PDO("sqlsrv:server=IP ; Database=database",'user','password');
return $conn;
}
function getStudents() {
global $conn;
$studentsql =
"SQL query";
$studentquery = $conn->prepare($studentsql);
$studentquery->execute();
$studentarray = array();
while ($studentrow = $studentquery->fetch(PDO::FETCH_ASSOC)) {
$studentarray[] = $studentrow;
}
return $studentarray;
}
function createFile($fileheader,$filebody) {
$file = fopen('php://memory', 'w');
fputcsv($file, $fileheader);
foreach ($filebody as $key => $students) {
fputcsv($file, $students);
}
rewind($file);
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=data.csv');
fpassthru($file);
fclose($file);
}
$conn = databaseConnection();
$fileheader = array("header1","header2");
createFile($fileheader, getStudents());
$conn = null;
echo "<p>The file has automatically downloaded and was placed in your downloads folder.</p>
<p>Double clicking the file will automatically open it in Excel. You should then go to File | Save As <br>
and choose a different name and save it as an excel file by choosing .xlsx as the file type.";
?>
You have two options:
Display the result on the page and then redirect to the file download.
Use Javascript, load the data through an AJAX request, display it on the page and redirect to a data URI.
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!?
UPDATE:
I used another solution to write my data into a file. It seems that I can't echo data while AJAX is waiting for a response. So I now use fwrite.
$fileHandle = '';
$fileHandle = fopen("export.txt","w");
fwrite($fileHandle, $export);
Original:
Hi there,
maybe my logic is wrong.
I make an AJAX call to get data from another URL.
That worked so far.
But now I want to add an file export also.
$handler = new MyHandler();
// Step 1: get data from URL
$dataAjax = $handler->getData($_POST['data']);
// Step 2: write the data into a text file to provide a download
$handler->writeToText($dataAjax);
echo json_encode($dataAjax);
Now the console shows me a "parserError" because my JSON data contains also the string I wanted to write into the file. That's bad and unwanted.
This below is just a test how I want to write my data into a txt file:
function writeToText($data)
{
header("Content-type: text/plain");
header("Content-Disposition: attachment; filename=export.txt");
header("Pragma: no-cache");
header("Expires: 0");
$title = "";
$title .= "Name,Quantity,Model,Price,Weight,Status"."\n";
echo $title;
}
That is how the error looks like:
{
"readyState": 4,
"responseText": "Name,Quantity,Model,Price,Weight,Status\n[{\"domain\":\"Text\",\"name\":\"Banana\}]",
"status": 200,
"statusText": "OK"
}
parsererror
I have the following code in a PHP page. Some times when I delete the cache2.html file, I expect the php to recreate it and the next person will get the cache2.html instead of executing the php code. I get the following warning some times on the page and no content. Is it because of multiple users accessing the php concurrently? If so, How do I fix it? Thank you.
Warning: include(dir1/cache2.html) [function.include]: failed to
open stream: No such file or directory in
/home/content/54/site/index.php on line 8
<?php
if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler"); else ob_start();
$cachefile = "dir1/cache2.html";
if (file_exists($cachefile)) {
include($cachefile); // output the contents of the cache file
} else {
/* HTML (BUILT USING PHP/MYSQL) */
$cachefile = "dir1/cache2.html";
$fp = fopen($cachefile, 'w');
fwrite($fp, ob_get_contents());
fclose($fp);
ob_flush(); // Send the output to the browser
}
?>
Calls to file_exists() are themselves cached, so it's likely you're getting a return value of true even after the file is deleted. See:
http://us.php.net/manual/en/function.clearstatcache.php
So, you could do:
clearstatcache();
if (file_exists($cache)) {
include($cache);
} else {
// generate page
}
Alternatively, you could do something like this:
if (file_exists($cache) && #include($cache)) {
exit;
} else {
// generate page
}
Or better, if you're deleting the cache file from within a PHP process, then just call clearstatcache() after you delete the file.