Forum Moderators: phranque

Message Too Old, No Replies

Trying to fill in gaps for .htaccess RewriteCond

302 to page if IP not in range & file is outside of root or allowed folder

         

otem

7:51 pm on Feb 6, 2007 (gmt 0)

10+ Year Member



Hello,

I'm fairly new to writing rules in for my .htaccess file.

What I'm trying to do is to serve a 302 redirect to a page IF the ip address is outside of a range X AND the requested file is not in the root folder, folder Y, OR is the index file in the root.

302 Redirect if (ip address outside of range X && (requested file not in (root ¦¦ folder Y) ¦¦ is index file in root ))

This is what I have so far:

RewriteCond %{HTTP_HOST} ^123\.123\.123\.123 # IP Not In Range
RewriteCond ___ # Request is not in root or folder Y
RewriteCond ___ # Request is not index file in root
RewriteRule ^(.*)$ /file.php [R=302,L] # 302 Redirect to this page

Any ideas on how I can fill in the blanks, or any caviots I'm missing?

Thanks

otem

11:54 pm on Feb 6, 2007 (gmt 0)

10+ Year Member



Here's an update, but its not quite right.

Any ideas?

RewriteCond %{HTTP_HOST}!^123\.123\.123\.123
RewriteCond %{REQUEST_URI} ^(!/folder_y/(.*)¦!/[A-Za-z0-9\-_\.]*¦/index.php)$ [NC]
RewriteCond %{REQUEST_URI}!/file.php
RewriteRule (.*) /file.php [R=302,L]

Thanks

jdMorgan

11:59 pm on Feb 6, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



What is the IP address "range" -- Defining the range for mod_rewrite may or may not be simple, so please give an example. Also not sure what your index page might be named...

# If requesting client is not within 192.168.123.0 - 192.168.123.31
RewriteCond %{REMOTE_ADDR}!^192\.168\.123\.([12]?[0-9]¦3[01])$
# And requested URL-path is not in root (if $1 contains a slash, it's not in root)
RewriteCond $1 /
# But also not in folder Y
RewriteCond $1 !^Y/
RewriteRule ^(.*)$ http://www.example.com/file.php [R=302,L]
#
# If requesting client is not within 192.168.123.0 - 192.168.123.31
RewriteCond %{REMOTE_ADDR}!^192\.168\.123\.([12]?[0-9]¦3[01])$
# And "/" or index.html file requested
RewriteCond $1 !^(index\.html)?$
# And not already redirected to "file.php" (Prevent recursion)
RewriteCond $1 !file\.php$
RewriteRule ^(.*)$ http://www.example.com/file.php [R=302,L] # 302 Redirect to this page

In order to get through this, you need to "flatten" the logic to a single level of ANDed Boolean logic. For example, convert (NOT(A OR B)) to (NOT(A) AND NOT(B)) -- See "DeMorgan's Theorem" for more details.

You also need to know that the [OR] operator only operates between the current RewriteCond and the following RewriteCond, and that RewriteConds apply only to the single RewriteRule which follows them. This makes it impossible to implement your logic with a single rule.

And finally, getting back to the IP address range, be aware that there is no numeric range compare in mod_rewrite; Mod_rewrite can only do string compares -- That is, you are comparing the characters that express numbers, and not the numbers themselves.

Oh, and the "not file.php" RewriteCond may be redundant in the second rule, depending on whether it is in fact your "index file."

Replace all broken pipe "¦" characters above with solid pipe characters before use; Posting on this forum modifies the pipe characters.

Jim

otem

1:03 am on Feb 7, 2007 (gmt 0)

10+ Year Member



Thank you so much for your help Jim!

Your advice has helped move me in the right direction and allowed me to accomplish my task at hand.

While it works perfectly, I still don't understand this part:

RewriteCond $1 /

I thought the $1 was a variable, something used in the RewriteRule part. Is this different?

How would I read that expression out-loud?

Maybe, "If the following condition request variable contains a slash, then this rule is in agreement with the rewrite"?

Thanks again.

jdMorgan

2:21 am on Feb 7, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



$1 in a RewriteCond or RewriteRule back-references (or takes the matched value of) the first parenthesized (sub)pattern in the RewriteRule, so in this case $1 is equal to the URL-path as matched by the RewriteRule's non-specific ^(.*)$ pattern.

If it's not clear, be aware that the RewriteRule pattern is always evaluated first. Only if it matches are any of the RewriteConds evaluated. If they too match, then the rewrite or redirect specified by the rule is invoked. Thus RewriteRule back-references are available to both RewriteConds and to the RewriteRule itself, and RewriteCond back-references are available to subsequent RewriteConds and to the RewriteRule (as %1 through %9).

See the Ruleset Processing section and the descriptions of back-references in the mod_rewrite documentation if this isn't clear.

With a "(.*)" pattern back-referenced as $1 in a .htaccess context, RewriteCond patterns are identical to what would be used if you tested the %{REQUEST_URI} variable, except that the leading slash will be present in %{REQUEST_URI}, but not in the URL-path as seen by RewriteRule. So, using $1 in this ruleset actually simplified it, because it made testing for "not in root" easier than it would have been if we used


RewriteCond %{REQUEST_URI} ^/[^/]+/

to account for the presence of the leading slash on all URL-paths.

Jim