apache mod_rewrite and number of query parameter - apache

Here I have an original url:
/index.php?controller=controller_name&action=action_name&param1=val1&param2=val2
I need a rule that will transform it to:
/controller_name/action_name/param1/val1/param2/val2/
The issue is I don't know how many param out there, param may have any name, for example a real case:
/member/filter/location/us/gender/male/age/20
Thanks for your help!

RewriteEngine On
# match query string in the form
# controller=controller_name&action=action_name&param1=val1&param2=val2
# and rewrite it to /controller_name/action_name/?param1=val1&param2=val2
RewriteCond %{QUERY_STRING} ^controller=([^&]+)&action=([^&]+)&?(.*)$
RewriteRule .* /%1/%2?%3
# parse the query string from result of rules above
# and create "directories" from key, value pairs
RewriteCond %{QUERY_STRING} !=""
RewriteCond %{QUERY_STRING} ^&?([^=]+)=([^&]+)&?(.*)$
RewriteRule ^(.*)$ $1/%1/%2?%3

Related

Rewrite Apache Query_String

I have a query string URL: http://localhost/cgi-bin/qgis_mapserv.fcgi?map=/home/qgis/project/map.qgs. I want to hind the map.qgs path in the variable MAP. Besides the map variable, there are some variables (version, request, service, etc).
Here is what I need:
RewriteRule:
Pattern: ^cgi-bin/qgis_mapserv.fcgi?map=map.qgs&(.)$
Substitution: ^cgi-bin/qgis_mapserv.fcgi?map=/home/qgis/project/map.qgs&(.)$
Find bellow my unsuccessful attempt:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/cgi-bin/qgis_mapserv.fcgi$
RewriteCond %{QUERY_STRING} ^map=([A-Za-z0-9.-_]+)$
RewriteRule ^cgi-bin/qgis_mapserv.fcgi?(.*)$ cgi-bin/qgis_mapserv.fcgi?$1
Note: The map variable can show up in the pattern uRL anywhere among the other variables.
I wonder what I am missing on the code above
You are almost there.
The reason why your rule isn't working is because you can't test queryString in pattern of a RewriteRule.
You need to change your rule's pattern to
RewriteRule ^cgi-bin/qgis_mapserv.fcgi$
With this change your htaccess rules will look like :
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/cgi-bin/qgis_mapserv.fcgi$
RewriteCond %{QUERY_STRING} ^map=([A-Za-z0-9./-_]+)/map.qgs$
RewriteRule ^/?cgi-bin/qgis_mapserv.fcgi$ /cgi-bin/qgis_mapserv.fcgi?%1 [R,L]

Apache .htaccess rewrite parameter to directory

I've got an application that has been migrated to a newer platform. The tasks are similar and I'd like to redirect a GET parameter to a directory. For example
http://gallery/index.php?gal=ABC => http://photos/gal/ABC
and
http://gallery/?gal=DEF => http://photos/gal/DEF
and the anything that doesn't get caught redirect it to http://photos
I've tried
RewriteEngine on
RewriteCond %{QUERY_STRING} ^(\w+)=(\w+)$
RewriteRule ^(/index.php)$ /%1/%2?
However all I get is a 404 and no redirection. Similarly, I've tried
RedirectMatch ^/index\.php\?=gal(.*) http://photos/gal/$1
but I'm having trouble escaping the ? in the original URL.
What would be the proper way of going about this?
Create a .htaccess file and insert the following code:
RewriteCond %{QUERY_STRING} ^(.+)=(.+)$
RewriteRule ^index.php$ http://photos %1/%2? [L,NC,R=301]
Your order is reversed. Rewrite it in front of you
RewriteRule /(.+)\/(.+) index.php?$1=$2
The question is old but might be still relevant for others, so I suggest a slightly different general approach:
RewriteEngine On
RewriteCond %{QUERY_STRING} key=([0-9a-zA-Z]+) [NC]
RewriteRule (.*) /%1? [R=302,L]
Notes:
QUERY_STRING in the condition checks for a param name "key" and catches it's value
The rewrite rule adds the param value as directory using %1. Note the ? removes the original query part from end result

Apache rewrite rule query string

