Redirect for generic files

If I have two folders - let’s call them “specific” and “generic” and the “specific” folder is the one being referenced to access the site then how do I set things up so that if a given file or folder is not found inside “specific” that the corresponding file or folder from “generic” gets substituted instead?

The idea is to be able to set up several specific sites that share a large portion of their code that will be stored in the generic folder. Only those files needing to be specifically overridden for the specific sites (eg. config files) will be stored in the specific folders.


# +FollowSymlinks is needed for mod_rewrite to work
# I always disable MultiViews because I don't like it. Not necessary for this example to work 
Options +FollowSymlinks -MultiViews

# enable mod_rewrite
RewriteEngine On
# If the request is not for an existing directory, AND ...
RewriteCond %{REQUEST_FILENAME} !-d
# ... the request is not for an existing file, AND ...
RewriteCond %{REQUEST_FILENAME} !-f
# ... the request is not for an existing symlink, THEN ...
RewriteCond %{REQUEST_FILENAME} !-l
# rewrite "specific" to "generic"
RewriteRule ^specific/(.*)$ generic/$1 [L]

Of course you can add R=301 to the [L] if you want the browser to 301 redirect, but I don’t think that’s needed in this case?

Note that the code does not check whether the file exists within generic, it just assumes it does, or that the generic dir will somehow generate a 404 if it doesn’t.

Thanks Remon. I had tried numerous variations not too different from this but hadn’t quite got close enough to have it work the way I wanted.

Stephen,

Excellent information from Rémon but I’d recommend adding a check that the file does exist in the generic directory before making the redirection.

Regards,

DK

David,

I decided to swap the folders the other way around. Pointing all of the domains to the generic folder and having it redirect to specific ones when files are not found looks to be a much simpler approach.

So how do I modify the following so that it does the additional check. For example if http://specific1.com/images/logo.gif is not found that it checks if http://specific1.com/specific1.com/images/logo.gif exists before redirecting to it?

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !^/%{HTTP_HOST}/
RewriteRule ^(.*)$ /%{HTTP_HOST}/$1 [L]

Hi Stephen,

Either way, checking for the existence of a redirection is a smart thing to do (unless it’s known to exist by virtue of your website’s structure).

Youve confused me with the specific1.com/specific1.com URL but let me answer generically:

...

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l # do you use symbolic links?
RewriteCond {server_path_to_other host}/$1 -d
RewriteRule ^(.*)$ %{other_host}/{path}/$1 [L,R=301]

Okay, I’ve assumed that your two domains are on the same account on the server so that PHP does have access to both. Anyway, the question you were asking was HOW to check that the redirection file exists before redirecting and this should give you the idea. The explanation (for others):

  1. The first three RewriteCond statements are checking for a 404 at the requested server.

  2. The fourth RewriteCond takes advantage of two things: First, that both domains are on the same account so PHP can access files from both AND that the following RewriteRule (RewriteRules are processed before the RewriteCond statements so $1 already exists) captures the %{REQUEST_URI} as $1 (alternatively, use %{REQUEST_URI} then uses the SERVER PATH to the corresponding file on the second server to check that it exists as a file (change the -d to -f if you want to redirect to a directory).

  3. The RewriteRule then, if all the RewriteCond statements evaluate as TRUE, redirects to the file on the second server. I needed to use pseudo code as I’m not sure if two domains are really being handled by this AND whether the path to the request is the same on both servers.

Stephen, if I did not understand correctly (I probably didn’t), then the fourth RewriteCond and RewriteRule can probably be simplified greatly. Of course, PM me with your e-mail address if you want to take this offline.

Regards,

DK

Generic is a folder that doesn’t have a domain name of its own - it contains files and folders to be shared between a (hopefully) growing number of domains.

All of the domain names will point to this folder to pick up the common files. So all the domains point to the same folder they don’t point to different servers or even different folders on the same server.

As well as the images, includes, plots, forum, and gallery sub-folders under the generic folder and containing shared files there will also be an additional folder for each domain that points to the generic folder that will have the same images, includes, plots, forum, and gallery sub-folders under it to hold the files specific to that domain. To make it really easy to identify which of these specific folders belongs to which domain I am going to use the same name for the folder as the domain name - that way I only need one redirect for all the domains and not one per domain

So with what I have so far:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !^/%{HTTP_HOST}/
RewriteRule ^(.*)$ /%{HTTP_HOST}/$1 [L]

The first three conditions check for not found in the generic folders and thr fourth was added to hopefully eliminate infinite recursion in the specific folders if the file doesn’t exist in either place.

So a request for specific1.com/image/logo.gif should start in the generic folder and look for /images/logo.gif and if it can’t find that it then should look for /specific1.com/images.logo.gif

I can see how RewriteCond %{HTTP_HOST}/%{REQUEST_FILENAME} -d would work for the files directly in the generic folder if not found in the corresponding specific folder but can’t see how that would apply to files in the generic and corresponding specific sub-folders.

Stephen (et al),

Because it looks like the domain names are in subdirectories of the generic, they are unable to be addressed directly (they are above the webspace of the domain names). IMHO, the best way to do this is to PARK (cPanel term for shared folder for multiple domain names) the specific domains on the generic domain name. Requests made of the specific domain can then (invisibly) redirect to its own subdirectory IF the domain-specific file exists, otherwise, the request would default to the generic domain’s file. The only problem I can see with this would be providing domain-specific 404’s but that can be done, too, with more mod_rewrite statements. Of course, the generic and specific domains MUST use a common name for all files.

The way this would be done might be:

RewriteEngine on

# Test if specific file exists and redirect to that
RewriteCond %{HTTP_HOST} (domain1|domain2|...|domainx) 
# NOTE: be consistent in domain capitalization
# - redirect if no match to lowercase version to match subdirectory capitalization
# this is merely to ensure that the requested domain exists;
# its domain-specific files will be in a subdirectory of the same name, i.e., domain1.tld
RewriteCond %{DOCUMENT_ROOT}/%{HTTP_HOST}/$1 -f 
# This only checks for files; I wouldn't do this for directories as the directory level would be very convoluted
RewriteRule ^(.*)$ %{HTTP_HOST}/$1 [L]
# This would redirect to the subdirectory but only if the file exists

To handle 404’s, continue the code:

RewriteCond %{REQUEST_FILENAME} !-f
# Again, specific to files!
RewriteRule ^(.*)$ %{HTTP_HOST}/404_script.php?uri=$1 [L]
# I've added the uri key and %{REQUEST_URI} in case
# the 404_script.php is a smart script and can do something intelligent with it

I’ve turned your question around for the simple reason that, if the specific domains were ADDON domains with their %{DOCUMENT_ROOT} below the generic %{DOCUMENT_ROOT}, they would be forced to fetch the content from the generic domain and insert in their own. IMHO, that would be just too ugly and unnecessarily complex!

Regards,

DK