what is this htaccess rule actually doing - apache

I have this condition and rule and want to know what actually is going on here
RewriteCond %{REQUEST_URI} ^/sitepages/newversion/
RewriteCond %{QUERY_STRING} ^(.*[?|&])page=dynamicpage
RewriteRule ^sitepages/newversion/(.*)$ /pages/oldversion/$1 [L]
Also very interested in a detail explaination of this line
RewriteRule ^sitepages/newversion/(.*)$ /pages/oldversion/$1 [L]
thanks

RewriteCond %{REQUEST_URI} ^/sitepages/newversion/
If the request URL starts with "/sitepages/newversion/",
RewriteCond %{QUERY_STRING} ^(.*[?|&])page=dynamicpage
and the query string contains "page=dynamicpage",
RewriteRule ^sitepages/newversion/(.*)$ /pages/oldversion/$1 [L]
then take the part of the URL after "sitepages/newversion/" and redirect the request to "/pages/oldversion/(the rest of the url)".
For example:
http://domain.com/sitepages/newversion/someleaf?page=dynamicpage
will get redirected to
http://domain.com/pages/oldversion/someleaf?page=dynamicpage

First of all your rule can be rewritten better as this:
RewriteCond %{QUERY_STRING} (?:^|&)page=dynamicpage(?:&|$) [NC]
RewriteRule ^sitepages/newversion/(.*)$ /pages/oldversion/$1 [L,NC]
Now for explanation part.
RewriteCond is matching a URI with query parameter page=dynamicpage
RewriteRule is matching a URI with pattern sitepages/newversion/(.*)$ which will match /sitepages/newversion/abc123 or /sitepages/newversion/foobar
(.*) is capturing group to populate $1 with the value abc123 in my first example.
In target we use /pages/oldversion/$1 that will become /pages/oldversion/abc123 for same example.
NC flag is for no case comparison.
L flag is for Last that makes mod_rewrite run the rewrite loop again.
Reference: Apache mod_rewrite Introduction
Apache mod_rewrite Technical Details

Related

How do I Redirect and Show Content with same urls?

I have a maybe simple Problem. I have serveral URLs that needed to be redirected in this way:
if the URL "/abc/" is called, it should show the content located under "xyz.html"
i can do that with
RewriteRule abc$ xyz.html
but "xyz.html" should be 301 redirecting to "/abc" if it is called.
This is my simple problem i am searching for an solution since hours.
it would be easy if its like "test.html" and /test/. i can do it like
RewriteRule ^(.+)\.html$ /$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_URI}.html [END]
But in my case i have a bunch of URLs with no pattern.
All i tried results to server misconfiguration.
Can you help me with that one sample?
thanks, kanuddel
Could you please try following.
RewriteEngine ON
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} ^/abc/? [NC]
RewriteRule ^(.*) /xyz.html [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} ^/xyz\.html/? [NC]
RewriteRule ^(.*) /abc/? [R=301,L]
Detailed Explanation:
Why there is redirection loop with normal rule writing: Question from OP is interesting and contradictory(kind of), why because lets say we write 1st rule to redirect(in backend) from abc url to xyz.html it will work fine. But then when we write our 2nd rule which is to rewrite url from xyz.html to abc/ which is exactly opposite of first rule. Hence it becomes a loop, ASAP 1st rules gets served it reaches out to 2nd rule and it serves it back to 1st rule thus a REDIRECTION INFINITE LOOP(till 50 cycles or so).
How to prevent redirection loop?
First since both rules are exactly opposite of each other so in a normal rule writing it will become a loop, now how could we prevent it to become a loop? Answer is using: RewriteCond(explained in next step)
I have used an ENVIRONMENT VARIABLE named ENV:REDIRECT_STATUS which will have any redirection status in its value. 2 things we need to understand about this variable.
1- Without any request redirection its default value is NULL.
2- Whenever we do a successful redirection its value becomes 200(NON ZERO), which we can make use of in our conditions part.
Detailed explanation of htaccess Rules:
Now coming to the condition explanation part: In RewriteRuleRewriteRule ^(.*) /xyz.html [L] I have NOT done any rewriting of url on browser why because of the THUMB RULE that we always want to show USER FRIENDLY URLs to users, so environment variable ENV:REDIRECT_STATUS will always be ZERO here.
Coming to 2nd RewriteRule now RewriteRule ^(.*) /abc/? [R=301,L] where user already using a user NON-friendly URL so first thing is I need to rewrite URL in browser to user friendly url hence R=301(redirection with permanent flag is used here). Once Redirection happens through this condition, 1st condition will start failing now why because that checks if REDIRECT_STATUS variable is NULL which is NOT after serving redirection from 2nd condition. Hence this is how it prevents loop by this small trick :)
Thanks for the great Explanation!
I tried it with a second URL, where "/xxx/" should show "zzz.html" But this gave me an Misonfiguration. I tried to shorten it like this:
RewriteEngine ON
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} ^/abc/? [NC]
RewriteRule ^(.*) /xyz.html [L]
RewriteCond %{REQUEST_URI} ^/xxx/? [NC]
RewriteRule ^(.*) /zzz.html [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} ^/xyz\.html/? [NC]
RewriteRule ^(.*) /abc/? [R=301,L]
RewriteCond %{REQUEST_URI} ^/zzz\.html/? [NC]
RewriteRule ^(.*) /xxx/? [R=301,L]

Apache manipulating query string on https

