Mod_rewrite help - mod-rewrite

I'm trying to remove query strings from my calendar, but my mod_rewrite is not appending the query string.
The website is http://cacrochester.com/Calendar
and if you click the link to go to a different month, the query string is usually http://cacrochester.com/Calendar?currentmonth=2010-11
With my rule below, it just doesn't append the query string so when you click the next month link, it just stays on the month October. What's wrong with my rule?
Here is my rule
RewriteCond %{QUERY_STRING} !^$
RewriteRule ^.*$ http://cacrochester.com/Calendar? [NC,R=301,L]
EDIT:
What i want is to take a url like http://cacrochester.com/Calendar?currentmonth=2010-11 and turn it into something like http://cacrochester.com/Calendar/2010-11

You probably need your app to output relative urls like "/Calendar/2010-11". That's a simple code change.
Then in Apache you'd want to rewrite those urls, using:
RewriteRule ^/Calendar/([0-9]+-[0-9]{2})$ /Calendar.php?currentmonth=$1 [NC,QSA,L]
(You don't want a RewriteCond for this rule.)
Forcing a redirect with R=301 will only expose the internal url scheme. I don't think that's what you want.

To maintain query strings when rewriting, use the QSA (query string append) flag.
[NC,R=301,QSA,L]

Related

Rewriting an URL to become a query string

I'm trying to rewrite URLs such as
/product/16/var1/value1/var2/value2...
to this
index.php?page=product&id=16&var1=value1&var2=value2...
In other words, I would like to have a "main parameter" translated to an id (and I can do this), but I would also like to have, from that point on, couples of "directories" translated recursively to key-value pairs.
Is this possible with Apache mod_rewrite?
In the absence of the [L] flag, any mod_rewrite rule will apply repeatedly to any URI which corresponds to the rule's rewrite conditions and pattern.
Knowing this, we can build a mod_rewrite rule which looks for any URIs with query strings beginning in a certain way and then repeatedly harvests the folder-names of that URI (two at a time) to build the rest of the query string.
See example below:
In the root folder of
http://example.com/
save an .htaccess file with the following mod_rewrite directives:
RewriteEngine On
RewriteRule ^(product)/([0-9]{2})/(.*) http://%{HTTP_HOST}/$3/index.php?page=$1&id=$2
RewriteCond %{QUERY_STRING} ^(page=product&id=[0-9]{2}.*)
RewriteRule ^([^/]+)/([^/]+)/(.*/)?index.php$ http://%{HTTP_HOST}/$3index.php?%1&$1=$2
Using the above:
http://example.com/product/16/var1/value1/var2/value2/
becomes
http://example.com/index.php?page=product&id=16&var1=value1&var2=value2
and
http://example.com/product/16/var1/value1/var2/value2/var3/value3/var4/value4/
becomes
http://example.com/index.php?page=product&id=16&var1=value1&var2=value2&var3=value3&var4=value4

Mod Rewrite + QSA : Same querystring param in rewrite target and in querystring - Force use of target possible?

We have the following rewrite rule:
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?rewrite=$1 [L,QSA]
We were wondering if there was a way to have the ?rewrite=$1 take precedence over one that is passed via the query string in the request uri?
Because as it stands now, due to the QSA flag (which we do need btw) if the following url is hit:
http://www.domain.com/this_rewrite_will_match_the_above_rule?rewrite=some_value
The value of $_GET['rewrite'] in PHP will be some_value, and not this_rewrite_will_match_the_above rule.
Before we go in and start modifying the rewrites and adding a RewriteCond to match the query string, etc etc... We were hoping there was a flag to set so that the target url (index.php?rewrite=$1 in this case) took precedence over the passed query string values.
Hope this makes sense.
Thanks.
Slightly hackish
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%{QUERY_STRING}&rewrite=$1 [L]
This works because, in php, the second rewrite=... overwrite the first.
I have searched for some mechanics to override single querystring parameters in an Apache rewrite multiple times and quite intensely, but it looks like there is no option to do that, even with the latest Apache version (2.4.3 at the time of this writing).
But there is an alternative that makes use of the fact that the PHP querystring parser only returns the last of multiple idententical querystring parameters.
Example:
http://www.domain.com/index.php?id=123&id=456
This will return the following single (!) entry in $_GET:
array(1) {
["id"]=>
string(3) "456"
}
So you can solve your problem by simply appending any override parameters to the end of your existing querystring (without removing them within the querystring). The last occurrence of a repeated parameter is the one that makes it into the $_GET array.
Unfortunately the QSA switch is not suitable for this technique, as it always appends the original parameters to the end of the new querystring. There is no switch that would preprend the old parameters. So you have to take a little detour with a RewriteCond to catch and prepend the original querystring yourself instead of using QSA:
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%1&rewrite=$1 [L]
The only function of the RewriteCond is to capture the querystring in %1. The regexp (.*) of the condition is always matched, so the following RewriteRule is always executed.
With this technique your above testcase will rewrite to...
http://www.domain.com/index.php?rewrite=some_value&rewrite=this_rewrite_will_match_the_above_rule
...which will be interpreted by the PHP querystring parser to
$_GET["id"] => "this_rewrite_will_match_the_above_rule"
...which is what you want.
Please be aware that this will work only if you take your querystring values from PHP's $_GET array. It will not necessarily work if you parse the content of $_SERVER["QUERY_STRING"] yourself or if you use any other programming language.
I have opted to create an answer of my own, because its slightly cleaner then the examples provided by Jpsy and Gerben.
Credit where credit is due, their suggestions are what got me here, I only expanded on them:
So, our final solution includes 2 rules.
# check if querystring is not empty (this is the addition vs other answers)
RewriteCond %{QUERY_STRING} !^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%{QUERY_STRING}&rewrite=$1 [L]
if the above query string fails (mainly, the querystring is empty) this rule will apply.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?rewrite=$1 [L]
The reason I opted to go for this dual rule setup is to avoid having the php server variables polluted with "?&rewrite=...." if the query string is empty.
Thanks to jpsy and gerben for the help.
I used the following instructions:
RewriteRule ([^\?]*)\?(.*) $1?$2 [N] (1)
RewriteCond %{QUERY_STRING} (.*?)&?(rewrite=[^&]+)&?(.*)
RewriteRule ^(.*)$ $1?%1&%3 [N] (2)
RewriteRule ^(.*)$ $1?domain=newValue [L,QSA] (3)
The trick is done by the [N] flag in the first two rules, which causes to rewrite engine to re-process the output.
Rule (1) simple rewrites the url as it is. I needed it because I'm using mod_rewrite togheter with mod_proxy_ajp and in the first iteration the query string is not splitted from the url. After the execution of the first line, the url is unchanged but the engine will split the path from the query string.
Rule (2) iterates and removes all occurrences of the parameter "rewrite" from the query string.
Rule (3) sets the new value for the parameter and appends whichever query string survives from the replacement done by rule (2).

mod_rewrite, change one URL with query to a completely different URL

I am migrating data from one content management system to another. There is no relationship between old URLs and new URLs, although both contain query strings. I am trying to set up a set a rewrites that will redirect broad category lists of data from one to the other.
Here's a sample:
OLD
rss.php?categoryID=53
NEW
index.php?module=news&type=user&func=list&tid=1&filter=blogtopic:eq:19
I tried
RewriteRule ^rss.php\?categoryID=53 index.php?module=news&type=user&func=list&tid=1&filter=blogtopic:eq:19 [L]
but it doesn't match. If I follow that one with
RewriteRule ^rss.php index.php?module=news&type=user&func=list&tid=1 [L]
if DOES match, so I conclude that the question mark in the old URL is causing the problem. I am already escaping the question mark. What do I do?
I will probably end up with about 50 of these in my .htaccess file.
You can't match against the query string (all that stuff after the ?) in a RewriteRule, you need to use a RewriteCond and match against the `%{QUERY_STRING} var:
RewriteCond %{QUERY_STRING} ^categoryID=53$
RewriteRule ^rss\.php$ /index.php?module=news&type=user&func=list&tid=1&filter=blogtopic:eq:19 [L]
Or change the brackets to [R=301,L] if you want to redirect the browser.

Remove All Query Strings from URL

I would like to rewrite my url's, so that whenever there's a ?, it and everything after is removed.
I have various strings, such as:
....html?frame=...
....html?sport=...
....html?type=...
So to make it easy, if there's a ? anywhere in the url, it should be truncated.
(By the way, I am already rewriting .php as .html)
Thanks a lot.
As pointed out in the comments:
RewriteCond %{QUERY_STRING} !=""
RewriteRule ^(.*)$ /$1?
Works, but OP says it reverts the php -> html extension conversion back.
Try it adding the php/html rewrite before:
RewriteRule ^(.*)\.php$ /$1.html
RewriteCond %{QUERY_STRING} !=""
RewriteRule ^(.*)$ /$1? [L,R=302]
I just tried it, and I'm having some issues with RewriteBase, which you might need to setup for this to work. Otherwise, looks fine.
From mod_rewrite documentation (emphasis mine):
Modifying the Query String
By default, the query string is passed through unchanged. You can, however, create URLs in the substitution string containing a query string part. Simply use a question mark inside the substitution string to indicate that the following text should be re-injected into the query string. When you want to erase an existing query string, end the substitution string with just a question mark. To combine new and old query strings, use the [QSA] flag.

mod_rewrite is being ignored

I'm trying to transform "domain.com/index.php?site=food&category=beef" into "domain.com/food/beef" but it does not work, no matter what I try. It always leaves the original domain and I get no errors.
I think it's my fault, I tried this for 3 different URLs on 3 different servers (and 3 different projects)... it just seems like I don't get how mod_rewrite really works, though I read every documentation on this topic I found. I even spent days here on SO without finding any solution.
Mod_rewrite is enabled on the server:
RewriteEngine On
RewriteRule ^ http://www.google.com [R,L]
gives me "http://www.google.com/?site=food&category=beef". It looks like mod_rewrite does not recognise the query string... So I tried several solutions with RewriteCond %{QUERY_STRING}... but nothing works :/
Hopefully you guys can help me! I'm going insane on this!
Thanks in advance!
Try:
RewriteEngine on
RewriteRule ^food/beef$ index.php?site=food&category=beef [L]
Or more generally:
RewriteEngine on
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)$ index.php?site=$1&category=$2 [L]
Are you trying to do something like this?
RewriteRule ^([^/]+)/([^/]+)/? /index.php?site=$1&category=$2 [L]
This will make it so when you go to http://domain.com/food/beef the request gets rewritten to "/index.php?site=food&category=beef" internally and index.php is used to serve the original request. The browser's location bar will still say "http://domain.com/food/beef".
If you want the location bar to say http://domain.com/index.php?site=food&category=beef then add an "R," to the "[L]". If this is backwards and you want it so when someone enters http://domain.com/index.php?site=food&category=beef in the location bar, and the request gets rewritten to "/food/beef" internally on the server, then you need to parse out the query string using RewriteCond:
RewriteCond %{QUERY_STRING} ^site=([^&]+)&category=([^&]+)
RewriteRule ^index.php /%1/%2? [L]
The same thing applies with the "R" causing a browser redirect like the first example. If you want the location bar to change to http://domain.com/food/beef then the brackets should look like: [L,R]. Note that you need a ? at the end of the target in the rule, so that query strings don't get thrown in. That is why in your google example, the query string is being appended.
EDIT:
Seeing as you just wanted to change what's in the browser's location bar and not where the content is:
You need to re-rewrite what the 2nd rule above has rewritten BACK to index.php, but without a redirect. In order to keep the 2 rules from looping indefinitely because one rule rewrites to the other rule and vice versa, you need to add a flag somewhere to keep the 2nd rule above from redirecting you over and over again.
So combining the two, you'll have this:
RewriteRule ^([^/]+)/([^/]+)/? /index.php?site=$1&category=$2&redirected [L]
RewriteCond %{QUERY_STRING} !redirected
RewriteCond %{QUERY_STRING} ^site=([^&]+)&category=([^&]+)
RewriteRule ^index.php /%1/%2? [L,R=301]
Note the redirected parameter in the query string. This gets inserted when someone tries to access the clean version of the url, e.g. "/food/beef". internally, it gets rerouted to index.php but since the rule doesn't have a "R", the browser's location bar doesn't change.
The second rule now checks if the request contains the redirected param in the query string. If it doesn't, that means someone entered in their browser's location bar the index.php url, so redirect the browser to the clean version.

Resources