URL rewriting with ISAPI Rewrite - url-rewriting

I am trying to create a filter system for products and keep the URL's friendly, i am using a map file for the filter params and the following re-write code.
The url could contain, one param or 10 params and will be bulit like so
Start URL: www.domain.com/climbing-frames/
First Param: www.domain.com/climbing-frames_rockwall/
Second Param: www.domain.com/climbing frames_rockwall_rope-ladder/
And so on.....
The rewrite rule so far
RewriteMap features txt:features.txt
RewriteCond ${features:$1|NOT_FOUND} !NOT_FOUND
RewriteRule ^climbing-frames(?:_([^/]+))(?:_([^/]+))(?:_([^/]+))(?:_([^/]+))/ /get-features.cfm?(?1(param1=${features:$1|0}))(?2(,${features:$2|0}))(?3(,${features:$3|0}))(?4(,${features:$4|0}))
This works if 4 prams are entered but not if only two params are entered. This is driving me crazy!
Any clues would be greatly appreciated.
Jason

I think you're close - there might be a looping approach that would be better, but I do tend to go with the way you're going.
I see how you're doing the non-capturing underscore, then capturing the next characters. Instead of looking for not-slash, look for not-underscore. With the not-slash, it's going to grab the whole thing in the first group. That is, look for underscore-not-underscore.
Then (getting to the real fix), each section needs to be optional - the rule above is requiring the four sections. So add a ? to the end of each one, as:
RewriteRule ^climbing-frames(?:_([^_]+))(?:_([^_]+))?(?:_([^_]+))?(?:_([^_]+))?/
I left the first group required, since it practically should be there, and the RewriteCond is checking for it anyway.

Related

Is mod_rewrite rewrite rule match depending on position in substitution?

I try to echo current state of a URL being rewrited in .htaccess if query string contains DEBUG phrase:
RewriteCond %{QUERY_STRING} DEBUG
RewriteRule .+ echo.php?ip=%{REMOTE_ADDR}&url=$0&query=%{QUERY_STRING} [L]
and my echo.php script echoes expected URL.
But strangely when I change order of parameters in substitution to:
RewriteRule .+ echo.php?url=$0&ip=%{REMOTE_ADDR}&query=%{QUERY_STRING} [L]
echoed url is "echo.php" itself.
Is this expected behavior, and if so why?
When I test, I don't get the different behaviour you are stating. When I use the rule either way round, I get echo.php as the URL, when visiting example?DEBUG. And this is because rules in .htaccess will keep looping (because the whole directory processing starts again after the rewrite, including the rewrite rules) until the URL does not change. So since you are matching .+ you will always end up with echo.php unless some prior rule gets in the way and ends processing of that iteration before reaching your rule.
You can prove this to yourself by adding the [END] flag to the rule which stops any further mod_rewrite processing, and then you will get the behaviour you are expecting. The difference you are seeing must be due to your prior rules in some way.
As mentioned in the comments, a better way to debug mod_rewrite is to make use of the LogLevel rewrite:traceX option, with X being a number between 1 and 8. 3 is a good place to start, and increase from there if not enough info. There is a lot of info as you increase towards 8. You can only enable it in the main config. See the documentation. Make sure to switch it off again as all that logging affects performance. It does not interfere with any earlier LogLevel directives.

Mod rewrite with uppercase adds query string

I'm using mod Rewrite to rewrite part of the URL to a query parameter
URLs are of the form
http://www.my_site.com/ABC
where ABC is the bit to force into a query parameter to my index.php in a sub directory
My .htaccess has the following:
RewriteEngine on
RewriteRule ^/?([a-zA-Z0-9]+)/?$ directory/index.php?Site=$1 [L]
When I have a lowercase ABC e.g:
my_site.com/abc
the browser URL remains unchanged and the page works perfectly with abc being passed in the GET.
However, when ABC is UPPERCASE e.g:
my_site.com/ABC
the URL in the browser becomes:
my_site.com/ABC/?Site=ABC
It works OK and ABC is still in the GET parameter but it looks ugly!
Why does case affect this and can I make BOTH upper and lower case maintain the original URL?
Further note: I tried an example of a different server and it worked perfectly! Any ideas if there are server settings that could affect this?
Thanks for any assistance
I've solved it - as sidoh said something else is going on.
If there is a directory on my server which is the same name as the parameter the mod_rewrite adds the query to the URL.
e.g.
If I've got a directory ABC on the server then using my mod_rewrite with www.domain.com/ABC results in the browser URL www.domain.com/ABC/Site=ABC - if no directory ABC all is fine and the URL remains www.domain.com/ABC (which is what I want).
Since I'm on Linux ABC is different to abc - which explains the apparent case sensitive nature of the behaviour.
Thanks to all for their inputs.
Do you mean, the [NC] nocase flag? Which will make the rule be matched in a case-insensitive manner. Means, it will doesn't care whether letters appear as upper-case or lower-case.
RewriteRule ^([a-zA-Z0-9]+)/?$ /directory/index.php?Site=$1 [NC]
I think, you want to rewrite a URL such /bigSMALL into /directory/index.php?Site=BIGsmall? If am I right, then the problem is in the program and not in URL remapping. However, in MySQL database, when you're getting the value of a query string for querying a WHERE value, it is match in a case-insensitive. Take a look at the picture:
Are you developing a website? If ever, then what DBMS are you using? Maybe, MySQL?

