How to make Isapi Rewrite rules case-sensitive? - mod-rewrite

I want to direct my users based on a case-sensitive url:
www.mysite.com/a ==> page 1
www.mysite.com/A ==> page 2
I'm using the ISAPI rewrite with the following rule:
RewriteRule ^([0-9a-zA-Z] {1,7}) $/redirect/?K=$1 [L]
Apparently this rule is not case-sensitive, since it redirects to the same page. What's is wrong?
=====UPDATE=====
I solved in part this problem by adding a binary query (case-sensitive) in my MySql statement. But in chrome this problem still occurs.

I see 2 problems:
1) space between [] and {}
2) your regular expression is non-case sensitive
for lowercase expression you need RewriteRule ^([0-9a-z]{1,7}) $/redirect/?K=$1 [L]
and for upper-case RewriteRule ^([0-9A-Z]{1,7}) $/redirect/?K=$1 [L]

Related

Apache2 rewrite returns filename extension

I really don't understand where I'm doing wrong. I'm trying to apply a rule to
http://localhost/prezzo/account/1
so that it is rewritten as
http://localhost/prezzo/account/test.php?user=1
I'm using UniformServer as WAMP. I placed the .htaccess file in the subfolder I'm working on (prezzo/account/) with the following rule:
RewriteEngine On
RewriteRule (\w+)/?$ test.php?user=$1 [L]
htaccess tester reports that the rule is applied correclty.
But when I go to the URL http://localhost/prezzo/account/1 and test.php is loaded - which contains simply
<?php
echo $_GET['user'];
?>
it returns the string "php" instead of "1".
If I try with
RewriteRule ^prezzo/account/(\w+)/?$ prezzo/account/test.php?user=$1 [L]
I get 404 not found although htaccess tester reports that the rule is applied correctly and the URL is rewritten as
http://localhost/prezzo/account/test.php?user=1
that if I copy/paste in the address bar it works.
But when I go to the URL http://localhost/prezzo/account/1 and test.php is loaded [...] it returns the string "php" instead of "1".
Yes, this is expected with the rule as posted.
This appears to work in the "htaccess tester" because that tool only makes a single pass through the file, which is not how a real server works.
RewriteRule (\w+)/?$ test.php?user=$1 [L]
When you request /prezzo/account/1 then...
The request is rewritten to test.php?user=1
The L flag causes the rewrite engine to start over using the rewritten URL (test.php?user=1) as input to the next round of processing.
The request is rewritten to test.php?user=php since the regex (\w+)/?$ captures the php part of test.php. (The \w shorthand character class excludes dots and the regex is not anchored.)
The L flag causes the rewrite engine to start over using the rewritten URL (test.php?user=php) as input to the next round of processing.
The request is rewritten to test.php?user=php (again).
Since the URL has passed through unchanged the rewriting process stops and the request is finally rewritten to /test.php?user=php.
Solution A - Use the END flag
One solution is to simply use the END flag (Apache 2.4) instead of L to prevent the rewriting engine from "looping". It will stop as soon as the directive is processed. For example:
RewriteRule (\w+)/?$ test.php?user=$1 [END]
Solution B - Make regex more specific
The other solution (or as well as) is to make the regex more specific, so that it doesn't match test.php. ie. Only match the URL format you are expecting.
The regex (\w+)/?$ would seem to be too generic, as it is basically just matching the last group of letters/numbers on the URL-path. If you only want to match digits (a "user-id") then you could make the regex more restrictive and match only digits instead.
You should also anchor the regex at the start, so that it matches a whole path segment, rather than just capturing the last part that matches. In fact, simply anchoring the above regex would have also resolved this, since test.php would have failed to match because \w does not match dots.
For example:
RewriteRule ^(\d+)/?$ test.php?user=$1 [L]
This will match digits only in the last path segment.
If I try with
RewriteRule ^prezzo/account/(\w+)/?$ prezzo/account/test.php?user=$1 [L]
I get 404 not found although htaccess tester reports that the rule is
applied correctly and the URL is rewritten
If the .htaccess file is located in the /prezzo/account subdirectory (as you stated) then the above will never match and the directive does nothing.
That testing tool assumes the .htaccess file is located in the document root only. If your .htaccess was located in the document root and not the subdirectory, then that directive would indeed be OK.
In a directory context (eg. .htaccess) the RewriteRule pattern matches against the URL-path relative to the directory that contains the .htaccess file.
Aside:
In your link, the entire file would seem to be:
RewriteEngine On
#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteCond %{REQUEST_FILENAME} !-l
#RewriteRule . index.php [L]
RewriteRule (\w+)/?$ test.php?user=$1 [L]
The first rule is commented out so does not apply here. However, if you uncomment that first rule then the rules are in the wrong order. Since a request for /prezzo/account/1 would first be rewritten to index.php and you'd have the same problem as before.
The order of rules is important.

