.htaccess mod_rewrite - Non-matching patterns - apache

I'm having trouble getting non-matching (negation) mod_rewrite patterns to work.
In the example below I want all requests redirected to "/promo-page", however, don't allow a redirect loop (hence the RewriteCond).
### Request URL: http://example.com/promo-page ###
RewriteCond %{REQUEST_URI} !^/$
RewriteCond %{REQUEST_URI} !/promo-page
RewriteRule .* /promo-page [R=302,L]
When a request for "/promo-page" is made, the RewriteCond rule is ignored and a redirect loop occurs.
Any ideas why the Exclamation Mark (!) isn't working? Is the syntax incorrect?
Thanks in advance.
UPDATE
I've also tried these rules in an online mod_rewrite tester and they also don't work (if you use "home" as the URL and "/home" as the REQUEST_URI).
http://martinmelin.se/rewrite-rule-tester/

Remove RewriteCond %{REQUEST_URI} !^/$ - it will always be true, as Jon says.

Thanks all for your answers and thoughts. I finally tracked down the issue, so here's the details in the hope it may help someone else down the track.
What was confusing the situation was more rules further down in the .htaccess file. These weren't posted in my original question as I didn't believe they were relevant and would even affect the outcome.
These additional rules re-write the Clean URL's into a GET request. I was under the (false) impression that %{REQUEST_URI} also includes the GET variables tacked onto the end of URL's. It doesn't. You must use %{QUERY_STRING} to separately check the content of the GET query string.
Mod-Rewrite Logging was very useful in helping me debug this issue. I wasn't able to enable it on our live/production cPanel server, so I installed XAMPP on my PC, enabled logging and played with the rewrite rules locally until I got it working.

Related

Block direct access to .php files, less the index.php file and ajax.php file

been looking for your help, i found a method, but it is not as i wish. if someone can help me.
What I want is that nobody can enter a direct URL with .php
example when I enter my domain.com/buy/product.php, I want it to be forbidden,
I was looking for information here, I found this code that worked for me but in .htaccess
RewriteEngine On
RewriteCond %{THE_REQUEST} "^.+? [^?]+\.php(?:[?/# ]|$)" [NC]
RewriteRule !^index\.php$ - [F,L,NC]
it worked fine for me, but the problem that I in a directory /include/ajax.php , I use an ajax. and it gives me error to execute the ajax by browsing.
Now what I'm thinking how to make it work with that htaccess code that you can enter the index.php and /include/ajax.php, I tried all means but it does not work for me.
In another case if you know any code to add to my php or how to do for my version which is version 7.3, but without ruining my code.
Rather than giving you the answer straight out, I'm going to give you some hints so that you aren't copying code you don't understand.
Each RewriteRule has three parts:
the pattern to match against the URL sent by the browser
the URL to rewrite to
an optional set of flags for extra options
Before each rule, you can optionally have one or more RewriteCond lines which apply extra conditions to the rule; each has three parts:
a variable to match against
the pattern to match
an optional set of flags for extra options
The most important flag in this case is [F], short for [forbidden], which says "if the rule matches, instead of rewriting or redirecting, just server a 403 response.
You should very rarely need to test against %{THE_REQUEST}, which is a raw version of the request line from the browser; much more often, you want %{REQUEST_URI} and/or %{QUERY_STRING}.
The patterns in both RewriteRule and RewriteCond can be negated (i.e. "must not match this pattern") by starting them with !
So, if you wanted to return a 403 for all URLs ending ".bad", except for URLs ending "not.bad" or "only-a-little.bad", you could write this (note that $ is the way to say "must end here" in the regex patterns):
RewriteCond %{REQUEST_URI} !not.bad$
RewriteCond %{REQUEST_URI} !only-a-little.bad$
RewriteRule .bad$ - [F]
Hopefully it should be straight-forward enough to see how to adapt that to your requirements.
The full list of options and variables available is in the Apache manual.
After 2 days of looking for some code, I was able to read and understand.
study how htaccess works.
Thanks to the users who guided me, I found the solution.
Although my title is not quite correct.
My intention was always to block all .php that always the user wanted to enter directly by .PHP, I had found the code above, but it did not work with a specific file in the /include/ajax.php folder, exactly it was an ajax, I could not find solution.
exactly it was an Ajax, I could not find the solution to make it work.
Until I managed to solve this way.
RewriteEngine on
RewriteCond %{THE_REQUEST} ajax\.php [NC]
RewriteRule ^ - [NC,L]
RewriteCond %{THE_REQUEST} .+\.php [NC]
RewriteRule ^ - [F,L]
This causes all .php to be blocked, except the index.php and the /include/ajax.php file.
This is how it worked for me.
If I am right or wrong, can you give me some guidance.
I leave this in case someone might find it useful in the future.
I was always recommended to route my php, that I would forget about these problems.
I will keep it in mind as I move forward in the future, to route my php.

