Conditional redirect in .htaccess depending on the number of path segments in the URL

SergioG

I would like to do a .htaccess redirect, depending on the number of path segments in the URL. However, if this condition is detected then no more RewriteRule conditions should be evaluated.

Let's suppose I have URL like this:

http://www.example.com/level1/level2/level3/...../levelx

and I would like to do a redirection using RewriteRule, depending on the number of "levels" that I have on the URL.

For instance, if I have three of more "levels" (something like http://www.example.com/levels/level1/level2/level3/level4/../100). I would like to redirect to something like: http://www.example.com/whatever.php?id=100 page

However I would use something like:

RewriteRule ^levels/(.+)/(.+)/(.+)/(.+)/(.+) basedir/whatever.php?id=$5

But the key on this question is to create a condition that acts when a number of detected slashes on original URL is more than on number (that could be variable).

MrWhite

There is no way of conventional "counting" in .htaccess. (You can define server-side rewrite maps that link to external programs, but I assume that is out of scope for this question.)

If you have a limited number of path segments then you can hardcode the responses. For example:

RewriteRule ^levels/$ /whatever.php?query=0 [R,L]
RewriteRule ^levels/[^/]*$ /whatever.php?query=1 [R,L]
RewriteRule ^levels/[^/]*/[^/]*$ /whatever.php?query=2 [R,L]
RewriteRule ^levels/[^/]*/[^/]*/[^/]*$ /whatever.php?query=3 [R,L]
RewriteRule ^levels/[^/]*/[^/]*/[^/]*/[^/]*$ /whatever.php?query=4 [R,L]
RewriteRule ^levels/[^/]*/[^/]*/[^/]*/[^/]*/[^/]*$ /whatever.php?query=5 [R,L]

I would use something like:

RewriteRule ^levels/(.+)/(.+)/(.+)/(.+)/(.+) basedir/whatever.php?id=$5

Capturing backreferences doesn't "count" them. $5 simply holds the value of the 5th captured subpattern. This is equivalent of hardcoding. However, bear in mind that the pattern .+ will also capture slashes (ie. URL path segments). So, the above regex only "counts" the first 5, when there could be many more. There is also a technical limit of 9 backreferences.

Workaround

A possible workaround is to build a query string (appending 1 character at a time) for each slash (path segment) found in the source string.

For example:

RewriteEngine On
RewriteCond %{QUERY_STRING} ^1*$
RewriteRule ^levels/(.*)/(.*)$ levels/$1-$2?%{QUERY_STRING}1 [N,DPI]
RewriteRule ^levels/([^/]*)$ /whatever.php?query=%{QUERY_STRING} [R,L]

Given a request for:

http://www.example.com/levels/lev1/lev2/lev3/lev4/lev5/lev6/lev7/lev8/lev9/lev10

Would result in an external redirect to:

http://www.example.com/whatever.php?query=111111111

Then in whatever.php you would count the length of the query URL parameter to determine the number of levels. Since we are strictly counting the number of slashes, the number of "levels" is count+1.

Explanation

The first RewriteRule repeatedly replaces all slashes in the original URL-path with hyphens (just an arbitrary character) via a looping internal rewrite (N flag). On each iteration, when a slash is replaced, we append a 1 to the end of the query string. The DPI flag (Discard Pathname Information) is required in this example to discard additional path-info from the original request that would otherwise be appended to the rewritten URL - this is necessary in order to prevent an endless rewrite loop (and possible server crash!).

The second RewriteRule triggers the external redirect, once all the additional slashes have been replaced in the URL-path. The query string (that now consists of a string of the form "11111") is appended to the redirected URL as part of the query URL parameter.

Caveats

  • There must be no query string on the original request. The above checks for one or more 1. This could perhaps be adapted as required.
  • The above "counts" the number of slashes, not strictly the number of path segments. So, a trailing slash at the end of the URL is still counted, although the last path segment is "empty". The regex could perhaps be adjusted if this is undesirable. Or a pre-rule could be used to remove a trailing slash.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related