the auto urldecode in apache mod_rewrite - .htaccess

this is my apache .htaccess setting with a search page redirect
(RewriteRule ^search/(.*)$ /index.php?c=index&m=search&keywords=$1 [L,QSA]),
if I set the search query in url without %, it works success request without '%' but if a % char added to the string, apache with return a bad request with % , howerver instead of adding % but %25, the urlencoded string of %, success request when pre encode % to %25
I want to know about the reason of this situation. I guess in the RewriteRule of .htaccess an urldecode function worked from Pattern to Substitution, that's why % char cannot be recognized by the server, but %25 can. How can I disable this urldecode function?

Because the percent ("%") character serves as the indicator for percent-encoded octets, it must be percent-encoded as "%25" for that octet to be used as data within a URI (RFC 3986)
I think it's because Apache follows the standards, mod_rewrite has to unescape URLs before mapping them.. (https://httpd.apache.org/docs/current/rewrite/flags.html#flag_b)
Easy workaround for "disable" auto url decoding is to use Server-Variables like REQUEST_URI or THE_REQUEST in RewriteCond Directive (http://httpd.apache.org/docs/current/mod/mod_rewrite.html#RewriteCond)
RewriteEngine on
RewriteCond %{REQUEST_URI} /search/(.*)
RewriteRule . test.php?c=index&m=search&keywords=%1 [L,QSA]
If you use REQUEST_URI, in PHP you must use $_SERVER['REQUEST_URI']. Do not use $_SERVER['QUERY_STRING'] or $_GET, otherwise you will get the decoded url.
If you want all $_SERVER doing what you need, use THE_REQUEST instead:
RewriteEngine on
RewriteCond %{THE_REQUEST} \s/search/([^\s]*)
RewriteRule . test.php?c=index&m=search&keywords=%1 [L,QSA]
And we just need to put . (dot) in RewriteRule pattern and use %1 instead of $1

Related

Rewrite URL with query parameters in .htaccess

Say I have these urls:
https://example.com/bbs/board.php?bo_table=cad
https://example.com/bbs/board.php?bo_table=videos
https://example.com/bbs/board.php?bo_table=news
How can I rewrite these in .htaccess to something like this:
https://example.com/cad
https://example.com/videos
https://example.com/news
This is my attempt thus far. I know that my rewrite method is solid because it works on URL's without query strings. I tried the QSA flag (Query String Append) to no avail.
Options -MultiViews
RewriteRule ^bbs/board.php?bo_table=cad$ /caster-cad-downloads [R=301,L,QSA]
RewriteRule ^caster-cad-downloads$ bbs/board.php?bo_table=cad [END]
RewriteRule ^bbs/board.php?bo_table=video$ /caster-videos [R=301,L,QSA]
RewriteRule ^caster-videos$ bbs/board.php?bo_table=video [END]
RewriteRule ^bbs/board.php?bo_table=news$ /news [R=301,L,QSA]
RewriteRule ^news$ bbs/board.php?bo_table=news [END]
How can I rewrite to a different URL instead of the query string while still using the
%{QUERY_STRING method?
RewriteCond %{QUERY_STRING} ^bo_table=(cad|videos|news)$
RewriteRule ^bbs/board\.php$ /%1 [QSD,R=301,L]
# RewriteRule ^(caster-cad-downloads|caster-videos|news)$ bbs/board.php?bo_table=$1 [END]
RewriteRule ^(?:caster-(cad)-downloads|caster-(videos)|(news))$ bbs/board.php?bo_table=$1 [END]
How can I rewrite these in .htaccess to something like this:
The "rewrite" is the other way round (as mentioned previously). The incoming request is for /cad and this is internally rewritten to /bbs/board.php?bo_table=cad that actually handles the request.
This can be achieved with a single rule since these 3 URLs follow the same pattern (although that conflicts with the code sample you've posted). For example:
RewriteRule ^(cad|videos|news)$ bbs/board.php?bo_table=$1 [END]
The $1 backreference contains the value of the first capturing group in the RewriteRule pattern. ie. either cad, videos or news.
The external redirect is not strictly necessary, unless you are changing an existing URL structure. Note that the RewriteRule pattern matches against the URL-path only, which notably excludes the query string. (So your rules that include a query string would never match.) To match the query string you need an additional condition (RewriteCond directive) and match against the QUERY_STRING server variable. For example, the following would go before the above rewrite:
RewriteCond %{QUERY_STRING} ^bo_table=(cad|videos|news)$
RewriteRule ^bbs/board\.php$ /%1 [QSD,R=301,L]
Note that we need to use the QSD flag here in order to discard the original query string, we don't want to append it.
The %1 backreference (as opposed to $1) matches the capturing group in the last matched CondPattern (RewriteCond directive).
Don't forget to backslash-escape literal dots in the regex in order to negate their special meaning.
UPDATE:
RewriteRule ^(cad-downloads|cad-videos|news)$ bbs/board.php?bo_table=$1 [END]
To pass cad, videos (video?) or news as the URL parameter, you could do it like this:
RewriteRule ^(?:(cad)-downloads|cad-(videos)|(news))$ bbs/board.php?bo_table=$1 [END]
This is made possible because cad, videos and news are still part of the requested URL. The outer regex group is made non-capturing (with the ?: prefix). An additional capturing group inside this captures the necessary part of the requested URL.
However, the reverse is not possible without hardcoding the mappings.
I'll see if I can get back to your other queries/chat tomorrow...

Sanitize query parameters in the URL with htaccess

Is there a way with mod_rewrite to sanitize an URL of this type:
https://www.example.com/blabla/?&param1=1&param2=2
to
https://www.example.com/blabla/?param1=1&param2=2
Thank you
RewriteCond %{QUERY_STRING} ^&(.*)
RewriteRule ^(.*)$ /$1?%1 [R=301,L]
That should basically do it. The RewriteCond matches on any query string that starts with &, and simply captures the rest.
And then you simply insert the back reference to that "rest" into the substitution URL, using %1.
Edit: Pattern changed to (.*) to capture all URL paths; back reference $1 inserted into substitution URL.

remove all querystring from any url [duplicate]

Have been trying to write a redirect rule with query string but did not succeed.
I have the URL example.com/blog/?page=1 or example.com/blog/?hello, so it does not really matter what goes in the query string. How do I write a Redirect rule, so that it cuts the query string and redirects to the URL before the query string. For example, both of those URLs have to redirect to example.com/blog/ so that URL does not contain any query string.
I was trying
RewriteRule ^blog/?$ blog/ [R=301,L,NE] but got redirected to 404 page.
Also tried
RewriteRule ^blog/?$ /blog/ [R=301,L,NE] and got the message that page is not working, 'URL' redirected you too many times.
BTW, technology I am using is Gatsby with htaccess plugin.
To remove the query string you first need to check that there is a query string to remove, otherwise, it should do nothing.
For example, to remove the query string from /blog/?<query-string> you would do something like this:
RewriteCond %{QUERY_STRING} .
RewriteRule ^(blog)/?$ /$1/ [QSD,R=302,L]
This matches the URL-path blog/ (trailing slash optional) and redirects to /blog/ (with a trailing slash). Your example URL includes the trailing slash, but your regex appears to suggest the trailing slash is optional?
The preceding condition (RewriteCond directive) checks the QUERY_STRING server variable to make sure this is non-empty (ie. it matches a single character, denoted by the dot).
The $1 backreference in the substitution string contains the value from the captured group in the preceding RewriteRule pattern. ie. "blog" in this example. This simply saves repetition. You could just as easily write RewriteRule ^blog/?$ /blog/ [QSD,R,L] instead.
The QSD (Query String Discard) flag removes the original query string from the redirected response, otherwise, this would be passed through by default (which would create a redirect-loop).
If the request does not contain a query string then this rule does nothing (since the condition will fail).
If this is intended to be permanent then change the 302 (temporary) redirect to 301 (permanent), but only once you have confirmed this works as intended. 301s are cached persistently by the browser so can make testing problematic.
A look at your existing rules:
was trying RewriteRule ^blog/?$ blog/ [R=301,L,NE] but got redirected to 404 page.
By default, the relative substitution string (ie. blog/) is seen as relative to the directory that contains the .htaccess file and this "directory-prefix" is then prefixed back to the relative URL, so this will (by default) result in a malformed redirect of the form https://example.com/path/to/public_html/blog/.
Also tried RewriteRule ^blog/?$ /blog/ [R=301,L,NE] and got message that page is not working, 'url' redirected you too many times.
This is not checking for (or removing) the query string so this is basically just redirecting to itself - an endless redirect-loop.
Remove any query string from any URL
What rule do i write, to remove query string from any URL.
Modify the RewriteRule pattern to match any URL and redirect to the same. For example:
RewriteCond %{QUERY_STRING} .
RewriteRule (.*) /$1 [QSD,R=302,L]
This needs to go at the top of the root .htaccess file before any existing rewrites.
If the .htaccess file is in a subdirectory (not the root) then you will need to do something like the following instead, since the $1 backreference (as used above) won't contain the complete root-relative URL-path.
RewriteCond %{QUERY_STRING} .
RewriteRule ^ %{REQUEST_URI} [QSD,R=302,L]

Redirect rule to remove query string from URL

Have been trying to write a redirect rule with query string but did not succeed.
I have the URL example.com/blog/?page=1 or example.com/blog/?hello, so it does not really matter what goes in the query string. How do I write a Redirect rule, so that it cuts the query string and redirects to the URL before the query string. For example, both of those URLs have to redirect to example.com/blog/ so that URL does not contain any query string.
I was trying
RewriteRule ^blog/?$ blog/ [R=301,L,NE] but got redirected to 404 page.
Also tried
RewriteRule ^blog/?$ /blog/ [R=301,L,NE] and got the message that page is not working, 'URL' redirected you too many times.
BTW, technology I am using is Gatsby with htaccess plugin.
To remove the query string you first need to check that there is a query string to remove, otherwise, it should do nothing.
For example, to remove the query string from /blog/?<query-string> you would do something like this:
RewriteCond %{QUERY_STRING} .
RewriteRule ^(blog)/?$ /$1/ [QSD,R=302,L]
This matches the URL-path blog/ (trailing slash optional) and redirects to /blog/ (with a trailing slash). Your example URL includes the trailing slash, but your regex appears to suggest the trailing slash is optional?
The preceding condition (RewriteCond directive) checks the QUERY_STRING server variable to make sure this is non-empty (ie. it matches a single character, denoted by the dot).
The $1 backreference in the substitution string contains the value from the captured group in the preceding RewriteRule pattern. ie. "blog" in this example. This simply saves repetition. You could just as easily write RewriteRule ^blog/?$ /blog/ [QSD,R,L] instead.
The QSD (Query String Discard) flag removes the original query string from the redirected response, otherwise, this would be passed through by default (which would create a redirect-loop).
If the request does not contain a query string then this rule does nothing (since the condition will fail).
If this is intended to be permanent then change the 302 (temporary) redirect to 301 (permanent), but only once you have confirmed this works as intended. 301s are cached persistently by the browser so can make testing problematic.
A look at your existing rules:
was trying RewriteRule ^blog/?$ blog/ [R=301,L,NE] but got redirected to 404 page.
By default, the relative substitution string (ie. blog/) is seen as relative to the directory that contains the .htaccess file and this "directory-prefix" is then prefixed back to the relative URL, so this will (by default) result in a malformed redirect of the form https://example.com/path/to/public_html/blog/.
Also tried RewriteRule ^blog/?$ /blog/ [R=301,L,NE] and got message that page is not working, 'url' redirected you too many times.
This is not checking for (or removing) the query string so this is basically just redirecting to itself - an endless redirect-loop.
Remove any query string from any URL
What rule do i write, to remove query string from any URL.
Modify the RewriteRule pattern to match any URL and redirect to the same. For example:
RewriteCond %{QUERY_STRING} .
RewriteRule (.*) /$1 [QSD,R=302,L]
This needs to go at the top of the root .htaccess file before any existing rewrites.
If the .htaccess file is in a subdirectory (not the root) then you will need to do something like the following instead, since the $1 backreference (as used above) won't contain the complete root-relative URL-path.
RewriteCond %{QUERY_STRING} .
RewriteRule ^ %{REQUEST_URI} [QSD,R=302,L]

Redirect all url start with /index.php?controller=allproducts to the home (with .htaccess)

I used this rule, but nothing happen when visiting pages starting with that string.
RewriteEngine on
RewriteRule ^index.php?controller=allproducts(.*)$ / [R=301,L]
What I'm doing wrong?
Query strings aren't considered to be a part of the URI, instead you need to use a condition search for the query string itself:
RewriteEngine on
RewriteCond %{QUERY_STRING} ^controller=allproducts$
RewriteRule (.*) $1? [R,L]
This would redirect http://website.com/index.php?controller=allproducts to http://website.com/index.php
Or if you're on Apache 2.4 you can use the [QSD] flag which discards the query. You would need to setup backreferences if you wanted to keep part of the query or use an absolute URL on the substitution if you wan't everything to go to the homepage.

Resources