check if file exists in subdirectories - apache

I have an include file that contains a Rewrite which checks if a semaphore file exists, if not display a maintenance page.
RewriteCond %{DOCUMENT_ROOT}/maintenance.enable -f
RewriteCond %{REQUEST_URI} !/maintenance.html
RewriteRule ^/ http://mydomain/maintenance.html [L]
Normally it works, but I have now a VirtualHost with several applications answering on different context roots:
mydomain/app1
mydomain/app2
etc.
If I change the rule for each apps is working.. but since the number of applications are already a lot, and may increase, I need to create a single rule for all, something like this, where xxx can be any:
<Location /xxx>
RewriteCond %{DOCUMENT_ROOT}/xxx/maintenance.enable -f
RewriteCond %{REQUEST_URI} !/maintenance.html
RewriteRule ^/ http://mydomain/maintenance.html [L]
</Location>
ps. I'm using latest apache 2.4 version

I found a solution similar to what I wanted initially using a macro like this:
<Macro check_maintenance $context>
RewriteCond %{DOCUMENT_ROOT}/$context/maintenance.enable -f
RewriteCond %{REQUEST_URI} !/maintenance.html
RewriteRule ^/ http://mydomain/maintenance.html [L]
</Macro>
And in the vhost configuration added outside the Location directives:
use check_maintenance app1
use check_maintenance app2

Related

.htaccess rule for redirecting to parent

I am trying to redirect one of my urls to the parent folder using .htaccess file. I have tried the following rule
RewriteRule ^test/(.+)$ /test/ [L,R=301]
found from htaccess wildcard redirect to parent folder but it is not working (logs show too many redirects).
I also tried the other rules below but none of them worked
RewriteBase /
RewriteCond %{REQUEST_URI} !=/test/
RewriteRule ^(.*) /test/ [END,NC]
or
RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^test/(.+)$ /test/ [L,R=301]
The OS is ubuntu server. Any help or pointers is appreciated. Please let me know if I can furnish any other details to debug. Thanks
Following should work considering the parent directory is test
RewriteEngine On
RewriteRule ^(test/).* /$1 [R=301,L]
Add this to disable MultiViews:
Options -MultiViews
The Apache docs on mod_negotiation, describes what the Multiviews Option does, when enabled:
If the
server receives a request for /some/dir/foo and /some/dir/foo does not
exist, then the server reads the directory looking for all files named
foo.*, and effectively fakes up a type map which names all those
files, assigning them the same media types and content-encodings it
would have if the client had asked for one of them by name. It then
chooses the best match to the client's requirements, and returns that
document.
Use:
Options -MultiViews
RewriteEngine on
RewriteRule ^test/(.+)$ /test/ [NC,L,R=301]
In your specific folder
RewriteEngine On
RewriteRule ^rootFName(.*) /rFile.php [QSA,R=301,L]

apache redirects with different destination depending on whether one of several files exists

I have a static website (served by Apache) where one can download software packages. These packages first appear in the "devel" section of the site and then at some point they become available in the "release" section as well. The packages can live in one of several "repositories", but each package is guaranteed to have a unique name across all repositories. Let's say that my repository names are repos1, repos2, and repos3.
So currently I have URLs like this:
/packages/release/repos1/html/mypkg.html
/packages/devel/repos1/html/mypkg.html
I want to set up redirects such that a user can go to:
/packages/mypkg/
...and the rewrite rule will try all the following URLs and redirect to the first one that exists (or to the 404 page if none do). So for the request /packages/mypkg/:
/packages/release/repos1/html/mypkg.html
/packages/release/repos2/html/mypkg.html
/packages/release/repos3/html/mypkg.html
/packages/devel/repos1/html/mypkg.html
/packages/devel/repos2/html/mypkg.html
/packages/devel/repos3/html/mypkg.html
It's not clear to me how to do this with mod_rewrite. I know there is the special RewriteCond pattern -f, but it seems before I can use it I have to process the REQUEST_FILENAME in such a way that I can parse out the package name with a backreference.
Just to make things more complicated, if the user knows whether they are looking for a release or devel package I want to honor that, so /packages/devel/mypkg/ should redirect to /packages/devel/X/html/mypkg.html where X is the first repository where Apache finds the file. Any ideas?
There's no elegant way of doing this with mod_rewrite.
Anyway, you can put this code in your /packages/.htaccess
Options -Indexes
RewriteEngine On
RewriteBase /packages/
################################################################################
# /packages/release/xxx or /packages/devel/xxx are internally rewritten to
# /packages/release/reposX/html/xxx.html or /packages/devel/reposX/html/xxx.html
# Note: (reposX) X is the first repos where xxx is found
################################################################################
RewriteCond %{DOCUMENT_ROOT}/packages/$1/repos1/html/$2\.html -f
RewriteRule ^(release|devel)/([^/]+)/$ $1/repos1/html/$2.html [L]
RewriteCond %{DOCUMENT_ROOT}/packages/$1/repos2/html/$2\.html -f
RewriteRule ^(release|devel)/([^/]+)/$ $1/repos2/html/$2.html [L]
RewriteCond %{DOCUMENT_ROOT}/packages/$1/repos3/html/$2\.html -f
RewriteRule ^(release|devel)/([^/]+)/$ $1/repos3/html/$2.html [L]
################################################################################
# /packages/xxx is internally rewritten to
# /packages/release/reposX/html/xxx.html or /packages/devel/reposX/html/xxx.html
# Note: all release repos are fetch first, then devel ones
# (reposX) X is the first repos where xxx is found
################################################################################
RewriteCond %{DOCUMENT_ROOT}/packages/release/repos1/html/$1\.html -f
RewriteRule ^([^/]+)/$ release/repos1/html/$1.html [L]
RewriteCond %{DOCUMENT_ROOT}/packages/release/repos2/html/$1\.html -f
RewriteRule ^([^/]+)/$ release/repos2/html/$1.html [L]
RewriteCond %{DOCUMENT_ROOT}/packages/release/repos3/html/$1\.html -f
RewriteRule ^([^/]+)/$ release/repos3/html/$1.html [L]
RewriteCond %{DOCUMENT_ROOT}/packages/devel/repos1/html/$1\.html -f
RewriteRule ^([^/]+)/$ devel/repos1/html/$1.html [L]
RewriteCond %{DOCUMENT_ROOT}/packages/devel/repos2/html/$1\.html -f
RewriteRule ^([^/]+)/$ devel/repos2/html/$1.html [L]
RewriteCond %{DOCUMENT_ROOT}/packages/devel/repos3/html/$1\.html -f
RewriteRule ^([^/]+)/$ devel/repos3/html/$1.html [L]

.htaccess to vhost

