Viewed   85 times

I'm struggling with an odd error. I have a simple web app that grabs stuff from a DB then outputs it as a downloadable csv file. It works on firefox and chrome, but IE fails to recognize it as a csv file (thinking it is a html fle) and when I click save I get the error, "Unable to download {name of file} from {name of site}. Unable to open this internet site. ..."

Code:

session_start();

//some logic goes here...  

//generate csv header  
header("Content-type: application/octet-stream");  
header("Content-Disposition: attachment; filename=exportevent.csv");  
header("Pragma: no-cache");  
header("Expires: 0");  

echo "Event: " . $event_title . "n";  

//print the column names  
echo "Last Name, First Name, Company n";  

while($row = mysql_fetch_assoc($result))  
{  
    echo $row['atlname'] . ',' . $row['atfname'] . ',' . $row['atcompany'] . "n";      
}

I've played around with the content-type a whole bunch, but that had no effect.

Update: I've tried text/csv, application/vnd.ms-excel (and variations of this), text/plain, and some others that I now forget with no luck.

This is IE8 btw.

Update 2: The connection is over SSL.

 Answers

3

Don't we love IE? :)

Try using those headers:

  header("Pragma: public");
  header("Expires: 0");
  header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
  header("Cache-Control: private",false);
  header("Content-Type: application/octet-stream");
  header("Content-Disposition: attachment; filename="exportevent.csv";" );
  header("Content-Transfer-Encoding: binary"); 

I think that the octet-stream content type forces IE to download the file.

Friday, November 18, 2022
3

Make sure your rvm is up to date: rvm get latest

And then run this: rvm uninstall 1.8.7 && CC=/usr/bin/gcc-4.2 rvm install 1.8.7

Basically you must tell rvm which gcc compiler to use (CC=/usr/bin/gcc-4.2)

Then you should be able to install the pg gem as normal.

Friday, October 7, 2022
 
1

This is my solution in case someone else is looking for a solution. now it works with FF, Chrome , and IE

var csv = JSON2CSV(json_obj);            
var blob = new Blob([csv],{type: "text/csv;charset=utf-8;"});

if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, "csvname.csv")
    } else {
        var link = document.createElement("a");
        if (link.download !== undefined) { // feature detection
            // Browsers that support HTML5 download attribute
            var url = URL.createObjectURL(blob);
            link.setAttribute("href", url);
            link.setAttribute("download", "csvname.csv");
            link.style = "visibility:hidden";
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }           
    }

Now I just need to figure out if there is a way to have the save as screen pop up instead of automatically saving the file. If anybody knows the answer to that please share. For now my users will have to use this functionality.

Thanks all for all the great answers, you guys are awesome.

Monday, October 17, 2022
 
ozbek
 
2

I think you might need a space after attachment;:

header("Content-Disposition: attachment; filename=$filename");

If that doesn't work, check out some of the points in this article, including:

  • On IE 6.0, things mostly work, but if you ALSO setup Cache-Control: no-cache, your suggested filename (and type!) will be IGNORED. A bummer if you have to choose between security and convienence. Of course, security wins.
  • On nearly all versions of IE, including 6.0, sometimes the browser will use the filename in the address bar instead of the Content-Disposition Header, and with IE5.5SP2 you're expected to change the UseCDFileName registry key, see Q303750. This was fixed with IE6.0SP1.

EDIT: Here's the code I use, directly copied from my application's source. Let me know if this works any better...

function forceDownload($filename,$mime=false,$downloadName=false)
{
    if(file_exists($filename) && is_readable($filename))
    {
        if(!$mime)      $mime = DFStdLib::determineMimeType($filename);

        if(!$expire)    $expire = DFStdLib::HOUR_IN_SECONDS;

        if(!$downloadName) $downloadName = basename($filename);

        header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($filename)).' GMT', true, 200);
        header('Cache-Control: no-cache',true);
        header('Pragma: Public',true);
        header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT',true);
        header('Content-Length: '.filesize($filename),true);
        header("Content-Type: {$mime}",true);
        header("Content-disposition: attachment; filename=$downloadName",true);
        readfile($filename);
        exit();
    }
    else
    {
        header('HTTP/1.1 404 Not Found',true,404);
        echo "<html><head><title>Not Found</title></head><body>The file was not found.</body></html>";
        exit();
    }
}

Usage for your case would be:

forceDownload('/example.pdf','application/pdf','quickquote.pdf');

Also you'll need to change DFStdLib::HOUR_IN_SECONDS to 3600 and write your own determineMimeType function, or delete that line and make the $mime argument required...

Friday, October 21, 2022
 
oblalex
 
2

I found this question while trying to find the answer myself. The solution was rather simple.

Based on the flash player bug that others have linked, and the comments on that page, I decided to append session identifiers to my upload URL and give it a shot. It really was that easy!

To make it work, I started by adding a flashVar parameter called sessionParams. This allowed me to pass any string I want in to the flash player as my session identifier, and it will later get appended to the URL used to upload.

//sessionParams - resolves firefox upload bug
public var sessionParams:String = "";

//...

public function initApp():void{
    sessionParams = Application.application.parameters.sessionParams;
}

In my case, I'm on ColdFusion with java sessions enabled, so my sessionParams are setup like the following before being passed into the flash player:

<cfset flashVars = "sessionParams=#urlEncodedFormat('jsessionid=' & session.sessionid)#" />

Don't forget to escape special characters like =,&, etc (which I've done with urlEncodedFormat), so that they are treated as part of the value of the "sessionParams" parameter, and not breakpoints to indicate other parameters. You're embedding future-URL information in the current URL.

Then, use the sessionParams value in your upload code. Here's a snippet of how I set mine up:

// Set Up URLRequest
_uploadURL = new URLRequest;
_uploadURL.url = _url + "?" + _sessionParams;
_uploadURL.method = "GET";
_uploadURL.data = _variables;
_uploadURL.contentType = "multipart/form-data";

The variable names are different (but similar) because this is part of a reusable class.

Hopefully that helps you. If not, let me know and I'll try to provide more code or explanation to help you out.

Monday, October 17, 2022
 
mdolbin
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :