.htaccess mod-rewrite conditional statements and sending GET request? - .htaccess

Not necessarily a problem, just something that I am not yet knowledgeable enough to do. I have an .htaccess file that I am using for url rewriting. This is what I have now.
ErrorDocument 404 /inc/error_documents/404.php
ErrorDocument 503 /inc/error_documents/503.php
# For security reasons, Option followsymlinks cannot be overridden.
#Options +FollowSymLinks
Options +SymLinksIfOwnerMatch
RewriteEngine ON
RewriteRule ^home$ /index.php [nc]
RewriteRule ^(about|contact|giving-tree)/?$ /$1.php [nc]
RewriteRule ^giving-tree/([0-9+]?)/?$ giving-tree.php?ageBegin=$1 [nc]
RewriteRule ^giving-tree/([0-9+]?)/([0-9+]?)/?$ giving-tree.php?ageBegin=$1&ageEnd=$2 [nc]
RewriteRule ^giving-tree/([0-9+]?)/([0-9+]?)/([0-9+]?)/?$ giving-tree.php?ageBegin=$1&ageEnd=$2&page=$3 [nc]
What I want to be able to do is make some of the parts in the 3 bottom rules optional. I know that I can accomplish this with RewriteCond, but I'm not sure how. What I need is basically this:
RewriteCond %{HTTP_HOST} ^hearttohandparadise.org/giving-tree
RewriteRule /beginAge-([0-9+]) #make it send GET request with beginAge as the variable
RewriteRule /endAge-([0-9+]) \?beginAge=$1 #make it send GET request with endAge as the variable
etc... etc...
Is there any way to accomplish this just by relying on .htaccess? or am I just fantasizing?
Forgive me is I sound stupid.