.htaccess drupal 7 RedirectMatch or RewriteRule nothing seams to work

I'm having some real issues getting a redirect to work in .htaccess with drupal 7.
I have links like this:
example.com/vid/category/filter?subcat_filter_depth=125
and I need them to go to: (on same domain)
example.com/vid/category/filter?type=All&subcat_filter_depth=125
after = the number may be different like 67 or 32 etc. meaning that can be any number and whatever number is at the end of the original link needs to also be at the end of the new link.
I think the fact that the link is pretty much the same path just different filter is what is causing the issue as even the Drupal redirect url module will not allow it at an attempt to add them one at a time as they occur.
here is everything I've tried:
RedirectMatch 301 ^/vid/category/filter?subcat_filter_depth=(.*) /vid/category/filter?type=All&subcat_filter_depth=$1
RewriteRule ^(.*)/vid/category/filter?subcat_filter_depth=(.*) $1/vid/category/filter?type=All&subcat_filter_depth=$2 [R=301]
RedirectMatch ^/vid/category/filter?subcat_filter_depth=(.*) ^/vid/category/filter?type=All&subcat_filter_depth=$1
RedirectMatch 301 ^(.*)/filter?subcat_filter_depth=(.*) ^$1/filter?type=All&subcat_filter_depth=$2
RedirectMatch ^/(.*)/filter?subcat_filter_depth=(.*) ^/$1/filter?type=All&subcat_filter_depth=$2
RewriteRule "^/(.*)/filter?subcat_filter_depth=(.*)" "^/$1/filter?type=All&subcat_filter_depth=$2"
mod_rewrite is on and there is an AllowOverride pathed/to/the/.htaccess file under <Directory> inside <VirtualHost> in the 000-default.conf running on Debian Apache ..pretty much latest versions.
I know mod_rewrite is working because if I add a bad rule or rewrite with a syntax error I get error 500 response page.
I've searched and tried just about everything I can think of and nothing seems to work.
Any help getting this sorted and functioning would be greatly appreciated!
Both the RedirectMatch (mod_alias) and RewriteRule (mod_rewrite) directives match against the URL-path only, which notably excludes the query string.
To match against the query string you need to use RewriteRule with an additional condition (RewriteCond directive) that checks against the QUERY_STRING server variable.
This rule also needs to go near the top of the .htaccess file, before any existing rewrites.
For example:
RewriteCond %{QUERY_STRING} ^subcat_filter_depth=\d+$
RewriteRule ^vid/category/filter$ /$0?type=All [QSA,R=302,L]
This redirects example.com/vid/category/filter?subcat_filter_depth=<number> to example.com/vid/category/filter?type=All&subcat_filter_depth=<number>.
In .htaccess there is no slash prefix on the URL-path matched by the RewriteRule pattern. ie. ^vid/category (not ^/vid/category).
$0 is a backreference that contains the matched URL-path from the RewriteRule pattern.
QSA causes the original query string (eg. subcat_filter_depth=125) to be appended to the query string stated in the substitution string, ie. type=All becomes type=All&subcat_filter_depth=125.
Test with 302 (temporary) redirect to avoid potential caching issues. Only change to a 301 (permanent) redirect - if that is the intention - once you have confirmed it works as intended.
You will likely need to clear your browser cache before testing.
I was able to come up with a solution that worked prior to the answer (above) I marked as correct as my solution isn't quite as elegant.
I did realize after a bit of more research I needed to use a RewriteCond with %{QUERY_STRING} for what I was trying to achieve.
Again not as elegant as the answer above...but here is my code:
RewriteCond %{REQUEST_URI} ^/vid/category/filter [NC]
RewriteCond %{QUERY_STRING} ^(.*)=(.*)
RewriteRule (.*) /vid/category/filter?type=All&subcat_filter_depth=%2 [R=301,L]
This actual kept the url in the browser as it was input (/var/category/filter?subcat_filter_depth=) but showed the page as if it was opened with the proper filter for type=ALL and produced no errors both in browser and in Drupal dblog.
The above solution is more useful in explanation alone and gave me much better understanding of how to break up a URL and put it back together with modifications especially when dealing with strings that have variables that change like unique ID's.

