How I can rewrite a query-string based URL only partially - apache

I want to rewrite the following URL, based on part of its query string, but at the same time, I want to keep the rest of the Query String.
Original URL:
http://example.com/index.php?route=product/show&item_id=25&show_mobile=true
To be converted to:
http://example.com/product/show/?item_id=25&show_mobile=true
I have searched and found the following wiki on Apache:
https://wiki.apache.org/httpd/RewriteQueryString
But it hasn't a section for rewriting a single Key&Value pair in Query string and keeping the rest.

This should get you close, it's based on the "remove a key" entry from the wiki. You want to isolate the part that will go into the path in the first capture and use the 2nd capture for the remaining query string.
RewriteCond %{QUERY_STRING} ^(route=[^&]*)&(.*)
RewriteRule ^index.php /%1?%2

You can use this generic rule to capture parameter value of route in any order from query string and reuse in target URL:
RewriteEngine On
RewriteCond %{THE_REQUEST} \?(.*&)?route=([^&]*)&?(\S*)\sHTTP [NC]
RewriteRule ^index\.php$ /%2?%1%3 [R=301,NE,L]

Related

Can't pass parameters to another redirect website

I want to redirect to another website, and pass the parameters also.
Example: I go to my website: source.example/?code=12345
Then, I want it to redirect to target.example/?code=12345.
I am currently using this for my .htaccess file, since I figured out from other posts that if I query a certain parameter, it will get passed also:
RewriteEngine On
RewriteCond %{QUERY_STRING} ^code=[NS]$
RewriteRule "www.google.com" /$1 [R=302,L]
Also, I tried many different approaches looking at these stack questions:
simple .htaccess redirect : how to redirect with parameters?
Redirect and keep the parameter in the url on .htaccess
But I can't get it running :(
since I figured out from other posts that if I query a certain parameter, it will get passed also
This is not true. The query string is passed through by default - there is nothing extra you need to do if you want the same query string on the target URL.
RewriteCond %{QUERY_STRING} ^code=[NS]$
RewriteRule "www.google.com" /$1 [R=302,L]
This code won't match the source URL for many reasons:
"www.google.com" - The first argument to the RewriteRule directive is a regex that matches the source URL-path (less the slash prefix). In your example the URL-path is empty.
^code=[NS]$ matches either code=N or code=S - which is not the intention from your example. (The [NS] looks like a mangled RewriteRule flag?!)
/$1 - this is the substitition string, ie. the URL you want to redirect to. (The $1 backreference is always empty, so this is meaningless.)
To redirect from source.example/?code=<number> to https://target.example/?code=<number> then try the following instead:
RewriteCond %{HTTP_HOST} ^source\.example [NC]
RewriteCond %{QUERY_STRING} ^code=\d+$
RewriteRule ^$ https://target.example/ [R=302,L]
This only matches a query string of the form code=1234. It does not match code= or code=1234&foo=bar, etc.
The query string is passed through by default.
If source.example is the only domain being hosted at the current location then you can remove the first condition that explicitly checks the requested hostname.
The order of directives in the .htaccess file is important. An external redirect like this should go near the top.

mod_rewrite: encode only certain matches in URL

I am trying to rewrite a URL using mod_rewrite and encode a substring in my URL which is between brackets. My URL:
http://localhost/something?var_a=A&var_b=(B&2/3&)&var_c=C
and my .htaccess:
RewriteEngine On
RewriteCond %{QUERY_STRING} (.+)\((.*?)\)(.+)
RewriteRule ^.*$ somedir/%1%2%3? [R,B]
so I capture three strings, anything before the brackets, anything within, and anything after.
Result is:
somedir/var_a%3dA%26var_b%3dB%262%2f3%26%26var_c%3dC
but I would like to encode only the text which was within the brackets of my initial URL, such that
somedir/var_a=A&var_b=dB%262%2f3%26&var_c=C
The problem seems to be that the [B] option decodes the whole string. Is there a way to do this selectively? Also, my solution could only capture an occurrence of brackets once, it would be nice to have this more generic; could someone give me a hint?
Note that this question is related to my previous one, where I was trying to capture text between brackets.
This is extremely tricky for mod_rewrite but I took a shot at it. Solution is not pretty as it involves 2 redirects and use of cookies, but it works.
RewriteEngine On
# store non bracket query string in cookie while redirecting value in brackets using B flag
RewriteCond %{QUERY_STRING} ^(.+?&)?(var_b=)\(([^)]*)\)(.*)$ [NC]
RewriteRule !^somedir/ /somedir/%3? [L,CO=QS:%1-%2-%4:%{HTTP_HOST},B,R]
# retrieve value from cookie and use it to construct full URL
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{HTTP_COOKIE} QS=([^-]*)-([^-]+)-([^;]+) [NC]
RewriteRule ^(somedir)/(.*)$ /$1/%1%2$2%3? [L,R,NE]
Using these rules when I visit this URL: http://localhost/something?var_a=A&var_b=(B&2/3&)&var_c=C
it gets redirected to: http://localhost/somedir/var_a=A&var_b=B%262%2f3%26&var_c=C

