views:

671

answers:

5

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.

Thanks for any suggestions! :)

A: 
RewriteCond %{REQUEST_FILENAME} !-f
chaos
Seems too short to do what I want. Can you explain the logic a little bit? Thanks!
ZenBlender
+1  A: 
# 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

Nerdling
A: 

Try this:

RewriteEngine on
RewriteRule ^clients/abc/ - [L]
RewriteCond %{DOCUMENT_ROOT}clients/abc/$0 -f
RewriteRule .* clients/abc/$0 [L]
Gumbo
Is this intended for the .htaccess in the web root?
ZenBlender
Yes, it’s intended for the .htaccess file in the document root directory.
Gumbo
A: 

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]
jcrossley3
Good point. But in .htaccess files the pattern must not start with a slash. And it would be more convenient if you use the DOCUMENT_ROOT variable.
Gumbo
Can you clarify how this should be updated with DOCUMENT_ROOT? It doesn't work as-is.
ZenBlender
Replace in RewriteCond “/home/blah/www/” by “%{DOCUMENT_ROOT}” and remove it in the substitutions. Also remove the leading “/” in the regular expression patterns. Then it should work.
Gumbo
I updated per your comments, Gumbo, thanks. I wasn't considering .htaccess
jcrossley3
A: 

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!

ZenBlender