Anyone know what to put in vhost.conf for apache to replicate this (from .htaccess):
RewriteEngine on
RewriteCond $1 !^(index\.php|images|scripts|css|uploads|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
Basically I want all requests except those for /images, /scripts or /css to go through /index.php.
It works when I use the .htaccess file but I'd like to know how to do it via vhost.conf as well. Anyone know if it's better to use one over the other as well (vhost.conf vs htaccess) in terms of performance, stability, etc?
It should work when prepending the pattern with /, either:
RewriteCond $1 !^(index\.php|images|scripts|css|uploads|robots\.txt)
RewriteRule ^/(.*)$ /index.php/$1 [L]
Or:
RewriteCond $1 !^/(index\.php|images|scripts|css|uploads|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
The disadvantage of .htaccess files is simply that they virtually need to be interpreted with every request while the virtual host configuration is just interpreted once when the server is started.
Gumbo++
I wrote this article on the httpd wiki to cover questions like this one.
http://wiki.apache.org/httpd/RewriteContext

Use symfony 1.4 without changing apache configuration

Is it possible to set the /web directory as webroot without changing apache configuration file?
I tried using the following .htaccess code, but if i go to localhost/module/, it displays 404 error. But if i go to localhost/web/module/ then everything works.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule sf/(.*) lib/vendor/symfony/data/web/sf/$1 [L]
RewriteRule ^$ web/ [L]
RewriteRule (.*) web/$1 [L]
</IfModule>
i do like this on the root :
RewriteEngine On
RewriteBase /
RewriteRule (.*) ./web/$1 [L]
And edit web/.htaccess uncommented the 'RewriteBase /' line.
this make all the mysite.com/aaaa/bbbb works like mysite.com/web/aaaa/bbbb
Short answer: no.
Bit longer: you will have to edit the apache config at least to give it permission to access the web/ directory, so even if you symlink your web folder to /var/www, it will not work.
This is quiet similar to my question Symfony on virtual host (document root problem).
This is my .htaccess in the project root directory:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/images/ [OR]
RewriteCond %{REQUEST_URI} ^/js/ [OR]
RewriteCond %{REQUEST_URI} ^/css/
RewriteRule ^(.*)$ /web/$1 [L]
RewriteCond %{REQUEST_URI} !^/web/
RewriteRule ^(.*)$ /web/index.php [QSA,L]
This solved my problem but symfony tries to generate every url (eg. using url_for) from the document root so instead of url like domain.com/my-article it generates domain.com/web/my-article.
I had to slightly modify my PatternRouting class to trim the /web prefix from each url. I think this is not the best solution but it works.
Also if I want to access backend application I have to call always /web/backend.php/ because I don't want to have so many rewrite rules in the .htaccess.
If you want to see my extended PatternRouting class source code I'll paste it here.
Yes, it is possible. Copy everything from web/ up a level to your document root. Edit index.php to reflect the fact that everything it includes is now one level closer to its current directory than it used to be (one less ../). You won't have to edit a single other Symfony file.

Redirect requests only if the file is not found?

I'm hoping there is a way to do this with mod_rewrite and Apache, but maybe there is another way to consider too.
On my site, I have directories set up for re-skinned versions of the site for clients. If the web root is /home/blah/www, a client directory would be /home/blah/www/clients/abc. When you access the client directory via a web browser, I want it to use any requested files in the client directory if they exist. Otherwise, I want it to use the file in the web root.
For example, let's say the client does not need their own index.html. Therefore, some code would determine that there is no index.html in /home/blah/www/clients/abc and will instead use the one in /home/blah/www. Keep in mind that I don't want to redirect the client to the web root at any time, I just want to use the web root's file with that name if the client directory has not specified its own copy. The web browser should still point to /clients/abc whether the file exists there or in the root. Likewise, if there is a request for news.html in the client directory and it does exist there, then just serve that file instead of the web root's news.html. The user's experience should be seamless.
I need this to work for requests on any filename. If I need to, for example, add a new line to .htaccess for every file I might want to redirect, it rather defeats the purpose as there is too much maintenance needed, and a good chance for errors given the large number of files.
In your examples, please indicate whether your code goes in the .htaccess file in the client directory, or the web root. Web root is preferred.
# If requested resource exists as a file or directory, skip next two rules
RewriteCond %{DOCUMENT_ROOT}/$1 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule (.*) - [S=2]
#
# Requested resource does not exist, do rewrite if it exists in /archive
RewriteCond %{DOCUMENT_ROOT}/archive/$1 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/archive/$1 -d
RewriteRule (.*) /archive/$1 [L]
#
# Else rewrite requests for non-existent resources to /index.php
RewriteRule (.*) /index.php?q=$1 [L]
From Rewrite if files do not exist
How about this?
# If requested resource exists as a file or directory go to it
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (.*) - [L]
# Else rewrite requests for non-existent resources to /index.php
RewriteRule (.*) /index.php?q=$1 [L]
I seemed to have at least one problem with each of the examples above. %{DOCUMENT_ROOT} seemed to do the wrong thing in certain places, and some / characters seem to be missing. Here is my solution, which goes in the .htaccess in the web root.
Instead of using two rules (one for the case where the file under clients/ is found, and one for not found), all I need to check is if the requested file (or directory) does NOT exist. Because if it exists, no change is needed, it can just use the file provided in the client dir. Here's the code I settled on:
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}/clients/$1/$2 !-f
RewriteCond %{DOCUMENT_ROOT}/clients/$1/$2 !-d
RewriteRule ^clients/([^/]+)/(.*)$ $2 [L]
Thanks for your help!
RewriteCond %{REQUEST_FILENAME} !-f
Try this:
RewriteEngine on
RewriteRule ^clients/abc/ - [L]
RewriteCond %{DOCUMENT_ROOT}clients/abc/$0 -f
RewriteRule .* clients/abc/$0 [L]
I think you want something along these lines:
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}clients/$1/$2 -f
RewriteRule ^clients/([^/]+)/(.*)$ %{DOCUMENT_ROOT}clients/$1/$2 [L]
RewriteRule ^clients/([^/]+)/(.*)$ %{DOCUMENT_ROOT}$2 [L]