Zip files being open as files by APACHE server instead of downloading - apache

The error that I get is from PHP because APACHE is tryng to pass the .zip file through the PHP interpreter.
But this post is not regarding any PHP script, or setting up headers from PHP to make the file download. It is about preventing APACHE from passing the file through PHP and generate a download instead.
I have found a few answers that involve adding File Exceptions on the .htaccess but still without success and I get the follwing Parse error message:
Parse error: in /home/user/public_html/downloads/files/1/test-file-132110.zip on line 431

These are the .htaccess instructions that I found that work:
<Location "/downloads/files/">
<Files *.*>
ForceType application/octet-stream
Header set Content-Disposition attachment
</Files>
</Location>
The previous example is not so great because I want to chose specific extensions, lile doc, zip, etc. So I tried these instead:
<Location "/downloads/files/">
<FilesMatch ".(?i:doc|docx|xls|xlsx|ppt|pptx|zip|rar)$">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
</Location>
or this, without specifying a location:
<FilesMatch "\.(doc|docx|xls|xlsx|ppt|pptx|zip|rar)$">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>

Related

Cache control static assets with query strings in htaccess

Do the cache control directives need to specify if a query string is present in the http request for proper matching?
Currently using query strings for static asset versioning, and disabled Etags for those - but the directives are not taking effect whatsoever. Looking at the headers, Etags are still used and there is no cache-control defined. Gmatrix and Lighthouse both state that static assets have no cache control set.
Example file requested: app.js?v=1.3.5
Here is the .htaccess file, followed by the troubleshooting steps
<IfModule mod_headers.c>
# One month for media files and icons
<FilesMatch "\.(ogg|mp3|ico|jpg|jpeg|png|svg|webp|webmanifest|xml)\?.*$">
Header set Cache-Control "max-age=2592000, public"
Header unset ETag
FileETag None
</FilesMatch>
# One week for CSS/JS files except service worker file
<FilesMatch "^(?!sw).+\.(css|json|js)\?.*$">
Header set Cache-Control "max-age=604800, public"
Header unset ETag
FileETag None
</FilesMatch>
# No cache for HTML files (checks with server for changes else serves cache)
<FilesMatch "\.(html)$">
Header set Cache-Control "no-cache, must-revalidate"
</FilesMatch>
<FilesMatch "^(sw\.js)$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
</FilesMatch>
</IfModule>
Troubleshooting steps
Directives don't seem to affect html pages either so assuming this may be a config or syntax issue.
Check syntax with validator: https://www.lyxx.com/freestuff/002.html
Ensure AllowOverride is set to All in /etc/apache2/sites-available/mysite.conf
Try setting AllowOverride to All in /etc/apache2/apache2.conf for /var/www/
Try adding the directives directly in /etc/apache2/sites-available/mysite.conf
Restart apache after changes: service apache2 restart
The mod_headers module was not activated!
Use apachectl -M to check for active modules (Debian/Ubuntu).
If headers module not listed:
Use a2enmod headers to activate the headers module.
Restart apache2 with service apache2 restart to implement changes.
At this point was able to test whether the query string needs to be added in the FilesMatch expression.
Turns out the query string needs to be omitted from the expression.
Use: \.(js)$
Don't use: \.(js)\?.*$

How to setup a download folder in Apache HTTPD?

I want to setup a download folder on HTTPD so that the folder it self is indexed and the files are downloaded when clicked.
I tried this, but didn't work:
# Downloads
<Directory /var/www/html/downloads>
Allow from all
Options Indexes
<Files "?*">
ForceType application/octet-stream
Header set Content-Disposition attachment
</Files>
</Directory>
Browsing to /downloads gives me the index of the folder. But clicking the files doesn't open download prompt.
Any ideas?
Regards,
--
Edit:
There seems to be something about my browser. Indeed it IS working.

apache2 and php5-fpm, how to correctly process *.phps files?

