Jump to content

Problem with downloading files from server


jeffg

Recommended Posts

I have a small database running on an intranet (Apache/MySQL/PHP), which I plan to back up on user request in a simple CSV-formatted text file.In database_backup.php, when the user clicks the Backup button a form is posted to self where I generate the file, set the file name in a session variable and go to download_file.php with the following:

	$_SESSION['download_file'] = $fname;	$_SESSION['backup_done'] = true;		echo "<script TYPE=\"text/javascript\">		document.location.href=\"download_file.php?".SID."\"</SCRIPT>";	exit();

(I use 'backup_done' to switch screens on return from the download, so it just says "Backup complete".)The code for download_file.php starts as follows, followed by normal HTML with an OK button to return to database_backup.php:

<?phpsession_cache_limiter("nocache");session_start();$fname		= $_SESSION['download_file'];$return_to	= $_SESSION['df_call'];// Output the special headersheader("Content-type:text/plain\n");header("Content-Disposition:attachment;filename=$fname\n");readfile("$fname");?>

In Firefox, the save dialog is popped up and the file can be successfully saved. However, the HTML code is appended to the end of the file instead of going to the screen, the address bar remains as database_backup.php, and I have to reload to get my original page (accepting the 'data already posted' warning).In IE7, it doesn't work at all: the file is not presented for saving at all, and it immediately re-shows database_backup.php.(Oh, I do get an information bar first over a blank screen, which gives me the option to download the file, but nothing happens when I choose that.)Can you help, please?IE7 Update: I added the name of my intranet to the intranet sites list (Options/Security/Local Intranet/Advanced) and I now get the dialog and can save the file. However, it now behaves the same as FF: I need to reload, and the HTML is appended to the end of the saved file.

Link to comment
Share on other sites

the download_file.php script should have only the php code that reads the file and sends it to the browser and no html should be included. because of the header (header("Content-Disposition:attachment;filename=$fname\n");) everything that comes from the server will be saved to the file, that's why the html code is appended to the file.Even if the html content would not be appended to the file it will not show correctly, because of this header("Content-type:text/plain\n"); the browser will treat the html content as plain text and and you will se the html tags on the browser instead of what you intended to display.

Link to comment
Share on other sites

Have an HTML page with an iframe on it that points to the download script. They will see the HTML content of the parent page and the iframe will cause a download box to show up. Also, use the mime type application/octet-stream to force a download, some browsers might show the text.

Link to comment
Share on other sites