No, it's a perfectly valid idea. You'd basically want to allow the user to write the URI in an unstructured manner, without a strict order imposed, right? Like, I could write giving-tree/page-6/endAge-23?
If so, this is what you're looking for:
RewriteRule /beginAge-([0-9]+) giving-tree.php?beginAge=$1 [QSA,NC]
RewriteRule /endAge-([0-9]+) giving-tree.php?endAge=$1 [NC,QSA]
RewriteRule /page-([0-9]+) giving-tree.php?page=$1 [NC,QSA]
You see, if any part of the URI matches the expression "/beginAge-([0-9]+)", it'll be redirected to giving-tree.php?beginAge=$1; the magic is done by the QSA, Query String Append, option, which, well, appends any existing query string to the resulting URI. So as more and more matches are found and more and more GET parameters added, the query string just grows.
If you want a stricter thing, where some parameters are optional, but their order is fixed, then it's uglier by magnitudes:
RewriteRule /(beginAge-)?([0-9]+)/?(endAge-)?([0-9]+)?/?(page-)?([0-9]+)? giving-tree.php?beginAge=$2&endAge=$4&page=$6 [NC]
I just made everything optional by using the ? operator. This one may use some prettifying/restructuring.
(Alternatively, you could just do this:
RewriteRule ^giving-tree/([^/]+)/?$ process.php?params=$1 [nc]
That is, grabbing the entire part of the URI after the giving-tree part, lumping the whole thing into a single parameter, then processing the thing with PHP (as it's somewhat better equipped to string manipulation). But the first version is certainly more elegant.)
By the way, are you sure about the ([0-9+]?) parts? This means "One or no single character, which may be a digit or the plus sign". I think you meant ([0-9]+), i.e. "one or more digit".

Related

Correct .htaccess RewriteCond?

I have spent hours looking for a solution, but .htaccess rules seem way over my head. I have this rule:
RewriteRule ^(.*)$ wikka.php?wakka=$1 [QSA,L]
and I need it to be applied only if there is anything beyond the domain name, ie. www.example.com/xyz but NOT with just www.example.com because then I only need to display a simple index.php instead {no address translation}.
How do I do that?
RewriteRule ^(.*)$ wikka.php?wakka=$1 [QSA,L]
You just need to change the * (0 or more) in the RewriteRule pattern to + (1 or more). For example:
RewriteRule (.+) wikka.php?wakka=$1 [QSA,L]
I also removed the anchors ^ and $, since they are not necessary here. You are grabbing everything anyway, so saying you are grabbing everything from the start to the end is just not necessary.
Also, unless you require the query string from the original request I would remove the QSA flag. By itself this rule will result in a repeated query string of the form ?wakka=wikka.php&wakka=xyz - where xyz is the intial request. This still "works" if reading the URL params with PHP as wakka=xyz will override the earlier parameter.

mod_rewrite doesn't actually... re-write the URL

Basically, I've been trying to make some friendly URL's via .htaccess using mod_rewrite - and I've managed to get it to work... but only with basic stuff like:
RewriteEngine On
RewriteBase /
RewriteRule ^profile.php http://www.google.co.uk [L]
So mod_rewrite works, and I can re-direct to other sites, other files/directories in my server, etc. - but it seems to not work when I use this:
RewriteEngine On
RewriteBase /
RewriteRule ^profile.php?user=$1 ^profile/user/([^/]*)/$ [L]
Any help on this would be great, as I pretty much suck at mod_rewrite, but it's something I need to learn.
Cheers!
Change your [L] to [R,L] to force an actual HTTP redirect. Otherwise it just does the rewriting internally (when possible), which only affects the mapping from the URI to the filesystem. (See the description of the [R] flag at http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriteflags.)
Wrong.
## rewriting from to
RewriteRule ^profile.php?user=$1 ^profile/user/([^/]*)/$ [L]
Should be
## rewriting from to
RewriteRule ^profile/user/([^/]+)$ profile.php?user=$1 [L]
Your configuration currently is this:
RewriteEngine On
RewriteBase /
RewriteRule ^profile.php?user=$1 ^profile/user/([^/]*)/$ [L]
In the RewriteRule you swapped the from and to parameters.
Assuming that on your server there is a directory structure like this:
/var/www/htdocs/profile/user/albert
/var/www/htdocs/profile/user/bob
Then you can use the following rule:
RewriteCond ${QUERY_STRING} ^user=(\w+)$
RewriteRule ^profile\.php$ profile/user/%1 [L]
There are some points that you got wrong here:
The request to "/profile.php?user=bob" first gets split into the Request URI and the Query String. Only the Request URI will be used by mod_rewrite. Therefore you have to handle the query string separately.
I restricted the user name to only [A-Za-z0-9_]. If I had allowed all characters, an attacker could easily call /profile.php?user=../../config.php, which would be rewritten to profile/user/../../config.php, and you probably don't want to share that file with the world.
The arguments to the RewriteRule directive are completely different regarding their syntax.
The first argument (the from part) is a regular expression, which usually starts with a caret ^ and ends with a dollar $.
The second argument (the to part) is the replacement, which is almost only a simple string, with only some special features. This string usually doesn't start with a caret, but looks rather like a pathname.

Fixing Rewrite Rules and Conditions In HTACCESS file

Well lets say I have this follow code in my htaccess file,
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^/]+)$ $1.php
RewriteRule ^forums/([0-9]+) forums.php?category=$1 [NC]
I was wondering how would I, with the above code, redirect certain extensions in a url to my websites 404 page.
For instance, if this link mywebsite.com/forums has any extension at the end of it such as .asp, .php, .html, and so forth it then would get redirected to my 404 page.
And on a quick side note how can I limit the last RewriteRule to only a certain forward slash where mywebsite.com/forums/2 would show the page fine and anything after that certain limit such as mywebsite.com/forums/2/so on... would be redirected to my 404 page.
Anyone have any ideas?
If I understand the question properly, then you need to firm up the regular expressions to only match the patterns you really want - at the moment, they're a bit too lenient for your needs.
For example:
RewriteRule ^([^/]+)$ $1.php
This will match anything without a trailing slash, whereas if you wanted to restrict it to only match, say, things without a trailing slash and consisting of alphanumeric characters, then you might do this:
RewriteRule ^([a-zA-Z0-9]+)$ $1.php
(You could achieve the same effect for certain extensions only by using a lookahead assertion, but that complicates your regular expression. I feel it's probably saner (and easier on the mind) to think about the patterns you really want matched, and then express those up-front.)
Likewise, your latter example:
RewriteRule ^forums/([0-9]+) forums.php?category=$1 [NC]
will match anything which starts with the string forums/, followed by one or more digits, whether or not there's anything after that. Adding an end anchor ($) as you have above
RewriteRule ^forums/([0-9]+)$ ...
will assert that the string ends after the digits.
This relies on the fact that if mod_rewrite can't find a match, it won't attempt any rewrites, and will (in the absence of any explicit resource at that path) fall through to Apache's 404 handling, which is then up to you to override.

.htaccess questions

Say I have the following .htaccess file:
RewriteEngine On
RewriteCond %{HTTP_COOKIE} name=value [NC]
RewriteRule ^image01.gif$ http://www.domain.tld/images/partner/image01.gif [NC,QSA]
RewriteCond %{HTTP_COOKIE} name=value [NC]
RewriteRule ^image02.gif$ http://www.domain.tld/images/partner/image02.gif [NC,QSA]
What do NC and QSA mean?
Also, instead of repeating the same RewriteCond twice is there to use it just once and have it apply to both RewriteRules?
Finally, if the above .htaccess is located at http://www.domain.tld/images/ why doesn't a RewriteRule like this work?:
RewriteRule ^image02.gif$ /images/partner/image02.gif [NC,QSA]
Or maybe this?:
RewriteRule ^image02.gif$ partner/image02.gif [NC,QSA]
The square bracket options are documented in the RewriteRule manual page:
'nocase|NC' (no case):
This makes the Pattern case-insensitive, ignoring difference
between 'A-Z' and 'a-z' when Pattern is matched against the current URL.
'qsappend|QSA' (query string append):
This flag forces the rewrite engine to append a query string part
of the substitution string to the
existing string, instead of replacing
it. Use this when you want to add more
data to the query string via a rewrite
rule.
As far as I know, the RewriteCond directives affect the RewriteRule they precede. If you were setting rules in the main confing file you could write the common directives in a file and include it several times but that's not an option in .htaccess files, sorry.
Your directive works for me, although you probably mean this:
RewriteRule ^image02\.gif$ /images/partner/image02.gif [NC,QSA]
How are you testing it exactly?
NC is for No Case, meaning it can be upper or lower case and it will take you to the same page.
QSA is for query string append. Not really sure on this one, however a quick search http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html sheds a bit more light on this one.

301 Redirecting URLs based on GET variables in .htaccess

I have a few messy old URLs like...
http://www.example.com/bunch.of/unneeded/crap?opendocument&part=1
http://www.example.com/bunch.of/unneeded/crap?opendocument&part=2
...that I want to redirect to the newer, cleaner form...
http://www.example.com/page.php/welcome
http://www.example.com/page.php/prices
I understand I can redirect one page to another with a simple redirect i.e.
Redirect 301 /bunch.of/unneeded/crap http://www.example.com/page.php
But the source page doesn't change, only it's GET vars. I can't figure out how to base the redirect on the value of these GET variables. Can anybody help pls!? I'm fairly handy with the old regexes so I can have a pop at using mod-rewrite if I have to but I'm not clear on the syntax for rewriting GET vars and I'd prefer to avoid the performance hit and use the cleaner Redirect directive. Is there a way? and if not can anyone clue me in as to the right mod-rewrite syntax pls?
Cheers,
Roger.
As the parameters in the URL query may have an arbitrary order, you need to use a either one RewriteCond directive for every parameter to check or for every possible permutiation.
Here’s an example with a RewriteCond directive for each parameter:
RewriteCond %{QUERY_STRING} ^([^&]&)*opendocument(&|$)
RewriteCond %{QUERY_STRING} ^([^&]&)*part=1(&|$)
RewriteRule ^bunch\.of/unneeded/crap$ /page.php/welcome? [L,R=301]
RewriteCond %{QUERY_STRING} ^([^&]&)*opendocument(&|$)
RewriteCond %{QUERY_STRING} ^([^&]&)*part=2(&|$)
RewriteRule ^bunch\.of/unneeded/crap$ /page.php/prices? [L,R=301]
But as you can see, this may get a mess.
So a better approach might be to use a RewriteMap. The easiest would be a plain text file with key and value pairs:
1 welcome
2 prices
To define your map, write the following directive in your server or virual host configuration (this directive is not allowed in per-directory context):
RewriteMap examplemap txt:/path/to/file/map.txt
Then you would just need one rule:
RewriteCond %{QUERY_STRING} ^([^&]&)*opendocument(&|$)
RewriteCond %{QUERY_STRING} ^([^&]&)*part=([0-9]+)(&|$)
RewriteRule ^bunch\.of/unneeded/crap$ /page.php/%{examplemap:%2}? [L,R=301]
RewriteCond %{QUERY_STRING} option=com_content&task=view&id=70&Itemid=82
RewriteRule ^index.php http://www.example.com/business/banks/? [R=301,L]
The ? will prevent the url the user is sent to from having the same query string as the origin page.
In summary, you could use RedirectMatch with a regex that will match the full URL, including query string. That will let you rearrange parts of the URL, but if you have to do conversions like "opendocument&part=1" to "welcome" (where the new URL is completely different from the original one), you might need a RewriteMap - or perhaps better, just send all URLs to page.php and parse the query string in PHP.
EDIT: If it's just a few URLs you want to redirect, you could probably write out individual rules like
RedirectPermanent http://www.example.com/bunch.of/unneeded/crap?opendocument&part=1 http://www.example.com/page.php/welcome
RedirectPermanent http://www.example.com/bunch.of/unneeded/crap?opendocument&part=2 http://www.example.com/page.php/prices

Resources