I've setup my server using apache2 and php5-fpm, pretty much like in this guide:
http://www.versatilewebsolutions.com/blog/2012/11/installing-apache-2-with-php-fastcgi-on-ubuntu-12-10.html
The only question left is, how can I configure it to correctly process the *.phps files?
I want to show the highlighted code of them.
There are guides for nginx and php-fpm ( https://blog.kamalnasser.net/post/highlighting-phps-files-in-nginx/ ), but what should we do with apache2 ?
Caveats: Ubuntu 14.10, Apache/2.4.10
In the file /etc/apache2/mods-available/php5.conf:
<FilesMatch ".+\.phps$">
SetHandler application/x-httpd-php-source
# Deny access to raw php sources by default
# To re-enable it's recommended to enable access to the files
# only in specific virtual host or directory
Order Deny,Allow
Deny from all
</FilesMatch>
Add a with "Allow from all" (or something more appropriate to your paranoia-level) to you host config, and you'll be all set.
My config:
<Directory /my/very/long/and/winding/server/path/public_html/phpsource/>
<FilesMatch ".+\.phps$">
Order Deny,Allow
Allow from all
</FilesMatch>
</Directory>
Php Source files in other directories get denied, the ones in that directory gets displayed. It works like a charm...
This should do it:
AddType application/x-httpd-php-source .phps
Add it to your apache config file. There should be a similar line like this:
AddType application/x-httpd-php .php
So just add it below.

configure apache run run php in html pages

How can I make apache parse php code inside my html pages? I don't wanna use .htaccess. I've added:
AddType application/x-httpd-php .html
AddType application/x-httpd-php .php
in my vhost file for one of the websites but it won't work.
Did you build your Apache binary with PHP? Or if you built a SO, reference it in the Apache config (e.g.: LoadModule php5_module modules/libphp5.so)?
When using .html for PHP, ensure 'AddType text/html .html' is removed, so it doesn't conflict with the x-httpd-php reference.
FYI -- you can create one entry 'AddType application/x-httpd-php .html .php'
I have the same problem in the latest versions (Debian 10 , Apache 2.4.25, PHP 7.0.33)
My solution is edit the php.config file, to find it I put:
find -iname php*.conf
...and in my debian instalation I found it in:
/etc/apache2/mods-available/php7.0.conf
Then, I introduce those lines at begining:
<FilesMatch ".+\.html$">
SetHandler application/x-httpd-php
</FilesMatch>
And it work for me.

How can I pre-compress files with mod_deflate in Apache 2.x?

I am serving all content through apache with Content-Encoding: zip but that compresses on the fly. A good amount of my content is static files on the disk. I want to gzip the files beforehand rather than compressing them every time they are requested.
This is something that, I believe, mod_gzip did in Apache 1.x automatically, but just having the file with .gz next to it. That's no longer the case with mod_deflate.
This functionality was misplaced in mod_gzip anyway. In Apache 2.x, you do that with content negotiation. Specifically, you need to enable MultiViews with the Options directive and you need to specify your encoding types with the AddEncoding directive.
To answer my own question with the really simple line I was missing in my confiuration:
Options FollowSymLinks MultiViews
I was missing the MultiViews option. It's there in the Ubuntu default web server configuration, so don't be like me and drop it off.
Also I wrote a quick Rake task to compress all the files.
namespace :static do
desc "Gzip compress the static content so Apache doesn't need to do it on-the-fly."
task :compress do
puts "Gzipping js, html and css files."
Dir.glob("#{RAILS_ROOT}/public/**/*.{js,html,css}") do |file|
system "gzip -c -9 #{file} > #{file}.gz"
end
end
end
I am afraid MultiViews will not work as expected: the doc says Multiviews works "if the server receives a request for /some/dir/foo, if /some/dir has MultiViews enabled, and /some/dir/foo does not exist...", in other words: if you have a file foo.js and foo.js.gz in the same directory, just activating MultiViews will not cause the .gz file to be sent even if the AcceptEncoding gzip header is transmitted by the browser (you can verify this behavior by temporarily disabling mod_deflate and monitoring the response with e.g. HTTPFox).
I am not sure if there is a way around this with MultiViews (maybe you can rename the original file and then add a special AddEncoding directive), but I believe you can construct a mod_rewrite rule to handle this.
It is possible to serve pre-compressed files using mod_negotiation although it is a bit finicky. The primary difficulty is that only requests for files which do not exist are negotiated. So if foo.js and foo.js.gz both exist, responses for /foo.js will always be uncompressed (although responses for /foo would work correctly).
The easiest solution I've found (from François Marier) is to rename uncompressed files with a double file extension, so foo.js is deployed as foo.js.js so requests for /foo.js negotiate between foo.js.js (no encoding) and foo.js.gz (gzip encoding).
I combine that trick with the following configuration:
Options +MultiViews
RemoveType .gz
AddEncoding gzip .gz
# Send .tar.gz without Content-Encoding: gzip
<FilesMatch ".+\.tar\.gz$">
RemoveEncoding .gz
# Note: Can use application/x-gzip for backwards-compatibility
AddType application/gzip .gz
</FilesMatch>
I wrote a post which discusses the reasoning for this configuration and some alternatives in detail.
I have an Apache 2 built from source, and I found I had to modify the following in my httpd.conf file:
Add MultiViews to Options:
Options Indexes FollowSymLinks MultiViews
Uncomment AddEncoding:
AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
Comment AddType:
#AddType application/x-compress .Z
#AddType application/x-gzip .gz .tgz
mod_gzip compressed content on the fly as well. You can pre-compress the files by actually logging into your server, and doing it from shell.
cd /var/www/.../data/
for file in *; do
gzip -c $file > $file.gz;
done;
You can use mod_cache to proxy local content in memory or on disk. I don't know if this will work as expected with mod_deflate.
I have a lot of big .json files. Most readers are in this situation. The preview answers didn't talk about the returned "Content-type".
I you want the following request return a pre-compressed file with "Content-Type: application/json" transparently, use Multiview with ForceType
http://www.domain.com/(...)/bigfile.json
-> Content-Encoding:gzip, Content-Type: Content-Encoding:gzip
1) files must be rename: "file.ext.ext"
2) Multiview works great with ForceType
In the file system:
// Note there is no bigfile.json
(...)/bigfile.json.gz
(...)/bigfile.json.json
In your apache config:
<Directory (...)>
AddEncoding gzip .gz
Options +Multiviews
<Files *.json.gz>
ForceType application/json
</Files>
</Directory>
Short and simple :)