How can I debug mod_rewrite rules?

This is a case of "ask a question and answer it myself", which I'm posting for the benefit of anyone who has the same problem.
I had some problems debugging a mod_rewrite ruleset in a .htaccess file on a shared server, where I couldn't even access the Apache error logs. I found a neat way to debug them, which is this:
Write a short script that simply prints out it's querystring variables. e.g. in PHP:
<?='<pre>',htmlentities(print_r($_GET,true)),'</pre>'?>
is all you need.
Let's say you name this script "show.php" and put it in /public_html. Then in your .htaccess file, identify the point in your ruleset that you think might be causing the problem, and insert this rule:
RewriteRule (.*) /show.php?url=$1 [END]
The effect is the same as inserting a PRINT statement in a regular program. It'll let you know that (a) You reached that point in the ruleset, and (b) what the current rewritten URL is.
It's not as flash as a real debugging tool, but it gets the job done.
If you're using Apache <2.3.9, you'll have to use [L] instead of [END]. In that case, something to look out for is that your ruleset should not attempt to rewrite "/show.php" to anything else. If that's a problem, you can fix it by adding this rule at the very top:
RewriteRule ^show.php$ - [L]
...Just remember to remove it when you're done debugging!
Other possibility:
use this online htaccess tester:
http://htaccess.madewithlove.be/
Very helpful insight. For years I've been trying to figure out how to debug mod_rewrite rules without needing to have root access and having to put the rules in httpd.conf. This does it!
You have one minor mistake in your PHP:
<?='<pre>',htmlentities(print_r($_GET),true),'</pre>'?>
In this code, print_r() outputs everything in $_GET to stdout and then returns the value true, which htmlentities() picks up as its first argument. htmlentities() also receives the literal true as its second argument, which is an optional argument that tells htmlentities() whether or not to mess with single- and/or double-quotes.
I think what you intended was:
<?='<pre>',htmlentities(print_r($_GET, true)),'</pre>'?>
This tells print_r() to format everything in $_GET. Passing true as the second argument to print_r() tells it not to output the result to stdout, but instead to put the result in a string and return that string as print_r()'s return value. htmlentities() then receives that string as its one input parameter, and does appropriate substitutions to force the browser to display the string as is rather than allowing the browser to interpret the string. E.G. -
<i>text</i>
would get translated to:
<i>text</i>
which will cause the browser to display:
<i>text</i>
instead of displaying the word "text" in italics:
text

Creating a simple rule to rewrite a friendly URL to the physical URL

I cannot wrap my head around URL rewriting. What I want to do seems very simple but I am having problems getting the results I want.
I would like allow users to type www.mysite.com/search/real with an optional / at the end. This would take them to www.mysite.com/content/search_real_property.asp
That's it. Here is the rule I have right now. The problem with this is it will keep stacking.
RewriteRule ^(search) content/search_real_property.asp
So this would work /search/real but so would search/real/search/real/search/real/
and others.
Assuming there are no other issues, you've turned the rewrite engine on (RewriteEngine On) and that you're either adding the rewrite in httpd-vhosts.conf or an .htaccess file in the root of the web tree (so that any path issues are resolved)... then the issue is merely one of Regular Expression pattern matching. Though I'm a bit perplexed by ASP running on what appears to be an Apache server (assuming this IS mod rewrite we're talking about).
So, all you really want is to terminate the match - something like:
RewriteEngine On
RewriteRule ^search/real/?$ /content/search_real_property.asp
That will fix it to /search/real (with or without a trailing slash, the ? means match the preceding character 0 or 1 times) to /content/search_real_property.asp. As the $ sign denotes the line terminator (EOL effectively) there must be nothing after "real" (except perhaps that 1 forward slash).
For greater flexibility you might want to look at what you can actually do with regular expressions, for instance...
RewriteEngine On
RewriteRule ^search/([^/]*)/?$ /content/search_real_property.asp?query=$1
Which would allow you to take any string and pass it in the address bar as a variable called query (Request.QueryString('query') IIRC).
Try: http://www.regular-expressions.info/ for more info.

url-rewriting and rss feed (feedburner) issue

I am using below rule to read the URL like
URL:
http://www.example.com/blog/sampe-post-title/10004/
RULE:
RewriteRule (.*)/(.*)/([0-9]+)/$ $1/details.asp?mod_id=$3 [NS,I]
Everything was fine untill I discovered that links coming via feedburner are not working anymore. Because feedburner adds some extra parameter to URL for stats/tracking etc.
For example www.example.com/blog/sampe-post-title/10004/?utm_source=feedburner&utm_medium=email&utm_campaign=Feed:+somesite+(my+feed)
My rewrite URL doesn't recognizes the above URL anymore. Any idea how to deal with it?
Try adding a rule for the feedburner URLs:
RewriteRule (.*)/(.*)/([0-9]+)/\?(.*)$ $1/details.asp?mod_id=$3&$4 [NS,I]
I added an extra RegEx group at the end to capture everything after the question mark and place it after mod_id. You could probably combine this with your other URL if you only wanted to have one rule for some reason, but you might as well just have two.
Try the QSA flag to get the original requested URL query automatically appended to the new one.
I managed to figure out the answer on my own: just replace the ending $ with .* That's it!
Here is the modified rule:
RewriteRule (.*)/(.*)/([0-9]+)/.* $1/details.asp?mod_id=$3 [NS,I]

Resources