I am coding a file sharing application for my office. One strange problem I am going through is the Illustrator files being opened in PDF when you hit the download button.
This problem is triggered because the mime type of illustrator files is application/pdf. So the browser when it reads the file, triggers Acrobat to open the file. Is there any way I could instruct the browser to open the file in Illustrator?
Or is there any way to modify the mime type after uploading the file? The backend code is PHP.
Thank you for any help.
One way to do this is to force the browser to display the "download file"-dialog. So the user can decide what to do with the file.
This can be done via PHP-Headers. (http://www.php.net/manual/en/function.header.php#83384)
There is also an example on how to this (Post 83384):
<?php
// downloading a file
$filename = $_GET['path'];
// fix for IE catching or PHP bug issue
header("Pragma: public");
header("Expires: 0"); // set expiration time
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
// browser must download file from server instead of cache
// force download dialog
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
// use the Content-Disposition header to supply a recommended filename and
// force the browser to display the save dialog.
header("Content-Disposition: attachment; filename=".basename($filename).";");
/*
The Content-transfer-encoding header should be binary, since the file will be read
directly from the disk and the raw bytes passed to the downloading computer.
The Content-length header is useful to set for downloads. The browser will be able to
show a progress meter as a file downloads. The content-lenght can be determines by
filesize function returns the size of a file.
*/
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
#readfile($filename);
exit(0);
?>
When using this example please consider that using
$filename = $_GET['path'];
is a big security problem. You should work with something like ID's instead or validate the input.
For example:
if($_GET['file'] == 1) {
$filename = foobar.pdf;
} elseif($_GET['file'] == 2) {
$filename = foo.pdf;
} else {
die();
}
Related
I wrote a download script in PHP as specified below, my script is downloading the files correctly, but I am feeling that the browser(chrome) progress bar is not getting updated properly in regular intervals.
My file is of size 320MB, while downloading that file the progress is getting updated randomly as "11MB, 76MB, 200Mb & 320MB" or "70MB & 320MB" etc.
In most of the sites download progress update is happening in constant chunks like after every MB, so I want to know how we can control the progress update intervals, may be by sending some extra headers or something else.
I want to improve the user experience by updating the progress in constant intervals, so anybody please help me to handle this situation in a proper way.
// HTTP Headers for ZIP File Downloads
// http://perishablepress.com/press/2010/11/17/http-headers-file-downloads/
// file variables
$filename = "Movie Tunes.zip";
$filepath = "files/";
// http headers for zip downloads
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: public,must-revalidate, post-check=0, pre-check=0");
header("Content-Description: File Transfer"); // MIME
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary"); // MIME
header("Content-Length: ".filesize($filepath.$filename));
ob_end_flush();
#readfile($filepath.$filename);
Thanks,
Siva
No, you cannot influence when/how the browser updates its download progress bar.
I need to retrieve our reports from the jasperserver report engine as a PDF, then I want the PDF to be forced as a download, instead of being displayed inthe browser. The problem with displaying in the browser is we don't want the report parameters to be displayed to the end users in the url.
If I enter this URL path into the browser I get a PDF document that shows in the same browser window with all the report data:
https://mysite.com:8443/jasperserver/flow.html?_flowId=viewReportFlow&reportUnit=sample_report&output=pdf;
What I would prefer to have happen is for a download dialog box to be used and for the users to download the PDF to their computer, instead of it showing in the browser.
I've tried the following php code, but can't get it to work. I get a return value of false, but nothing in the server logs that shows an error.
ob_start();
header("Location: $src"); /* Redirect browser */
$report_contents = ob_get_contents();
ob_end_clean();
var_dump($report_contents);
I'm not really sure how to go about this...anyone got any ideas?
Thanks for the help.
You could buffer the file to the PHP server then output with force download:
header('Content-disposition: attachment; filename=huge_document.pdf');
header('Content-type: application/pdf');
readfile('https://mysite.com:8443/jasperserver/flow.html?_flowId=viewReportFlow&reportUnit=sample_report&output=pdf;');
See the notes about using readfile over an HTTP stream wrapper
http://php.net/manual/en/function.readfile.php
how about
$source=$url
header("Expires: 0");
header("Cache-Control: private");
header("Pragma: cache");
header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
readfile($source);
exit();
I am creating a PDF file from raw binary data and it's working perfectly but because of the headers that I define in my PHP file it prompts the user either to "save" the file or "open with". Is there any way that I can save the file on local server somewhere here http://localhost/pdf?
Below are the headers I have defined in my page
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=$filename");
header("Content-Transfer-Encoding: binary");
If you would like to save the file on the server rather than have the visitor download it, you won't need the headers. Headers are for telling the client what you are sending them, which is in this case nothing (although you are likely displaying a page linking to you newly created PDF or something).
So, instead just use a function such as file_put_contents to store the file locally, eventually letting your web server handle file transfer and HTTP headers.
// Let's say you have a function `generate_pdf()` which creates the PDF,
// and a variable $pdf_data where the file contents are stored upon creation
$pdf_data = generate_pdf();
// And a path where the file will be created
$path = '/path/to/your/www/root/public_html/newly_created_file.pdf';
// Then just save it like this
file_put_contents( $path, $pdf_data );
// Proceed in whatever way suitable, giving the user feedback if needed
// Eg. providing a download link to http://localhost/newly_created_file.pdf
You can use output control functions. Place ob_start() at beginning of your script. At the end use ob_get_contents() and save the content to a local file.
After that you can use ob_end_clean() or ob_end_flush() depending on whether you want to output PDF to browser as well, or you would redirect user to some other page. If you use ob_end_flush() make sure you set the headers before flushing the data.
I am allowing users to upload documents to the server. However, i don't want them to obviously see where the files are being stored. What can i do that will allow them to still get the file but without seeing the file location.
You can use a PHP query to accomplish this, lets say you use the following URL:
http://mysite.com/files.php?file=xyz.pdf
In files.php you can check the get variable file and have a hard coded function that retrieves the file. You can do this many ways one by using headers to force a download or read the file into a var and print it's contents to the page. For say like a pdf reading the file and printing it to the page is the same as linking it to the file.
warning though: like with using headers do not print anything to the page except the file. I also recommend declairing you headers still if you read the file and print it so that the end user will not get the gobbly goop that is the source of the file i.e. jpg or pdf.
Oh no, I forgot a header warning, I have been running into a header problem ever since Adobe made the ISO for PDF's open source, depending on the application that produced the PDF and the browser from which the user is uploading the PDF from, the header will be anything from:
'application/pdf', 'application/x-download','application/octet-stream','application/octet','binary/octet-stream'
so be careful hard coding the upload section to a header type, I know this question is about downloads but i just thought i would throw that in there. Also using headers for downloads doesn't matter I would simply use the standard application/pdf there.
There are a few ways todo this but i prefer using .htaccess
So my link would look like http://example.com/files/filename.zip
extra parameters within the url could be used a username or password like:
http://example.com/files/bob/filename.zip
http://example.com/files/18d52c/filename.zip
Then thos could be checked against a database to see if user is allowed to download that specific file, much like you would use for instant downloads after payment.. but a basic method would be like so:
.htaccess
RewriteRule ^files/(.*)$ serve.php?file=$1
serve.php
<?php
if(isset($_GET['file'])){
$file=basename($_GET['file']);
//Protect the index.php && serve.php
if(basename($_GET['file'])=='index.php' || basename($_GET['file'])=='serve.php'){
header("HTTP/1.1 403 Forbidden");die();
}
$downloadFolder="original_location/";
if(file_exists($downloadFolder.$file)){
$fsize = filesize($downloadFolder.$file);
$ctype=finfo_file(finfo_open(FILEINFO_MIME_TYPE), $downloadFolder.$file);
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
if(strstr($_SERVER["HTTP_USER_AGENT"],"MSIE")==false) {
header("Content-Type: application/force-download");
header('Content-Description: File Transfer');
}else{
header("Content-Type: $ctype");
}
header("Content-Disposition: attachment; filename=\"".basename($file)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$fsize);
ob_clean();
flush();
readfile('original_location/'.$file);
}else{
header("HTTP/1.0 404 Not Found");
}
die();
}
header("HTTP/1.0 404 Not Found");
?>
original_location/index.php
header("HTTP/1.1 403 Forbidden");
Store it using some random unique ID that you can map to the real file, then serve it using a script that does readfile() on the actual file.
The http://php.net/readfile docs also have an example on how to force it being a download.
I am working on a video site that has different movies and videos which users can stream and download. Now I am being asked to implement a download restriction in such a way that only 1 video can be downloaded at a time. There are two servers: my files and database are on one server and the videos are on the other.
What I am doing for downloading is to send a request from the first server for a file on the other server. If the requested video exists, it is downloaded.
Now I want to restrict the users so that if they are already downloading a video, they cannot download another until the current download completes. Once the current download has completed, the user can download the next video. I have not seen any function that enables a developer to know when the download has completed.
I have a few things in my mind about storing the information of the download time in the database. But storing the time of download is not my requirement.
What is the best way to implement this? Is there an event from which we can detect the download end time? Is there any solution to this? I am using PHP and here is the code that I have used for downloading the file from the second (videos) server. This file sends a request with a file name and full path. The $real_file variable contains the file name along with full path on the second server.
if(file_exists($real_file))
{
header("Pragma: public");
header("Cache-Control: private");
header("Expires: 0");
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: pre-check=0, post-check=0, max-age=0');
header('Content-Transfer-Encoding: binary');
header('Content-Encoding: none');
header("Content-Disposition: attachment; filename=".urlencode(basename($real_file)));
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize($real_file));
header("Accept-Length: ".filesize($real_file));
$fp = #fopen($real_file, "rb");
while(!feof($fp))
{
$buffer= fread($fp, 8192);
echo $buffer;
}
#flush();
#ob_flush();
die();
}
If you stream the file through a php-script, it would maybe be able to obtain a lock for a specific user (logged in of course) before you start to read the file and outputting to the stream:
(pseudocode)
obtain_lock_somehow();
readfile('yourvideofile.mpg');
release_lock();
I don't know how the script would respond to a closed connection, and it might force the script to end prematurely.
Another option would be to read the file and pass on to the stream in "chunks", and in between every chunk you update the status of the visitors "lock", so that you can identify at which last timestamp the visitor actually downloaded something.
(pseudocode)
while(file_is_not_finished) {
update_lock_status();
pass_thru_buffer();
}
But do note that streaming huge amount of data in a php-script like this is probably not the best way to go, and you might be better off with a native server module for it.