lotstolearn
lotstolearn

Reputation: 91

Redirect subdirectory to another subdirectory with mod_rewrite rewriterules

In an .htaccess inside the subdirectory alpha (a few directories down from root: http://domain.com/subsite/alpha/.htaccess) I want to catch all requests for files in:

and redirect them to:

My .htaccess looks like this:

RewriteRule ^images/(.*)$ %{REQUEST_URI}/\.\./\.\./img/$1 [R=302,NC,L]

This only works if there are no further directories inside /images. I could make it work from root like so

RewriteRule ^images/(.*)$ /subsite/alpha/img/$1 [R=302,NC,L]

but then I'd have to manually update this from alpha to beta, preprod, etc.

Basically, I need a way to isolate everything between ^ and images/. I tried some variations on this:

RewriteRule ^(.*)images/(.*)$ /$1/img/$2 [R=302,NC,L] RewriteRule ^(.*)images/(.*)$ ^$1/img/$2 [R=302,NC,L]

But it doesn't work because the .htaccess is in alpha and doesn't know about what's between it and root. Thus in the above, $1 isn't /subsite/alpha but whatever is between /alpha and images/.

Upvotes: 1

Views: 1993

Answers (1)

anubhava
anubhava

Reputation: 784918

You can use RewriteBase and use relative path:

RewriteEngine On
RewriteBase /subsite/alpha/

RewriteRule ^images/(.*)$ img/$1 [R=302,NC,L]

Or else if you want to avoid using RewriteBase then use this rule to generate dynamic RewriteBase:

RewriteEngine On

RewriteCond $0#%{REQUEST_URI} ^([^#]*)#(.*)\1$
RewriteRule ^.*$ - [E=BASE:%2]

RewriteRule ^(.*?/)?images/(.*)$ %{ENV:BASE}$1img/$2 [R=302,NC,L,NE]

How dynamic RewriteBase works:

  • It compares REQUEST_URI variable (which is complete path) with the URI matched by RewriteRule (which is relative to current path) and gets differential in %{ENV:BASE} variable.
  • You can use $0 captured from RewriteRule in your RewriteCond because mod_rewrite actually processes a ruleset backwards. It starts with the pattern in the RewriteRule, and if it matches, goes on to check the one or more RewriteCond.
  • So as you can see in a RewriteCond, the LHS (test string) can use back-reference variables e.g. $1, $2 OR %1, %2 etc but RHS side i.e. condition string cannot use these $1, $2 OR %1, %2 variables.
  • Inside the RHS condition part only back-reference we can use are internal back-references i.e. the groups we have captured in this condition itself. They are denoted by \1, \2 etc.
  • In your RewriteCond first captured group is ([^#]*). It will be represented by internal back-reference `\1.
  • As you can mark out that this rule is basically finding RewriteBase dynamically by comparing %{REQUEST_URI} and $0. An example of %{REQUEST_URI} will be /directory/foobar.php and example of $0 for same example URI will be foobar.php. ^([^#]*)#(.*)\1$ is putting the difference in 2nd captured group %2 or \2. Here t will populate %2 or \2 with the value /directory/ which is used later in setting up env variable %{ENV:BASE} i.e. E=BASE:%2.

Upvotes: 4

Related Questions