My website has a functionality of downloading excel sheet. I'm using PHPExcel library with Codeigniter to create the .xlsx sheet. It works fine almost everywhere but in iPad/ iPhone Safari. The following error covers the screen.
Safari Error Screenshot
My code to download the file is following:
ob_end_clean();
$filename='attendance_list.xlsx';
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($this->excel, 'Excel2007');
$objWriter->save('php://output');
And i am calling the php function with this code via jquery and AJAX. Please provide me with the answers.
instead of:
header('Content-Type: application/vnd.ms-excel');
use
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
I am trying to export an export file in PHP. I am using Codeigniter Framework.
I exported Excel in this way:
header("Content-Type: application/xls");
header("Content-Disposition: attachment; filename={$filename}.xls");
It is showing data in Windows in right format. But prompt a message when I initially open it. But When I open it in MAC OS, it is not working.
How can I export Excel in right format that works in Google Drive as well? I have tried so many ways as above and as follows. All not working properly in Mac and Google Drive spreadsheets:
header('Content-Disposition: attachment; filename='.$filename.'.xlsx');
header('Content-type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename='.$filename.'.xls');
header('Content-type: application/vnd.ms-excel');
header("Content-Type: application/xls");
header("Content-Disposition: attachment; filename=$filename.xls");
Even though you're using codeigniter I would advise you to load a external library to handle your excel stuff.
There's library that everyone uses with PHP called phpspreadsheet.
https://phpspreadsheet.readthedocs.io/en/latest/
This will handle all the problems you're having and more. It's really easy to install since its available as a composer package.
https://packagist.org/packages/phpoffice/phpspreadsheet
Creating a excel file would be as simple as:
<?php
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Hello World !');
$writer = new Xlsx($spreadsheet);
$writer->save('hello world.xlsx');
And since your using codeigniter you can combine this with the CI download helper to force download the document.
Try This
ini_set('memory_limit', '-1');
//ini_set('MAX_EXECUTION_TIME', '-1');
ini_set('max_execution_time', 300);
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=Registration.xlsx");
header("Pragma: no-cache");
header("Expires: 0");
header("Content-Type: application/xls");
header("Content-Disposition: attachement; filename=export_test.xls");
I have a CSV file on my server. If a user clicks on a link it should download, but instead it opens up in my browser window.
My code looks as follows
<a href="files/csv/example/example.csv">
Click here to download an example of the "CSV" file
</a>
It's a normal webserver where I have all of my development work on.
I tried something like:
<a href="files/csv/example/csv.php">
Click here to download an example of the "CSV" file
</a>
Now the contents of my csv.php file:
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=example.csv');
header('Pragma: no-cache');
Now my issue is it's downloading, but not my CSV file. It creates a new file.
.htaccess Solution
To brute force all CSV files on your server to download, add in your .htaccess file:
AddType application/octet-stream csv
PHP Solution
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=example.csv');
header('Pragma: no-cache');
readfile("/path/to/yourfile.csv");
Or you can do this using HTML5. Simply with
<a href="example.csv" download>download not open it</a>
This cannot be done reliably, since it's up to the browser to decide what to do with an URL it's been asked to retrieve.
You can suggest to the browser that it should offer to "save to disk" right away by sending a Content-disposition header:
header("Content-disposition: attachment");
I'm not sure how well this is supported by various browsers. The alternative is to send a Content-type of application/octet-stream, but that is a hack (you're basically telling the browser "I'm not telling you what kind of file this is" and depending on the fact that most browsers will then offer a download dialog) and allegedly causes problems with Internet Explorer.
Read more about this in the Web Authoring FAQ.
Edit You've already switched to a PHP file to deliver the data - which is necessary to set the Content-disposition header (unless there are some arcane Apache settings that can also do this). Now all that's left to do is for that PHP file to read the contents of the CSV file and print them - the filename=example.csv in the header only suggests to the client browser what name to use for the file, it does not actually fetch the data from the file on the server.
Here is a more browser-safe solution:
$fp = #fopen($yourfile, 'rb');
if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
{
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="yourname.file"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
header("Content-Length: ".filesize($yourfile));
}
else
{
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="yourname.file"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".filesize($yourfile));
}
fpassthru($fp);
fclose($fp);
Configure your server to send the file with the media type application/octet-stream.
This means that your browser can handle this file type.
If you don't like it, the easiest method would be offering ZIP files. Everyone can handle ZIP files, and they are downloadable by default.
Nice clean solution:
<?php
header('Content-Type: application/download');
header('Content-Disposition: attachment; filename="example.csv"');
header("Content-Length: " . filesize("example.csv"));
$fp = fopen("example.csv", "r");
fpassthru($fp);
fclose($fp);
?>
A previous answer on this page describes how to use .htaccess to force all files of a certain type to download. However, the solution does not work with all file types across all browsers. This is a more reliable way:
<FilesMatch "\.(?i:csv)$">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
You might need to flush your browser cache to see this working correctly.
If you are doing it with your application itself... I hope this code helps.
HTML
In href -- you have to add download_file.php along with your URL:
<a class="download" href="'/download_file.php?fileSource='+http://www.google.com/logo_small.png" target="_blank" title="YourTitle">
PHP
/* Here is the Download.php file to force download stuff */
<?php
$fullPath = $_GET['fileSource'];
if($fullPath) {
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
switch ($ext) {
case "pdf":
header("Content-Disposition: attachment; filename=\"" . $path_parts["basename"]."\""); // Use 'attachment' to force a download
header("Content-type: application/pdf"); // Add here more headers for diff. extensions
break;
default;
header("Content-type: application/octet-stream");
header("Content-Disposition: filename=\"" . $path_parts["basename"]."\"");
}
if($fsize) { // Checking if file size exist
header("Content-length: $fsize");
}
readfile($fullPath);
exit;
}
?>
To force download you may use Content-Type: application/octet-stream header, which is supported by most browsers:
function downloadFile($filePath)
{
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
}
A BETTER WAY
Downloading files this way is not the best idea especially for large files. PHP will require extra CPU / Memory to read and output file contents and when dealing with large files may reach time / memory limits.
A better way would be to use PHP to authenticate and grant access to a file, and actual file serving should be delegated to a web server using X-SENDFILE method (requires some web server configuration):
X-SENDFILE is natively supported by Lighttpd: https://redmine.lighttpd.net/projects/1/wiki/X-LIGHTTPD-send-file
Apache requires mod_xsendfile module: https://tn123.org/mod_xsendfile/ On Ubuntu may be installed by: apt install libapache2-mod-xsendfile
Nginx has a similar X-Accel-Redirect header: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/
After configuring web server to handle X-SENDFILE, just replace readfile($filePath) with header('X-SENDFILE: ' . $filePath) and web server will take care of file serving, which will require less resources than using PHP readfile.
(For Nginx use X-Accel-Redirect header instead of X-SENDFILE)
Note: If you end up downloading empty files, it means you didn't configure your web server to handle X-SENDFILE header. Check the links above to see how to correctly configure your web server.
I have used following code to generate zip
// push to download the zip
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
readfile($zip_name);
this code works fine but for unknown reasons was not working until I tried
// push to download the zip
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
echo file_get_contents($zip_name);
I am curious about finding what is happening in both the cases
Readfile will read the file directly into the output buffer, and file_get_contents will load the file into memory, when you echo the result the data is copied from memory to the output buffer effectively using 2 times the memory of readfile.
I have an mp3 on my server (urls are just examples):
http://www.my-server.com/myaudio.mp3
I have a php script on the server at:
http://www.my-server.com/testmp3.php
Which contains the following code (which I got here):
<?
$file = "myaudio.mp3";
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
?>
Is this all I have to do to mimic the behavior so that both request behave the same way and return the exact same response? Or is there anything I'm missing.
I'm using some streaming code on iOS (not relevant here) and both requests stream the audio fine but I can't seek properly using the php request but I can with the mp3 request directly.
So without getting into details about the app itself I wanted to eliminate this one variable first. Is there anything I need to do to make sure that from another app's perspective these two request will return the exact same data?
Thanks for any input you can give me here.
Update
It turns out my question really should have read "how do you support seeking of an mp3 when returning from a php script?".
To support seeking, you often will have to support a range request.
From the RFC: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
See also: Resumable downloads when using PHP to send the file?
Its probably better to handle this with a .htaccess modification rather than some PHP code.
Here's a link on htaccess to get you started.
If you have a whole directory of .mp3 files that you want to appear as downloads instead of playing it in browser, you'd simply modify the .htaccess file in that folder to include
AddType application/octet-stream .mp3