replace character in rewrite rule

Here are my current rules:
RewriteCond %{QUERY_STRING} ^to=(one|seventeen|thirty\+four)
RewriteRule ^/folder/page.php$ http://www.site.com/folder/category/%1? [L]
RewriteRule ^folder/category/(.+)\+(.+)$ http://www.site.com/folder/category/$1-$2 [L]
The first rule works fine, it redirects perfectly if the word is in the query string, but I can't get thirty+four to become thirty-four when redirected.
Any help would be greatly appreciated.
For starters, RewriteRule ^/folder/page.php$ will never match anything. The URI's get the prefix (the leading slash) removed if the rules are in an .htaccess file instead of server config.
Secondly, since you've included http://www.site.com/ in your targets, that means the browser will get redirected instead of internally rewritten. You need to remove http://www.site.com/ from your first rule so that the second one can be applied.
Here's what should work:
RewriteCond %{QUERY_STRING} ^to=(one|seventeen|thirty\+four)
RewriteRule ^folder/page.php$ folder/category/%1 [NC,QSA,L]
RewriteRule ^folder/category/(.+)\+(.+)$ folder/category/$1-$2 [NC,QSA,L]
And now three hints:
1)
Please make sure you've read everything here before asking:
Here's the wiki of serverfault.com
The howto's htaccess official guide
The official mod_rewrite guide
2)
Please try to use the RewriteLog directive: it helps you to track down problems:
# Trace:
# (!) file gets big quickly, remove in prod environments:
RewriteLog "/web/logs/mywebsite.rewrite.log"
RewriteLogLevel 9
RewriteEngine On
3)
My favorite tool to check for regexp:
http://www.quanetic.com/Regex (don't forget to choose ereg(POSIX) instead of preg(PCRE)!)
You use this tool when you want to check the URL and see if they're valid or not.

Problem redirect CodeIgniter URLs to WWW

I have a CI application that uses .htaccess for URL routing. My basic setup is as follow:
RewriteRule ^$ /var/www/html/ferdy/jungledragon/index.php [L]
RewriteCond $1 !^(index\.php|images|img|css|js|swf|type|themes|robots\.txt|favicon\.ico|sitemap\.xml)
RewriteRule ^(.*)$ /var/www/html/ferdy/jungledragon/index.php/$1 [L]
These rules are pretty standard for CI apps. They rewrite all URLs (except for those in the exception list) to the index.php front controller. The lines above also hide index.php, as it would normally appear as part of every URL.
So far, so good. Everything works just fine. Now, for the sake of SEO I would like to force all traffic to www. So I extended the rules as follow:
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^$ /var/www/html/ferdy/jungledragon/index.php [L]
RewriteCond $1 !^(index\.php|images|img|css|js|swf|type|themes|robots\.txt|favicon\.ico|sitemap\.xml)
RewriteRule ^(.*)$ /var/www/html/ferdy/jungledragon/index.php/$1 [L]
rewritecond %{http_host} ^jungledragon.com [nc]
rewriterule ^(.*)$ http://www.jungledragon.com/$1 [r=301,nc]
These last two lines rewrite http://jungledragon.com/anything URLs to http://www.jungledragon.com/anything URLs. This kind of works, but it brings back the index.php part back: http://jungledragon.com/anything becomes http://www.jungledragon.com/index.php/anything.
How exactly do I combine these rules so that they do not interfere with each other? I tried doing the WWW rewrite before the CI rules. That shows an Apache 301 page with an error, rather than doing the actual redirect.
Additionally, I would like to also include rules to get rid of trailing slashes, but for now let's keep the question simple. Note that I did find useful post here and elsewhere yet for some reason I still can't find the correct exact syntax for my situation.
Edit: Thanks for the help. This works:
Options +FollowSymlinks
RewriteEngine on
rewritecond %{http_host} ^jungledragon.com [nc]
rewriterule ^(.*)$ http://www.jungledragon.com/$1 [r=301,nc,L]
RewriteRule ^$ /var/www/html/ferdy/jungledragon/index.php [L]
RewriteCond $1 !^(index\.php|images|img|css|js|swf|type|themes|robots\.txt|favicon\.ico|sitemap\.xml)
RewriteRule ^(.*)$ /var/www/html/ferdy/jungledragon/index.php/$1 [L]
mod_rewrite processes rules in a linear fashion. Rules at the top of the file are processed first.
The [nc] and [L] at the end of the rules are the options for how to process rules.
nc - nocase: case insensative
L - last: last rule in the execution (if you hit this, stop processing)
You need to put your www redirect rules above your CI rules so it will first add the www, THEN apply the CI rules to the newly re-written url. **And also use either the C or N flag with your www redirect rule so it will parse the next rule.
http://mysite.com/blah ==becomes==> http://www.mysite.com/blah ==becomes==> http://www.mysite.com/index.php/blah (Executed, not redirected)
What's happening currently is:
http://mysite.com/blah ==becomes==> http://mysite.com/index.php/blah (STOP)
Browser goes to http://mysite.com/index.php/blah and a second re-write pass is done since your exceptions stop /index.php urls from being processed
http://mysite.com/index.php/blah ==becomes==> http://www.mysite.com/index.php/blah (Redirected)
As Suggested, here is a link to mod_rewrite's documentation if you want to look further.
#LazyOne: Brainfart, sorry.
Here's an excerpt from the docs outlining the flags you'll probably need:
'chain|C' (chained with next rule)
This flag chains the current rule with the next rule (which itself can be chained with the following rule, and so on). This has the following effect: if a rule matches, then processing continues as usual - the flag has no effect. If the rule does not match, then all following chained rules are skipped. For instance, it can be used to remove the .www'' part, inside a per-directory rule set, when you let an external redirect happen (where the.www'' part should not occur!).
'next|N' (next round)
Re-run the rewriting process (starting again with the first rewriting rule). This time, the URL to match is no longer the original URL, but rather the URL returned by the last rewriting rule. This corresponds to the Perl next command or the continue command in C. Use this flag to restart the rewriting process - to immediately go to the top of the loop.
Be careful not to create an infinite loop!
'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.
'noescape|NE' (no URI escaping of output)
This flag prevents mod_rewrite from applying the usual URI escaping rules to the result of a rewrite. Ordinarily, special characters (such as '%', '$', ';', and so on) will be escaped into their hexcode equivalents ('%25', '%24', and '%3B', respectively); this flag prevents this from happening. This allows percent symbols to appear in the output, as in

