mod_rewrite rule to prevent query string - apache

Ok i am testing a cms(joomla) installed on my personal webserver before putting it live.
And i want to be able to prevent the use of the query string, or more to the point prevent users from entering stuff on the query string (changing like articleid etc), but still allow the internal redirecting to use the query string.
Example
prevent someone from entering as the url
http://www.doamin.com/index.php?option=com_user&view=register
display Error page or redirect to index.php without query string
But still allow the rewrite rule
RewriteRule ^Register$ index.php?option=com_user&view=register
RewriteCond %{QUERY_STRING} !^$
RewriteRule ^index.php$ index.php? [R=301]
obviously redirects all query strings (but it also redirects /Register which isnt what i want)
The [L] flag on the end of the Register rewriterule doesnt make it stop the rule processing either.
EDIT:
Ended up answering this with a nudge from Daniel. See answer below

The mod_rewrite documentation says:
When you want to erase an existing query string, end the substitution string with just a question mark.
And though not mentioned in this sentence, the rewrite rule must not use the QSA flag.
As far as still allowing the rewrite rule:
RewriteRule ^Register$ index.php?option=com_user&view=register
You probably want that to appear below the rewrite rule to strip the query string. When it matches, the %{ENV:REDIRECT_STATUS} variable is set to 200 and mod_rewrite runs through the rewrite rules again. The rewrite rule to strip the query string would match on this second pass if a check that %{ENV:REDIRECT_STATUS} is not 200 were not used.
This will map all requests for index.php (with or without a query string) to index.php without a query string, but still allow /Register to be treated like /index.php?option=com_user&view=register:
RewriteCond %{ENV:REDIRECT_STATUS} !=200
RewriteRule ^index.php$ index.php?
RewriteRule ^Register$ index.php?option=com_user&view=register
Or, if you want to redirect to an error page if a request for index.php has a query string:
RewriteCond %{ENV:REDIRECT_STATUS} !=200
RewriteCond %{QUERY_STRING} !=""
RewriteRule ^index.php$ error.php? [R,L]
RewriteRule ^Register$ index.php?option=com_user&view=register
But I would just use the F flag:
RewriteCond %{ENV:REDIRECT_STATUS} !=200
RewriteCond %{QUERY_STRING} !=""
RewriteRule ^index.php$ - [F,L]
RewriteRule ^Register$ index.php?option=com_user&view=register

Ok while Daniels answer did not fully work, it got me started on the right track.
ended up needing two parts to do what i wanted, part of it was using the REDIRECT_STATUS variable
first needed
RewriteCond %{QUERY_STRING} !=""<br>
RewriteCond %{ENV:REDIRECT_STATUS} 200<Br>
RewriteRule .* - [L]<br>
.....
all my internal redirects
Like: RewriteRule ^Register$ index.php?option=com_register&view=register [L]
.....
then finally
RewriteRule .* - [F,L]
Makes it so that only thing able to be used are the urls defined by the internal redirects.

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]

Remove part of the query string with mod_rewrite

I am not very good with .htaccess at all, so I want to achieve something very simple, but I can't. What I want to do is to redirect certain files to test.php, and if test is ok, PHP redirects back to original page. It works fine, I add the "test=ok" part to the original URL, that way I don't get a redirect loop. However, I want to remove the test=ok query part from the original URL on redirection. How can I achieve that???
TL/DR
I have several URLs I want rewritten through mod_rewrite.
examples:
http://example.com/?time=1&test=ok
http://example.com/?test=ok
How can I remove the &test=ok and the ?test=ok parts using .htaccess?
Right now I have:
RewriteCond %{QUERY_STRING} ^test=ok$ [NC]
RewriteRule (.*) /$1? [L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} (/[^.]*|\.(php|html?|js))$ [NC]
RewriteCond %{QUERY_STRING} !test=ok [NC]
RewriteRule .* test.php [L]
But that doesn't remove the test=ok part... :(

How to rewrite /?blabla to another url?

How to rewrite with .htaccess
?p_action=user_profile to /user
It seems to ignore the "?" character and I dont know what to do....
Thanks
Some more details: ( my question has expanded now... :P)
I have www.example.com/?p_action=user_profile&post_author=34
and I want the browser to show www.example.com/nice_url
When I enter either the "ugly" or the "nice" url in the browser.
I.e. in case I enter www.example.com/nice_url , I want url_rewrite to happen,
In case I enter www.example.com/?p_action=user_profile&post_author=34, I want it to e redirected to www.example.com.
The problem: I could nod rewrite the "?" mark, but I overcame it (luckily).
Now this is the code I have:
RewriteRule ^nice_url$ ?p_action=user_profile&post_author=34 [L]
RewriteCond %{QUERY_STRING} p_action=user_profile&post_author=34
RewriteRule (.*) http://www.example.co.il/nice_url? [R=301,L]
HOWEVER, this creates a loop...
I tried adding this
RewriteCond %{ENV:REDIRECT_STATUS} 200 #looks if there was a redirect
RewriteRule .* - [L]
But it did not help. I guess this is because I am using Wordpress and there are already some redirects...
Please help. How can I make my browser always show "www.example.com/nice_url"?
Thanks!
Add the redirect status condition directly to the rule.
RewriteRule ^nice_url$ ?p_action=user_profile&post_author=34 [L]
RewriteCond %{ENV:REDIRECT_STATUS} !=200
RewriteCond %{QUERY_STRING} p_action=user_profile&post_author=34
RewriteRule .* http://www.example.co.il/nice_url? [R=301,L]
This prevents messing up other WordPress rules as well.

Can't get mod_rewrite to correctly (and invisibly) re-write my URLs?

I'm trying to make a URL shortening service for my website.
So instead of:
http://www.myfullwebsitename.com/page78/this-is-a-headline/
users will be able to visit:
http://abc.de/aBxf
which needs to redirect (invisibly!) to
http://abc.de/?shorturl=aBxf
which then 301 redirects via a database lookup to
http://www.myfullwebsitename.com/page78/this-is-a-headline/
I can do the DB lookup and the 301 redirect easily. It's the invisible intermediate redirect that I'm struggling with.
I've tried a LOT of different things, but none seems to work. This is what I currently feel should work:
RewriteCond %{HTTP_HOST} ^abc.de
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^/(.+) /?shorturl=$1
But instead of redirecting silently to
http://abc.de/?shorturl=aBxF
it redirects "noisily" (302) to
http://abc.de/aBxF/?shorturl=aBxF
What am I doing wrong?
Thank you!
There's a few things you can try.
I think your RewriteRule should look like this (without the forward /):
RewriteRule ^/(.+) ?shorturl=$1 [L]
This should at the very least stop it from redirecting to http://abc.de/aBxF/.
Your original rule may work if you add:
RewriteBase /
If it were me my rules would actually look like this:
RewriteBase /
RewriteCond %{HTTP_HOST} ^abc.de$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /redirect.php [L]
And then in PHP I would use $_SERVER['REQUEST_URI'] to get the URL (not sure what language you're using).
The rule can look like this:
RewriteRule ^(.*)$ /redirect.php?shorturl=$1 [L]
But I would make sure to mention the script by name. Part of what may be throwing your rules off is relying on Apache finding your index file after a rewrite.
The way Apache's rewrite rules work is as soon as the URL is rewritten, it actually will re-run the rules until no other rules will be found. The [L] flag for "last" says "stop here" - but it still starts over from the top. The RewriteCond with the !-f flag says "only if the file doesn't exist".
Use an absolute URL:
RewriteCond %{HTTP_HOST} ^abc.de
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^(.*)$ http://abc.de/?shorturl=$1 [R=301,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]