File throws an error on download - php

I'm generating a csv file for download using the following code.
/**#var array $results contains the results of an SQL query**/
$tmpFile = tmpfile(); //Create a temp file to write the csv to
fputcsv($tmpFile, array_keys($results[0])); //Write the column headers
foreach ($results as $result) { //write each row to the file
fputcsv($tmpFile, $result);
}
rewind($tmpFile); //Rewind the stream
$csv = stream_get_contents($tmpFile); //Get the file as text
fclose($tmpFile); //Done with the temp file.
//Set the download headers
header('Content-Description: File Transfer');
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="testDownload.csv"');
//Output the content
echo $csv;
exit(0);
The download appears to start normally, but after a second I get a message in firefox, "[The file] could not be saved, because the source file could not be read." I've tested this with chrome/safari and have gotten similar results. I've also tested with some static content (not from the database) without success.
In the developer console, I can inspect the network request and see that it comes back with status 200 and if I inspect the response, I see the complete file. I can even copy/paste it into a text file and open it in excel.
Additionally, if I comment out the header() lines, the file contents display in the browser without issue.
The content is only ~2500 rows, no special characters.

Related

php header print tag pages

I have this code to create a csv in php and after make possible the download:
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=data.csv');
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
// output the column headings
fputcsv($output, array( //values...));
$rows = #mysql_query("SELECT //values from table");
// loop over the rows, outputting them
while ($row = mysql_fetch_assoc($rows)) fputcsv($output, $row );
But, after the download, when I open the file, what I see is the content of the page with the tags, in addition to the csv content.
How is possible to see all the content of the csv without the tags page?
thanks in advances
If I understand correctly - I think the issue is that you are calling a function with the code you have posted when you have already outputted HTML (either intentionally or otherwise), when what you should do is link to a separate PHP Script containing your code, or not output before your code sample in called.
When you declare those headers in your code, you are telling the browser that the content is .csv but you are outputting this in the middle of HTML output (where likely HTML headers have already been sent due to some prior output).
Instead you can put your code in a separate PHP script and then create a link to it from other outputted HTML pages. This will mean that when your code is loaded the csv headers will be sent with the correct content only.

Generate/Download of CSV throws a Connection error PHP

So the process that I have goes like this. A user can pick a date range to view the data that he wants/needs. A Download is then available if he wants to download the file.
When doing a wide range the page throws off a connection error.
Firefox - The connection was reset
Chrome - No Data Received
The code that I use to generate the CSV is
<?php
$res = // the array generated by a mysql query
$text=strtotime("Now");
$filesave=fopen('Downloads/CallLogs'.$text.'.csv','w');
foreach ($res as $display)
{
fputcsv($filesave,$display);
}
//Force download the file. you can correct me if this is the improper way of doing it :)
header('Content-Type: application/download');
header('Content-Disposition: attachment; filename="CallLogs'.$text.'.csv"');
$fp = fopen("Downloads/CallLogs".$text.".csv", "r");
fpassthru($fp);
fclose($fp);
?>
Thanks in advance...

PHP zip download bug

I have a script that lets users download a zip file on request. It works 100% on computer browsers but does not work on Android/mobile browsers, except for Opera (mobile) only.
Here's my script.
$leads = new Packer($zip_name);
$index = 1;
$count = 0;
foreach($cLeads->lastUnitInfo['leads'] as $lead)
{
// build a request string
$export = 'export_lead_'.$index;
$req = $_POST[$export];
// add it to the zip file
if(isset($req) && $req == '1')
{
// debug only
//echo 'adding lead: '.$lead['file_name'].'<br />';
$leads->addLead('leads/'.$lead['file_name'],$lead['item_name']);
$count++;
//echo 'count: '.$count.'<br/>';
}
$index++;
}
// debug
//exit('count: '.$count); // displays same results on all browsers.
// we got anything packed ?
if($count <= 0) //// <-------- BLOCK OF BUG ON MOBILE PHONE
{
if(file_exists($zip_name))
unlink($zip_name); // delete the zip file created.
exit('<h1>Nothing to export</h1>');
} ///// <---------------------- END BLOCK
// download the leads here.
$leads->purge();
exit;
Here's my purge() function
public function purge($zip_name = 'leads.zip')
{
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
ob_clean();
flush();
readfile($this->zip_name);
// errors will be disabled here
unlink($this->zip_name);
}
On my Android phone, the zip file gets downloaded but contains <h1>Nothing to export</h1> which renders it as an invalid zip file.
So my problem is, How is it that the block only executes on mobile browsers (except Opera) and then continues to download the zip when it should have exited if $count was zero at all?
I debugged it using Fiddler and the requests are all the same but the output is different, why ?
Is this a bug in PHP? Because if you look at my code the function purge() should output errors saying headers have already been sent but it just continues to download the zip file.
Browsers:
Dolphin (+Beta)
FireFox
Default Android browser
Boat Browser
PHP versions tested:
5.3.13 (Production, shared server)
5.1.4
This is driving me nuts now.
#Alix This is the weirdest bug I've ever seen. I don't seriously see any logical errors here. For the script to initiate a download, there actually has to be files added to the zip. Now on my phone, it says no files are added but there's a zip file in the temp folder. Moreover if there are no files added ($count = 0) then the script should terminate (hence the exit() function) with just a message <h1>Nothing to export</h1>. But it goes on to download the zip file (which at this time does not exist, but in the temp folder it does). The zip file ends up being corrupt as it contains <h1>Nothing to export</h1>
Alix wrote:
*> what happens if you comment out the exit call before serving the file?
It says readfile error then purges the zip file in gibberish UNICODE chars. I can tell it's the zip file because it starts with PK and contains the names of images being exported.
Alix wrote:
If this doesn't work, you may wanna change exit('<h1>Nothing to export</h1>'); to exit(var_dump($_REQUEST));, that way you may check for possible bugs in the form submission by inspecting the Zip file.
Interesting. It prints nothing but the cookie and a $_GET parameter only. If I put the code in your suggestion at the beginning on the script and in the block that adds the files to the zip it prints all the $_POST variables.
There's clearly a bug on PHP's part here. It should terminate when exit is called but it doesn't. And mind you this only happens on mobile browsers except Opera. I'm going to cry blood now.
Are you sure the other browsers are setting $_POST[$export] to the correct value?
Also, you should first ob_[end_]clean() and then output the headers, not the other way around:
public function purge($zip_name = 'leads.zip')
{
ob_end_clean();
flush();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
readfile($this->zip_name);
// errors will be disabled here
unlink($this->zip_name);
}
Additionally, you may wanna set these headers:
header('Content-Length: ' . intval(filesize($zip_name)));
header('Content-Transfer-Encoding: binary');
If this doesn't work, you may wanna change exit('<h1>Nothing to export</h1>'); to exit(var_dump($_REQUEST));, that way you may check for possible bugs in the form submission by inspecting the Zip file.

Output Contents of PHP File for a GET/POST request

I have a script which generates an XML file when the user accesses the link like so:
domain.com/dirList.php
I would like to print the contents of the XML to the user at the end of the POST or GET request (have not implemented this yet). At the moment I am just viewing the link through a web browser.
This is the code I am using to print the file contents.
# Open XML file and print contents
$filename = "test.xml";
$handle = fopen ($filename, "r");
$contents = fread ($handle, filesize ($filename));
fclose ($handle);
print $contents;
The problem is that it doesn't seem to be working. I think I might be either missing a header like this: ("Content-Type: text/xml"); or maybe my code is wrong.
What do I need to do to get the XML file to print to the browser?
You can just do:
header('Content-type: text/xml'); // set the correct MIME type before you print.
readfile('test.xml'); // output the complete file.
//Check there is any extra space before <? and after ?>
//or
header('Content-type: text/xml');
echo file_get_contents($path.$xmlfile);

Export mySQL to excel or csv

I'm no php expert (a mere beginner) but need some help!
After hours searching Google and trying out about 100 different scripts, I finally found one that does what I need - almost.
Basically, my site has a button marked 'Export to Excel'. Visitor to site clicks button and a download begins containing all data from a specified table.
I found this on here - PHP code to convert a MySQL query to CSV
which does exactly what I want except the user sees the following error when trying to open the file:
Error - 'The file you are trying to open, 'export.xls', is in a different format than specified by the file extension. Verify that the file is not corrupted and is from a trusted source before opening the file. Wo you want to open the file now?'
User clicks 'Yes' and file opens with all data! Brilliant! Except users will not open the file with this error.
I would be very grateful if someone knows a way to fix this.
Many thanks
TT
Or, you could just change the script in the above solution to return a file with the .csv extension. .csv files are associated with Excel, so they should open directly.
Ok, this results from a feature specified by Excel 2007 called Extension Hardening. You can turn it off, but that can only be done client-side. If you click "OK" or "Yes" the file should open anyway. Check this blog post for more info.
EDIT: What this means is that Excel is finding that the file is of a different type (say HTML or CSV) that what is specified by the file extension. Therefore Excel wants to warn you that this file is not what it says it is. Unless you are going to create native Excel files on the server then prompt the user to download them, there is no getting around this error except for each user to turn off Extension Hardening on their own computer.
if you make the first letters “ID” of a text file Excel incorrectly
assumes you are trying to open an SYLK file.
Meaning if the first row & column value is "ID", Excel will throw this warning. Just change it from "ID" to anything else.
Credit: http://alunr.com/excel-csv-import-returns-an-sylk-file-format-error/
Dim objXL As Excel.Application
Dim objWkb As Excel.Workbook
Set objXL = New Excel.Application
'turn off excel warnings
objXL.DisplayAlerts = False
'Open the Workbook
Set objWkb = objXL.Workbooks.Open(fpath)
functions sendFile($filename,$content_type="application/ms-excel") {
header('Content-type: '.$content_type);
header('Content-disposition: Attachment; filename=' . $filename);
readfile($filename);
}
I had the same problem so I looked at the following link: PHP code to convert a MySQL query to CSV
I modified one of the answers to get the headers to work.
include('DBFILE.PHP');
$select="SELECT * FROM SOMETable";
$result = mysqli_query($conn, $select);
if (!$result) die('Couldn\'t fetch records');
$num_fields = mysql_num_fields($result);
//This is what I changed...
$headers ="";
while ($property = mysqli_fetch_field($result)) {
$headers.= $property->name.",";
}
$headers.="\n";
//////
$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 = $result->fetch_array(MYSQLI_NUM)) {
fputcsv($fp, array_values($row));
}
die;
}
I Tested this and it works like a charm, you just need to add your db connection or include the db.php file that you have.
you can change the name of the file if you edit the following line
header('Content-Disposition: attachment; filename="export.csv"');
Change export to what ever name you like.

Categories