Apache .htaccess redirect URL directories containing parameters

Sorry to be the asker of yet another tedious mod_rewrite question but after having made no progress in the last few hours, I thought it was time to ask ;)
I am trying to redirect URLs like these:
/some/thing?a=1 --> http://something-else.com/blah
/some/thing?a=1&b=whatever --> http://something-else.com/blah2
No need to keep the param values - the new URL will be hard-coded for each one I have to be redirected.
Have tried a few different things from other posts but with no joy so I am back to square one so any suggestions would be most welcome.
Thanks! :)
You can use the following rule-set:
RewriteEngine On
RewriteCond %{QUERY_STRING} ^a=1$
RewriteRule /some/thing http://something-else.com/blah [L]
This is indeed quite a common question, and people tend to overlook the QUERY_STRING variable. Have you tried it before?
This is what I used in the end:
RewriteEngine On
RewriteCond %{QUERY_STRING} ^(a=1&b=whatever)$
RewriteRule /some/thing http://something-else.com/blah2 [L,R=301]
I was adding the rules at the bottom rather than directly below the "RewriteEngine On" which was preventing it from working.
This solution does still append the params to http://something-else.com/blah2 which isn't exactly what I wanted but it will do.

mod_rewrite redirect specific .asp pages back to original server

I need to redirect traffic for a section of a redeveloped site back to the original site with apache mod_rewrite rules. I need to redirect all requests starting with http://www.example.com/page.asp back to the original site http://www.original.com/page.asp with the query string or anything following page.asp intact.
This seems simple enough, however I have had no luck with mod_rewrite generators or documentation on the web. My latest stab at the problem looks like this:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^http://www.example.com$ [NC]
RewriteRule ^page\.asp(.*)$ http://www.original.com/page\.asp$1 [R=301,NC]
I appreciate any insight into correcting this mod_rewrite rule. Other redirects are working fine.
I was able to get the rewrite to function properly using:
RewriteRule ^/page(.+) http://www.original.com/page$1 [R=301,NC,L]
I found this apache doc helpful: Resource Moved to Another Server

.htaccess mod_rewrite 301 redirect with nested exceptions?

I need a little help with my .htaccess before I deploy it!
I want to 301 redirect almost everything from elementalthreads.com to ethreads.com, excluding blog/wp-content/uploads, and /pommo.
Am I doing this right?:
RewriteEngine on
#exclude old uploads folder and /pommo
RewriteCond %{REQUEST_URI} !^/(blog/wp-content/uploads|pommo) [NC]
RewriteRule (.*) http://ethreads.com/$1 [R=301,L]
Will that transfer canonical pagerank?
Here's where I know I need help:
The old site has a wordpress blog, which I've cloned on the new domain. I'd love to preserve the permalinks, which are almost 1:1, eg:
http://www.elementalthreads.com/blog/ethreads-now-on-amazon-com/ redirects to
http://ethreads.com/ethreads-now-on-amazon-com/ (note /blog/ is missing here)
And the blog index http://www.elementalthreads.com/blog/ should redirect to http://ethreads.com/blog/, which seems like an exception to the above rule, since "/blog/" should only be preserved here?
I'm stumped about how to regEx or otherwise define these last two conditions/rules. Any help would be most appreciated!
That looks correct to me. However, you should not put this live without checking it, there really is nothing preventing you from being able to test it. One thing to bare in mind is that browsers can cache 301 response codes so when testing you should use [R,L] as your flags. Once you are happy add the [R=301,L] back in before deployment.
OK for points (1) & (2)
# only redirect the blog direcotry
RewriteRule ^blog/?$ http://ethreads.com/blog/ [NC,R=301,L]
# redirect all sub folders of blog to the new domain
RewriteRule ^blog/([\w-])/?$ http://ethreads.com/$1/ [NC,R=301,L]