How to capture the parameter value by mod_rewrite

I'm using Apache2.2.17 and am trying to redirect the URL like below with the same parameter value being preserved but having a different key name.
/aaa/bbb/ccc?oldkey=value => /ddd?newkey=value
I'm trying some variations of RewriteRule like below but not successful.
RewriteRule /aaa/bbb/ccc?oldkey=(.*) /ddd?newkey=$1 [R,L]
Then I noticed that if I have the condition like below, only the last path value is preserved and parameter key/value are lost.
RewriteRule /aaa/bbb/(.*) /ddd?newkey=$1 [R,L] ;This produces /ddd?newkey=ccc
So my question is,
Is there a way to capture the parameter value by using Apache mod_rewrite and how can I achieve that? (I can use mod_proxy too)
Thank you in advance.
You can check what's in %{QUERY_STRING}:
RewriteCond %{QUERY_STRING} oldkey=(.*)
RewriteRule .* /ddd?newkey=%1 [R,L]
Where %1 is the first capture group from RewriteCond (called RewriteCond backreference).
If by "parameter value" you mean the querystring then you can append it to your rewrites by adding QSA to your command so you have [QSA,R,L]

rewrite url using htaccess

How can I change url in this way using htaccess:
http://example.com/page.php?go=something.php
should be redirected to:
http://example.com/something
If the get parameter name is different than 'go' leave as it is...
This should do:
# Assuming that "RewriteEngine On" has already been called
RewriteCond %{QUERY_STRING} ^(.*&)?go=([a-z]+)\.php(&.*)?$
RewriteRule page.php %2?
What happens here? First, RewriteCond matches a query string that contains the go=something.php, where "something" is captured by ([a-z]+). Then the RewriteRule uses the second capture group's contents from RewriteCond, containing "something.php". The question mark at the end gets rid of the original query string.
Note: if you want to preserve the rest of the query string excluding go=... parameter, things get a bit more complicated.
See the docs in http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html for more info.
something like this (google around for the correct syntax)
RewriteEngine On
RewriteBase /
RewriteRule ^page.php?go=login.php /login [L]

Mod Rewrite: Handling two Get Variables

How can I edit this url rewrite to include a further get variable being appended to the URL? I have tried a few attemps but I always get a 500 internal server error!
I have added comments to show what I am trying to achieve.
# /view.php?user=h5k6&page=1 externally to /h5k6/1
# Some times the page get variable will not exist so it should just show /h5k6
RewriteCond %{THE_REQUEST} ^GET\ /view\.php
RewriteCond %{QUERY_STRING} ^([^&]*&)*user=([^&]+)&?.*$
RewriteRule ^view\.php$ /%2? [L,R=301]
# /h5k6/1 internally to /view.php?t=h5k6&page=1
RewriteRule ^([0-9a-z]+)$ view.php?t=$1 [L]
Thanks all for any help
The problem with URI query arguments is that they may appear in any order. With two arguments you just have two permutations (A before B and B before A). But the more arguments you want to extract the more permutations you have (n!).
That means you should put the arguments in the right order so that you can them at a time:
RewriteCond %{THE_REQUEST} ^GET\ /view\.php
RewriteCond %{QUERY_STRING} ^(([^&]*&)*)(page=[^&]+)&?([^&].*)?$
RewriteCond %3&%1%4 ^(([^&]*&)*)(user=[^&]+)&?([^&].*)?$
RewriteCond %3&%1%4 ^user=([^&]+)&page=([^&]+)&?([^&].*)?$
RewriteRule ^view\.php$ /%1/%2?%3 [L,R=301]
The first condition checks the request line like in your rule. The second condition picks the page argument and puts it at the start of the query string. The third condition does the same with the user argument so that the order always is: first user, second page. Then we use the fourth condition to take both argument values at a time to use them in the RewriteRule replacement. The rest of the query is appended to the replacement URI (see %3) but you can leave that off if you want.
As you see, the more arguments you want to extract, the more complex it gets. And it is easier to do that with a language that is more powerful than mod_rewrite like PHP.