I have a rather simple force download script:
$thefile = $_GET['id'];
$file = 'http://www.mywebsite.com/test/'.$thefile;
header('Content-Disposition: attachment; filename='.$thefile);
header("Content-Type: application/force-download");
#readfile($file);
And it works nicely, except it does not show how much time is remaining ("could not calculate time").
I found someone with a similar problem here, by using this code:
# for URL paths that begin with "/foo/bar/"
SetEnvIf Request_URI ^/foo/bar/ no-gzip=1
# for files that end with ".py"
<FilesMatch \.py$>
SetEnv no-gzip 1
</FilesMatch>
But alas, I can not get that to work. My files are media files (avi, wmv, mp4 and so forth), so I assumed I would have to modify the code along these lines:
SetEnvIf Request_URI ^/test/ no-gzip=1
<FilesMatch "\.(avi|wmv|mp4|mpg|mpeg|m4v)$">
SetEnv no-gzip 1
</FilesMatch>
I have also changed the path to a simple test folder, but time is still not being displayed.
How to?
You should add content-length header, for your browser to know total file size.
header("Content-Length: " . filesize($file));
Take a look at this example.
Related
I've some pdf files on my shared hosting server of bluehost. I need to download them from iOS app & I want to show the download progress bar.
But I couldn't because Content-length is not present in Header response.
How can I get this?
You can set it via header. With the header function you can set HTTP information. But note that you dont have any output before set HTTP informationen.
header('Content-type: application/pdf');
header("Content-length: $size");
header('Content-Disposition: attachment; filename="downloaded.pdf"');
Edit:
If you dont use PHP to download the file you can use SetEnv no-gzip dont-vary in your htaccess to suppress GZIP.
I have a little bit stupid necessity to disguise links to PDF files as PHP files with the PDF filename as a parameter.
Something like:
Client requests xxxx.pdf file.
Server receives request but instead of returning xxxx.pdf goes to yyyy.php or whatever extension.
yyyy.php has an iframe in which the PDF file is loaded.
The thing is that I managed to do point 2. but when I try to do point 3. it either cycles or doesn't locate the file.
I was thinking of having a custom extension to "simulate" another file in order to not cycle but it's still cycling.
I have the following .htaccess:
AddType application/pdf .view
RewriteRule ^(.*)\.pdf$ yyyy.php?filename=$1 [L]
RewriteRule ^(.*)\.view$ $1.pdf [L]
The thing is that it cycles and I get nowhere.
I am not really good with .htaccess, so where am I doing this wrong?
You probably need to add something to prevent the referer for yyyy.php from getting rewritten back to the php file. Add this before your yyyy.php rule:
RewriteCond %{HTTP_REFERER} !yyyy\.php
Note that referers can be forged, so this is one way people will be able to bypass the yyyy.php file.
I found it easier to just redirect when I detect a .pdf extension.
So I basically did this:
.htaccess detects a PDF extension and redirects to a php file passing the filename without extension as a parameter.
The php file uses the filename and renders the PDF using header and readfile to avoid conflicts with .htaccess.
Something like that:
.htaccess
RewriteRule ^(.*)\.pdf$ /pdfreader/$1 [L,R=302,NC]
RewriteRule ^pdfreader/(.*)?$ pdfreader.php?file=$1 [L,NC]
pdfreader.php
$file = $_GET["file"].".pdf";
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $file . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
header('Accept-Ranges: bytes');
#readfile($file);
I am using a controller in CodeIgniter 2 to generate a resized image based on its URL however the pictures are getting randomly cut off on one of our servers (only the top two thirds or so get shown). I believe the problem is related to GZIP being used when the picture is generated but it is difficult to reproduce consistently and disappears entirely when I turn compression off.
Interestingly, the GZIP compression is only added to the outputted JPEG when the text/html is being compressed.
This is my apache configuration:
<IfModule mod_deflate.c>
<FilesMatch "(?<!\.jpg)$">
AddOutputFilterByType DEFLATE text/html
</FilesMatch>
</IfModule>
<FilesMatch "\.jpg$" >
SetEnv no-gzip dont-vary
RemoveOutputFilter php
</FilesMatch>
My htaccess file contains this
SetEnvIfNoCase Request_URI ".jpg$" no-gzip dont-vary
<FilesMatch "\.(gif|jpe?g|png)$">
SetEnv no-gzip dont-vary
</FilesMatch>
PHP code looks like this
//code to generate the image and save it to the hard drive goes here
//output the file
$binarydata = file_get_contents($directory.$file);
$offset = 5184000;
header("Cache-Control: must-revalidate");
header('Content-Type: image/jpeg');
header('Expires: '. gmdate('D, d M Y H:i:s', $dbrecord->updated_at->format("U") + $offset) .' GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $dbrecord->updated_at->format("U")) .' GMT');
header('Accept-Ranges: bytes');
header("Content-Disposition: inline; filename=".$file);
header('Content-Length: '.strlen($binarydata));
print($binarydata);
die();
The URL of the photo would be something like http://example.com/photo/100x100-abc.jpg and as you can see, there are four different ways of trying to avoid the compression being set however it is still set.
I have tried all the methods above separately and combined but to no avail. I am at my wits end, can anyone help?
UPDATE:
I removed the content length header and apache did not set it on its own but we have just discovered something interesting, the problem only occurs in Chrome and Safari and not Firefox so I wonder if this is also webkit related?
I installed mod_xsendfile and it seems to have been successful; xsendfile.load appears in /etc/apache2/mods-enabled, and I've found no errors when running my test script. However, every time I run it, I get served a 0B file.
Here's my test script:
$file = 'sample.mp4';
$path = '/var/storage/media/'.$file;
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header("Content-type: application/octet-stream");
header("X-Sendfile: $path");
Obviously I have a file stored in /var/storage/media/sample.mp4, it's only 25MB, and is served perfectly fine if I do it this way:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($path));
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($path));
ob_clean();
flush();
readfile($path);
exit;
I also have this in the .htaccess file of both /var/storage and /var/www (the files that has all this is stored in /var/www/files/index.php):
XSendFile on
XSendFileAllowAbove on
Like I said, I get no errors, and the PHP can certianly access the file, but I must be missing something with the x-sendfile configuration... that reminds me, I notice in mods-enabled just about every mod has a .load and .conf, but xsendfile only has .load, but so do a few others, so would that have anything to do with it?
Thanks.
I had the same problem and this solution worked for me:
After installing the module, you need to enable it and give an access path into the Apache configuration (httpd.conf for global configuration, or specific site vhosts for specific configuration) like these:
# enable xsendfile
XSendFile On
# enable sending files from parent dirs
XSendFilePath /var/www/
Of course you must replace /var/www/ by whatever folder you want xsendfile to have access to
Make sure you also turn on XSendFile in your Apache configuration if using Apache. If you don't do this, it will look like it works, but empty files will be served.
For example:
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
XSendFile on
AllowOverride All
Order allow,deny
allow from all
</Directory>
I'm using it on Ubuntu 14.04 and Apache/2.4.7.
It's important to:
Setup on each host configuration:
<Directory /var/www/path/to/files>
XSendFile On
XSendFilePath /var/www/path/to/files
</Directory>
Add to .htaccess:
XSendFile on
While I was using only 1; it kept me downloading empty files.
After adding 2, worked nicely.
On Windows I had to use the following in order be able to serve files outside of doc roo.
Everything else was giving me 404
XSendFilePath C:/
Try making header("X-Sendfile: $path"); the first header() call in the file.
Also take a look at this. Seems like a similar issue and it may give you some ideas:
X-Sendfile Error
I'm having some trouble prevent mod_deflate from jumping in on this scenario:
user running CodeIgniter (or any other framework that re-directs to index.php)
mod_deflate is active
zip file is served by a CodeIgniter controller (headers + readfile)
The thing is that Apache always detects the content as being php and therefor something like the lines bellow wont work as the server assumes the ZIP file as being a PHP one.
<FilesMatch "\.(xml|txt|html|php)$">
SetOutputFilter DEFLATE
</FilesMatch>
Any ideas on how I can have Apache distinguish from an HTML file or a ZIP file both generated by the same index.php framework file.
Edit:
apache log
[Mon Jun 20 02:14:19 2011] [debug]
mod_deflate.c(602): [client 192.168.0.5]
Zlib: Compressed 50870209 to 50878224 : URL /index.php,
referer: http://demo.dev/
Edit:
CI controller that serves the zip
header('Content-Type: application/zip');
header('Content-Transfer-Encoding: binary');
header("Content-Length: " . filesize($file_location));
header('Content-Disposition: attachment; filename="' . $file_title . '"');
readfile($file_location);
Even tough all answers should have been perfectly valid in a reasonable scenario (and were actually tested prior to making the question) the reason to why I've been unable to instruct Apache to deflate a file by MIME-Type remains unknown.
I was able to have it work as desired by forcing the following instructions into the script
apache_setenv('no-gzip', 1);
ini_set('zlib.output_compression', 0);
I do understand that this is a hot patch and is not addressing the problem's root but so far that will have to suffice. As there are others who may hit the same flag, the above code stays here for reference in what is a dirty fix.
You can either:
use the deprecated AddOutputFilterByType and specify only the content types you do want to filter; or
use the more powerful mod_filter. In FilterProvider you can provide a rule that excludes the filter when the zip content type (application/zip) is found in the response headers.
You can make use of mod_rewrite to change the mime-type of the request on the Apache level:
# Serve .zip request as zip-files
RewriteRule \.zip$ - [T=application/zip,E=no-gzip:1]
Place it above the rules of the framework, however this needs to make DEFLATE as well depended on mime-type and not file-extension as you do with <FilesMatch>.
Probably it works well together with
AddOutputFilterByType DEFLATE text/html
instead of the <FilesMatch> Directive.
Edit: Added the L flag which should be used in .htaccess context and additionally turned DEFLATE off via the no-gzip environment variable.
Try this (since your urls appear to end in .zip it might work for you):
<FilesMatch "\.(xml|txt|html|php)$">
SetEnvIf Request_URI "\.zip$" no-gzip
SetOutputFilter DEFLATE
</FilesMatch>
Instead of using
<FilesMatch "\.(xml|txt|html|php)$">
SetOutputFilter DEFLATE
</FilesMatch>
Use this configuration for setting compression rules.
AddOutputFilterByType DEFLATE text/html text/plain text/css text/xml application/x-javascript application/javascript
This way, your output will be compressed only if content-type matches with above directives.
CI controller that serves the zip is already sending correct content-type header, so this will not get compressed.
header('Content-Type: application/zip');