mod_rewrite issues

I have used the mod_rewrite module but was not able to redirect to the target page - I am getting an error:
The requested URL /old.html was not found on this server.
Rewrite rules as follows:
RewriteEngine On
RewriteRule ^/IN/index.html$ /IN/index.iface [L]
You need to request a URL with a path that’s matched by the pattern of your RewriteRule directive. So in your case obviously /IN/index.html (where the . can actually be any character, as it’s not escaped).

What's wrong with my RewriteRule?

My .htaccess file currently looks like this
AddType x-mapp-php5 .php
Options +FollowSymLinks
Options +Indexes
RewriteEngine On
RewriteBase /
RewriteRule ^account$ /account/orders.php [L]
When I go to http://mywebsite.com/account it properly shows the page at http://mywebsite.com/account/orders.php. But when I change the RewriteRule to
RewriteRule ^account/orders$ /account/orders.php [L]
and then I go to http://mywebsite.com/account/orders, I get Error 404 Page Not Found. What did I do wrong?
******Additional Details**
I finally diagnosed the problem. But I don't understand why my solution works. Consider the scenario where account/orders.php exists.
The following rule will not work
RewriteRule ^account/orders$ account/orders.php [L]
The following rule will work
RewriteRule ^account/order$ account/orders.php [L]
Ie., the rewrite rule will fail if the Pattern evaluates to an existing file. So when the pattern is the same as the substitution, but minus the extension, the rewrite rule will fail. If I add a file called account/order.php, then both rules will fail.
Why does this happen?
I don't see how your first example would work, because I believe that intial slashes are also passed on.
RewriteRule ^/account/orders$ /account/orders.php [L]
Have you tried a relative path?
RewriteRule ^account/orders$ account/orders.php [L]
Edit   You should also make sure to have MultiViews disabled. This causes that Apache does some additional vague file matching to find similar named files and thus /account/orders would be mapped to /account/orders.php before it’s passed to mod_rewrite.
Strange, it seems ok to me...
If you have access to Apache Configuration try to enable RewriteLog and RewriteLogLevel for some debug...
Also take a look in the site's log files (always if you have access)
I would at first try to add a redirect to my rules, so I can see in the browser what is happening on the server.
RewriteRule ^account$ /account/orders.php [L,R]
Also make sure that there are no other rules (previous ones) interfering, just in case you are not showing all of your .htaccess file here.
I'm answering my own question because I finally diagnosed the problem. But I don't understand why my solution works. Consider the scenario where account/orders.php exists.
The following rule will not work
RewriteRule ^account/orders$ account/orders.php [L]
The following rule will work
RewriteRule ^account/order$ account/orders.php [L]
Ie., the rewrite rule will fail if the Pattern evaluates to an existing file. So when the pattern is the same as the substitution, but minus the extension, the rewrite rule will fail. If I add a file called account/order.php, then both rules will fail.
Why does this happen?

Resources