Just so I've got this right: You are saying I need a third page? In the context of my example, database_backup.php should have new_page.php where it currently has download_file.php, and new_page.php has an iframe in it with src='download_file.php' with other content that I want displayed?(I will try this anyway!)Edit: tried it and a spectacular failure, so I didn't fully understand you. My download_file.php now has the html content and an <iframe src='do_download.php'></iframe>, where do_download.php is the original file with just the headers as shown in the second code box on my OP. The save dialog comes up OK, but it asks to save do_download.php (not my generated file), and if I say yes, the file is created empty.If I replace the iframe src with my generated file name, that is displayed in the frame as text and no dialog appears. (In any case, if I finally get this right, I don't want to see that iframe on my page at all - in the first case I get a bordered frame that takes up real estate on the page. Presumably I can make it borderless and make it very small)

Link to comment
Share on other sites

Just so I've got this right: You are saying I need a third page? In the context of my example, database_backup.php should have new_page.php where it currently has download_file.php, and new_page.php has an iframe in it with src='download_file.php' with other content that I want displayed?
Yeah, that's what I was trying to describe. I have something set up here where clicking on a button causes a request to go out and pretty much do the exact same thing, generate a CSV file to download. In my case it's an ASP page, but that doesn't make a difference.This is the button that runs the function:<input type="submit" onclick="export_comments();" value="Export">The Javascript function is just a simple function that gets some options on the page and sets the src attribute of an iframe. This is the java script:
function export_comments(){  var theurl = "";  theurl = 'export_comments.asp?';  theurl += 'app=' + app_filter;  theurl += '&val=' + val_filter;  theurl += '&res=' + res_filter;  theurl += '&sm=' + sdate_filter.getMonth();  theurl += '&sd=' + sdate_filter.getDate();  theurl += '&sy=' + sdate_filter.getFullYear();  theurl += '&em=' + edate_filter.getMonth();  theurl += '&ed=' + edate_filter.getDate();  theurl += '&ey=' + edate_filter.getFullYear();  theurl += '&sort=' + comment_sort;  theurl += '&dir=' + sort_dir;  if (!nr_comments)	alert('There are no comments to export');  else  {	document.getElementById('file_download').setAttribute("src", theurl);  }}

And the iframe:<iframe id="file_download" width="0" height="0" scrolling="no" frameborder="0"></iframe>The iframe doesn't show up on the page at all, just clicking on the button causes a download box to show up. I use these lines to set the filename and cause the download:Response.ContentType = "application/octet-stream";Response.AddHeader("Content-Disposition", "attachment; filename=\"comments.csv\"");And, after getting information from the database, I use this to output the CSV data:

row = new Array("ID", "Name", "Application", "Location", "Page", "Change Request", "Post Date", "Validated", "Resolution", "Fix Version");output_csv(row);while (!dbcon.eof){  row = new Array;  row.push(dbcon.fields.item("id").value);  row.push(dbcon.fields.item("name").value);  row.push(dbcon.fields.item("title").value + " version " + dbcon.fields.item("version").value);  row.push(dbcon.fields.item("loc").value);  row.push(dbcon.fields.item("page").value);  row.push(dbcon.fields.item("comment").value);  row.push(parseDate(dbcon.fields.item("post_date").value));  row.push(parseDate(dbcon.fields.item("val_date").value) + (dbcon.fields.item("val_date").value == 0 ? "" : " by " + dbcon.fields.item("val_by").value));  row.push(dbcon.fields.item("resolution").value);  row.push(dbcon.fields.item("fix_ver").value);  output_csv(row);  dbcon.movenext();}dbcon.close();function output_csv(ar){  var outval = "";  for (var i = 0; i < ar.length; i++)  {	if (i)	  outval += ",";	outval += "\"";	val = new String(ar[i]);	val = val.split("\"").join("\"\"");	val = val.split("\n").join("  ");	val = val.split("\r").join("");	outval += val;	outval += "\"";  }  outval += "\n";  Response.Write(outval);}

It would be pretty easy to convert the Javascript ASP code to PHP, but that's what I have here.

Link to comment
Share on other sites

  • 3 weeks later...

It's been a while, but I finally came back to this after working on other parts of the project. By following justsomeguy's example, I have finally got backup working successfully on IE7. It prompts to save the generated file (vcwb_yyyymmdd.txt), which it does correctly, and returns properly. Result!However, on Firefox, I also get a save dialog, but similar to an earlier post in this thread, it prompts to save the containing file (download_file.php), which is saved as an empty file.Is this a problem with Firefox, or with me? And is there a way round it?Here is the main code (database_backup.php):

<?php// database_backup.phpsession_cache_limiter("nocache");session_start();require ('connect.inc');require ('db_error.inc');$self   = $_SERVER['PHP_SELF']."?".SID;// Edited to remove specifics$tables = array('table1', 'table2', 'table3', 'etcetera');$posted = $_POST['posted'];$state  = $_POST['state'];		// used to switch between formsif (!$state)	$state = 1;?><?php include ('page_heading.inc');page_heading("db_50.gif", "Backup database", false);?><!-- Start of page body --><iframe id='file_download' width='0' height='0' scrolling='no' frameborder='0'></iframe><?phpif ($posted && ($state == 1)){	// Get the current date and time	$timestamp = mktime();		// Create the file vcwb_yyyyddmm.txt	$fname = "vcwb_".date("Ymd", $timestamp).".txt";	$file = fopen($fname, "w") or die ("Could not create backup file.");	// Write the heading	$s = "-- Backup of vcwb database on ".date("l, j-M-Y", $timestamp);	$s .= " at ".date("H:i:s", $timestamp)."\n";	fwrite($file, $s);	foreach ($tables as $tname)	{		fwrite($file, "*$tname\n");		$query = "select * from $tname";		$rs = mysql_query($query, $conn) or db_error(__FILE__, __LINE__, $query, "");		while ($row = mysql_fetch_row($rs))			fputcsv($file, $row, "|");	}	fwrite($file, "*end\n");	fclose($file);	$_SESSION['download_file'] = $fname;	echo "<script type='text/javascript'>		document.getElementById('file_download').setAttribute('src','download_file.php');		</script>";	$state = 2;}elseif ($state == 2){	$fname = $_SESSION['download_file'];	unlink($fname);		unset($_SESSION['download_file']);	echo "<script type='text/javascript'>		document.location.href=\"maint.php?".SID."\"</script>";	exit();}if ($state == 1){	echo "<p><form action = '$self' method = 'post'>		<input type='hidden' name='posted' value='done'>		<input type='hidden' name='state' value='1'>		<p><center>Click 'Backup' to back up the database.<br>		To cancel the operation, click 'Cancel'.</center>		<p><table align='center'><tr><td width=200 align='center'>		<input type='button' value='Cancel' onclick=\"page('maint.php')\">		<td width=200 align='center'>		<input type='submit' name='backup' value='Backup'>		</td></tr></table></form>";}elseif ($state == 2){	echo "<p><form action = '$self' method = 'post'>		<input type='hidden' name='posted' value='done'>		<input type='hidden' name='state' value='2'>		<p><center>Backup complete.		<p><input type='submit' name='done' value='OK'></center>";}?></div></body></html>

(By way of explanation, when the page is in state 1, it displays a submit button "Backup". When clicked, the form is posted, which causes the backup file to be generated and the url 'download_file.php' to be set in the iframe's source parameter, causing the download. The state is then changed to 2, which displays the 'Backup complete' screen with the 'OK' button. When OK is clicked, the original server copy of the backup file is deleted and it returns to the previous page.)Here is the file 'download_file.php':

<?php// download_file.phpsession_cache_limiter("nocache");session_start();$fname = $_SESSION['download_file'];// Output the special headersheader("Content-type:application/octet-stream\n");header("Content-Disposition:attachment;filename=$fname\n");readfile("$fname");?>

Link to comment
Share on other sites

Nope. :)PS: BTW, since Apple popped up a window offering Safari the other day, I downloaded and installed that - that works OK too, though not very politely. It downloads the file wham! without prompting and then proceeds to open the file in my default text editor. Neither does it prompt if the file already exists - it downloads it anyway and sticks a number on the end of the file name.

Link to comment
Share on other sites

Try changing the content-type to text/plain. That works for me in FF, but I don't know about IE then...

Link to comment
Share on other sites

The problem is not there - I have found what the real problem is!The session variable referenced in download_file.php is not set. Well, it's not set when running under Firefox, but is when running under IE7 or Safari.Fortunately, I know what the file name should be (vcwb_yyyymmdd.txt), so I can generate it directly in download_file.php - providing my system is not running so slowly that it takes a whole day to get there :)PS: I found this from looking at the Apache error log - a brilliant source of PHP run time error information!

Link to comment
Share on other sites

OK, this is not browser-specific. I had Firefox set up to block session cookies for testing. If I block session cookies in either browser, it fails.And here's why:

	echo "<script type='text/javascript'>		document.getElementById('file_download').setAttribute('src','download_file.php');		</script>";

I am not tacking SID onto the 'download_file.php'. :) Mea major culpa!

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...