I am trying to write a Rewriterule which takes a domain from a URL of the format
https://www.example.com/sample?TARGET=https%3A%2F%2Fwww.example.com%2Fexample%2Fhelp%3Fparam%3D1.
If the TARGET parameter is present I need to redirect the user to the value inside the TARGET query parameter. My rewrite rule is below:
RewriteCond %{QUERY_STRING} TARGET=([-a-zA-Z0-9_+]+)
RewriteRule ^(.*)$ %1? [R=302,L]
This does not work because of two problems:
%1? in the rewrite rule causes the rewrite to append the value of the TARGET query string to the existing domain.
The value of %1 only contains https rather than https%3A%2F%2Fwww.example.com%2Fexample%2Fhelp%3Fparam%3D1.
I understand that this might not be the best way to go ahead with this, and I am open to suggestions.
You can use this rule instead:
RewriteEngine On
RewriteCond %{QUERY_STRING} ^TARGET=(.+)$ [NC]
RewriteRule ^ %1? [NE,R=302,L]
Important to use .+ in regex to be able to capture all characters of the URL specified in TARGET parameter.
This will redirect:
http://yourdomain.com/?TARGET=https://www.example.com/example/help?param=1 to
https://www.example.com/example/help?param=1

How do I remove parts of a query string with RewriteCond and RewriteRule?

Background
I want to replace several (3) query string parameters in urls. We're moving to a new search engine and there are tons of links that we would like to still work. Examples:
http://example.com/search?q=s&restrictBy[foo]=fltr1&restrictBy[baz]=fltr2 ->
http://example.com/search?q=s&newfoo=fltr1&bazinga=fltr2
http://example.com/search?q=s&restrictBy[bar]=fltr3 ->
http://example.com/search?q=s&barista=fltr3
http://example.com/search?q=s&restrictBy[bar]=fltr1&restrictBy[baz]=fltr2&restrictBy[foo]=fltr3 ->
http://example.com/search?q=s&barista=fltr1&bazinga=fltr2&newfoo=fltr3
Problem
The first parameter to RewriteRule does not look at the query string, so I cannot replace a single parameter while keeping the rest of the url intact. Additionally, the fact that NONE, SOME, or ALL of the parameters may exist, and IN ANY ORDER is throwing me for a loop.
# Does not work :/
RewriteRule (.*)restrictBy\[foo\]=(.*) $1newfoo=$2
# Kinda works, but loses rest of params
RewriteCond %{QUERY_STRING} restrictBy\[foo\]=([^&]*)
RewriteRule (.*) $1?newfoo=%1 [L]
# Kinda works, but doesn't remove old params
RewriteCond %{QUERY_STRING} restrictBy\[foo\]=([^&]*)
RewriteRule (.*) $1?newfoo=%1 [QSA,L]
Question
How can I replace ANY OR ALL 3 params without losing data and without additional data?
Remove QSA from rule to overwrite existing query string:
RewriteCond ::%{QUERY_STRING} ::(?:|.*&)restrictBy\[foo\]=([^&]*)
RewriteCond %1::%{QUERY_STRING} (.*?)::(?:|.*&)restrictBy\[baz\]=([^&]*)
RewriteCond %1&%2::%{QUERY_STRING} ([^&]*)&(.*?)::(?:|.*&)q=([^&]*)
RewriteRule ^(.*)$ $1?q=%3&newfoo=%1&bazinga=%2 [L,R]

RewriteCond to match query string parameters in any order