the following rules works on http but don't on https.
RewriteCond %{QUERY_STRING} "page=" [NC]
RewriteRule (.*) /$1? [L]
RewriteRule ^/path/file.html$ https://www.domain.tld/path/file/ [R=301,L]
Why the query_string part doesn't work in https?
Based on the comments of your question, it appears that you just want to remove the query string anytime there is a page parameter. This type of rewrite rule doesn't strip off or change the URL unless there is a redirect. So if you don't add R=301 or R to the rewrite rule, the query string will not be removed. All of the following worked on my server to remove the query string, and my server is 100% HTTPS:
RewriteCond %{QUERY_STRING} "page=" [NC]
RewriteRule (.*) /$1? [R=301,L]
Or you may be able to use the QSD flag instead of question mark:
RewriteCond %{QUERY_STRING} "page=" [NC]
RewriteRule (.*) /$1 [R=301,L,QSD]
Or you may be able to use something like this:
RewriteCond %{QUERY_STRING} "page=" [NC]
RewriteRule .* /? [R=301,L]
Or just R (for 302) instead of R=301:
RewriteCond %{QUERY_STRING} "page=" [NC]
RewriteRule (.*) /$1? [R,L]
But in no case was the query string removed unless I used a redirect.
Really all you need is QSD http://httpd.apache.org/docs/current/rewrite/flags.htm
RewriteCond %{QUERY_STRING} "page=" [NC]
RewriteRule (.*) /$1 [L,QSD]
I'm not sure why it would work on http but not https unless you're using separate vhosts for http and https and the settigns were slightly different
Remember that Rewrite rules are internal unless using the R flag. When you use the R flag it tells the browser to go to a different page causing a full server/client round-trip. Otherwise, it just changes the request and proceeds as normal.
I'm not really strong with .htaccess file, and I can't explain what's going on behind the scenes, but from my opinion your .htaccess file should look like this:
RewriteCond %{QUERY_STRING} page= [NC]
RewriteRule (.*) /$1? [L]
RewriteRule ^path/file.html$ https://www.domain.tld/path/file/ [R=301,L]
It work perfectly for
http://example.com?page=1
https://example.com/?page=1
http://example.com/path/file.html
https://example.com/path/file.html
Tested (with love) here

redirect url with query string to path, and url without query string must be internally rewritten

I've been trying and trying.
If one goes to:
www.domain.nl/vereniging
internally a page is requested from:
www.domain.nl/?p=vereniging
For that I use this:
RewriteCond %{QUERY_STRING} !(p=.*)$
RewriteRule ^(.+)$ ?p=$1 [NC]
If a users visits:
www.domain.nl/?p=vereniging
I want the users to be redirected to:
www.domain.nl/vereniging
For that I use:
RewriteCond %{QUERY_STRING} ^p=(.*)$ [NC]
RewriteRule ^$ http://www.domain.nl/%1? [NC,R=301]
(If I put RewriteCond %{REQUEST_FILENAME} !-d before this, it doesn't redirect anymore. That's strange because a query is not a directory right?)
Separately, these 2 chunks of code work.
However, if I put them together in 1 .htaccess it bitches about looping.I don't understand this, because the conditions should prevent looping.
Try applying the END flag to either the first or second RewriteRule.
Look at the END flag here: http://httpd.apache.org/docs/current/rewrite/flags.html
You need to check against the actual request:
RewriteCond %{THE_REQUEST} \?p=([^&\ ]+)
RewriteRule ^ /%1? [L,R=301]

htaccess - rewritecond issue

I have an htacess file for apache that isn't working properly.
I have a default cactch-all that grabs all requests however it's still catching the matched URL above it (ajax/*). I thought that condition to match urls not containing ajax would stop it but it isn't.
RewriteRule ^ajax/(.*)$ process_lite.php [QSA,L]
RewriteRule ^resources/(.*)$ resources/$1 [L]
RewriteCond %{REQUEST_URI} !\.(css|jpg|js|gif|png)$
RewriteCond %{REQUEST_URI} !^ajax
RewriteRule ^(.*)$ process.php [QSA,L]
Can someone help me out?
It's probably because the first rule matches /ajax/ requests and rewrites it to /process_lite.php, thus the RewriteCond %{REQUEST_URI} !^ajax doesn't match since the URI is now process_lite.php. The regular expression you use won't match anything anyways because REQUEST_URI variable will start with a leading slash. You can try changing the condition to:
RewriteCond %{REQUEST_URI} !^/process_lite.php
Additionally, the "resources" rule doesn't seem to do anything except end rewriting, you could change it to this if that's the goal:
RewriteRule ^resources/ - [L]

Redirect in combination with a rewrite condition in htaccess

I've got a cms-driven website, with no option to change the code. What I want to accomplish is creating friendly url's, using only apaches mod-rewrite engine.
The problem is I'm creating an infinite loop, because I first redirect the original url (index.php?id=21) to a friendly one (/friendly/) and then rewrite the '/friendly' part back to 'id=21'
I know there should be an extra condition or parameter to avoid looping in this case, but I can´t get one of the possible solutions to work.
Here´s the code:
RewriteCond %{query_string} ^id=21$ [NC]
RewriteRule /* /peuterspeelzaal? [R=301,L]
RewriteRule ^peuterspeelzaal$ index.php?id=21 [L]
You need to look at the request line in THE_REQUEST to see what originally has been requested:
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /[^?\ ]*\?id=21\ [NC]
RewriteRule /* /peuterspeelzaal? [R=301,L]
RewriteRule ^peuterspeelzaal$ index.php?id=21 [L]
I'm guessing you are rewriting in both directions to ensure that old links are redirected to the new friendly urls?
You could just add a dummy parameter to all your "friendly" rewrites so that they don't match the other rule:
RewriteCond %{query_string} ^id=21$ [NC]
RewriteRule /* /peuterspeelzaal? [R=301,L]
RewriteRule ^peuterspeelzaal$ index.php?id=21&dummy=1 [L]