I have a URL which may contain three parameters:
?category=computers
&subcategory=laptops
&product=dell-inspiron-15
I need 301 redirect this URL to its friendly version:
http://store.example.com/computers/laptops/dell-inspiron-15/
I have this but cannot make it to work if the query string parameters are in any other order:
RewriteCond %{QUERY_STRING} ^category=(\w+)&subcategory=(\w+)&product=(\w+) [NC]
RewriteRule ^index\.php$ http://store.example.com/%1/%2/%3/? [R,L]
You can achieve this with multiple steps, by detecting one parameter and then forwarding to the next step and then redirecting to the final destination
RewriteEngine On
RewriteCond %{QUERY_STRING} ^category=([^&]+) [NC,OR]
RewriteCond %{QUERY_STRING} &category=([^&]+) [NC]
RewriteRule ^index\.php$ $0/%1
RewriteCond %{QUERY_STRING} ^subcategory=([^&]+) [NC,OR]
RewriteCond %{QUERY_STRING} &subcategory=([^&]+) [NC]
RewriteRule ^index\.php/[^/]+$ $0/%1
RewriteCond %{QUERY_STRING} ^product=([^&]+) [NC,OR]
RewriteCond %{QUERY_STRING} &product=([^&]+) [NC]
RewriteRule ^index\.php/([^/]+/[^/]+)$ http://store.example.com/$1/%1/? [R,L]
To avoid the OR and double condition, you can use
RewriteCond %{QUERY_STRING} (?:^|&)category=([^&]+) [NC]
as #TrueBlue suggested.
Another approach is to prefix the TestString QUERY_STRING with an ampersand &, and check always
RewriteCond &%{QUERY_STRING} &category=([^&]+) [NC]
This technique (prefixing the TestString) can also be used to carry forward already found parameters to the next RewriteCond. This lets us simplify the three rules to just one
RewriteCond &%{QUERY_STRING} &category=([^&]+) [NC]
RewriteCond %1!&%{QUERY_STRING} (.+)!.*&subcategory=([^&]+) [NC]
RewriteCond %1/%2!&%{QUERY_STRING} (.+)!.*&product=([^&]+) [NC]
RewriteRule ^index\.php$ http://store.example.com/%1/%2/? [R,L]
The ! is only used to separate the already found and reordered parameters from the QUERY_STRING.
I take a slightly different approach for this sort of thing, leveraging ENV VARs set and read by mod_rewrite. I find it more readable / maintainable to refer to the backreferences by name like this, and these ENV VARs can be reused later in request processing too. Overall I think it's a more powerful and flexible approach than the accepted answer here. In any case, it works well for me. I've copied my gist below in its entirety:
From https://gist.github.com/cweekly/5ee064ddd551e1997d4c
# Mod_rewrite is great at manipulating HTTP requests.
# Using it to set and read temp env vars is a helpful technique.
#
# This example walks through fixing a query string:
# Extract good query params, discard unwanted ones, reorder good ones, append one new one.
#
# Before: /before?badparam=here&baz=w00t&foo=1&bar=good&mood=bad
# After: /after?foo=1&bar=good&baz=w00t&mood=happy
#
# Storing parts of the request (or anything you want to insert into it) in ENV VARs is convenient.
# Note the special RewriteRule target of "-" which means "no redirect; simply apply side effects"
# This lets you manipulate the request at will over multiple steps.
#
# In a RewriteRule, set custom temp ENV VARs via [E=NAME:value]
# Note it's also possible to set multiple env vars
# like [E=VAR_ONE:hi,E=VAR_TWO:bye]
#
# You can read these values using %{ENV:VAR_NAME}e <- little "e" is not a typo
#
# Tangent:
# Note you can also read these env vars the same way, if you set them via SetEnvIf[NoCase]
# (It won't work to use SetEnv, which runs too early for mod_rewrite to pair with it.)
#
# Regex details:
# (?:) syntax means "match but don't store group in %1 backreference"
# so (?:^|&) is simply the ^ beginning or an & delimiter
# (the only 2 possibilities for the start of a qs param)
# ([^&]+) means 1 or more chars that are not an & delimiter
RewriteCond %{QUERY_STRING} (?:^|&)foo=([^&]+)
RewriteRule ^/before - [E=FOO_VAL:%1]
RewriteCond %{QUERY_STRING} (?:^|&)bar=([^&]+)
RewriteRule ^/before - [E=BAR_VAL:%1]
RewriteCond %{QUERY_STRING} (?:^|&)baz=([^&]+)
RewriteRule ^/before - [E=BAZ_VAL:%1]
RewriteRule ^/before /after?foo=%{FOO_VAL}e&bar=%{BAR_VAL}e&baz=%{BAZ_VAL}e&mood=happy [R=301,L]
P.S. This is not a copy/pasteable solution to your question, but rather shows exactly how to handle this kind of problem. Armed w this understanding, leveraging it for your example will be completely trivial. :)
1) In case You just need to check that all parameters are in url:
RewriteCond %{QUERY_STRING} (^|&)category\=computers($|&)
RewriteCond %{QUERY_STRING} (^|&)subcategory\=laptops($|&)
RewriteCond %{QUERY_STRING} (^|&)product\=dell\-inspiron\-15($|&)
RewriteRule ^$ http://store.example.com/computers/laptops/dell-inspiron-15/? [R=301,L]
2) In case You need exact set of parameters:
RewriteCond %{QUERY_STRING} ^&*(?:category\=computers|subcategory\=laptops|product\=dell\-inspiron\-15)(?!.*&\1(?:&|$))(?:&+(category\=computers|subcategory\=laptops|product\=dell\-inspiron\-15)(?!.*&\1(?:&|$))){2}&*$
RewriteRule ^$ http://store.example.com/computers/laptops/dell-inspiron-15/? [R=301,L]
This rule is generated by 301 redirect generator