Rewrite that appends a query string is not firing? - apache

I'd like to perform internal redirect
From /search/lalafa to /search/lalafa?post_type=review
The rule is
RewriteRule ^/search/([^/]+)$ /search/$1?post_type=review [L]
Seems correct but it doesn't seem to be matching:
https://htaccess.madewithlove.com/?share=c2ce1c7f-60be-40c8-9f0b-58ffc9eeba40

RewriteRule ^/search/([^/]+)$ /search/$1?post_type=review [L]
This will fail for two reasons:
The URL-path matched by the RewriteRule pattern in .htaccess does not include the slash prefix, so this rule never matches. It should be ^search/([^/]+)$.
If it did match it would create a rewrite-loop (500 Internal Server Error) since you are rewriting to the same URL-path and not checking the query string.
Try the following instead:
RewriteCond %{QUERY_STRING} !=post_type=review
RewriteRule ^search/[^/]+$ $0?post_type=review [L]
The $0 backreference contains the full URL-path, as matched by the RewriteRule pattern (NB: no slash prefix). The preceding condition checks that the query string is not already equal to post_type=review, thus preventing a rewrite-loop.

Related

I want to remove a string with a question mark at the end of my URL with .htaccess

I want to remove the string
?mobile=1
out from different URLs with .htaccess. So:
https://www.example.com/?mobile=1 should become https://www.example.com/
and
https://www.example.com/something/?mobile=1 should become https://www.example.com/something/
I tried the following
RewriteEngine On
RewriteRule ^(.+)?mobile=1 /$1 [R=301,L,NC]
But that does not seem to work. Any ideas?
RewriteRule ^(.+)?mobile=1 /$1 [R=301,L,NC]
The RewriteRule pattern matches against the URL-path only, which notably excludes the query string. So the above would never match. (Unless there was a %-encoded ? in the URL-path, eg. %3F)
To match the query string you need an additional condition (RewriteCond directive) and match against the QUERY_STRING server variable.
The regex .+ (1 or more) will not match the document root (ie. your first example: https://www.example.com/?mobile=1). You need to allow for an empty URL-path in this case. eg. .* (0 or more).
For example, try the following near the top of your root .htaccess file:
RewriteCond %{QUERY_STRING} =mobile=1
RewriteRule (.*) /$1 [QSD,R=301,L]
This matches the query string mobile=1 exactly, case-sensitive (as in your examples). No other URL parameters can exist. The = prefix on the CondPattern makes this an exact match string comparison, rather than a regex as it normally would.
And redirects to the same URL-path, represented by the $1 backreference in the substitution string that contains the URL-path from the captured group in the RewriteRule pattern.
The QSD (Query String Discard) flag removes the query string from the redirect response.
Test first with a 302 (temporary) redirect and and only change to a 301 (permanent) - if that is the intention - once you have confirmed this works as intended. 301s are cached persistently by the browser so can make testing problematic.

htaccess send 404 if query string contains keyword

I'm seeing a lot of traffic which I suspect is probing for a flaw or exploit with the request format of
https://example.com/?testword
I figured while I look into this more I could save resources and disrupt or discourage these requests with a 404 or 500 response
I have tried
RewriteEngine On
RewriteCond %{QUERY_STRING} !(^|&)testword($|&) [NC]
RewriteRule https://example.com/ [L,R=404]
And some other variations on the Query string match but none seem to return 404 when testing. Other questions I have found look for query string values/pairs and rewrite them but no examples seem to exits for just a single value.
RewriteCond %{QUERY_STRING} !(^|&)testword($|&) [NC]
RewriteRule https://example.com/ [L,R=404]
There are a few issues here:
The CondPattern in your condition is negated (! prefix), so it's only successfull when the testword is not present in the query string.
The RewriteRule directive is missing the pattern (first) argument (or substitution (second) argument depending on how you look at it). The RewriteRule directive matches against the URL-path only.
When you specify a non-3xx status code for the R flag, the substitution is ignored. You should specify a single hyphen (-) to indicate no substitution.
To test that the whole-word "testword" exists anywhere in the query string, you can use the regex \btestword\b - where \b are word boundaries. Or maybe you simply want the regex testword - to match "testword" literally anywhere, including when it appears as part of another word? In comparison, the regex (^|&)testword($|&) would miss instances where "testword" appears as a URL parameter name.
Try the following instead:
RewriteCond %{QUERY_STRING} \btestword\b [NC]
RewriteRule ^$ - [R=404]
This matches the homepage only (ie. empty URL-path). The L flag is not required when specifying a non-3xx return status, it is implied.
The - (second argument) indicates no substitution. As mentioned above, when specifying a non-3xx HTTP status, the substitution string is ignored anyway.
To test any URL-path then simply remove the $ (end-of-string anchor) on the RewriteRule pattern. For example:
RewriteCond %{QUERY_STRING} \btestword\b [NC]
RewriteRule ^ - [R=404]
If your homepage doesn't accept any query string parameters then you could simply reject the request (ie. 404 Not Found) when a query string is present. For example:
RewriteCond %{QUERY_STRING} .
RewriteRule ^$ - [R=404]

Rewrite URL containing directory path and parameters to parameter based URL using both path and query string

I use htaccess to rewrite this path:
/inventory/products/tools/
to this url with query string:
/inventory.php?cat=products&type=tools
using the following rule:
RewriteRule ^inventory/(.*)/(.*)/? /inventory.php?cat=$1&type=$2 [L,R=301]
When I add a query string to my url path
/inventory/products/tools/?sort=pricehigh
and use this rule
RewriteCond %{QUERY_STRING} ^(.*)$ [NC]
RewriteRule ^inventory/(.*)/(.*)/? /inventory.php?cat=$1&type=$2&%1 [L,R=301]
I am getting a redirect loop and the urlstring is rewritten over and over
I am trying to end up with the following destination url
/inventory.php?cat=products&type=tools&sort=pricehigh
In the example rule above I am using R=301 in order to visualize the url.
In a production I would use [L] only
Without the trailing slash, the second (.*) also allows for matching zero characters - so due to the greediness of regular expressions, the first (.*) matches products/tools already.
The following should work:
RewriteRule ^inventory/([^/]+)/([^/]+)/?$ /inventory.php?cat=$1&type=$2 [QSA,L,R=302,NE]
([^/]+) demands one or more characters, out of the class of characters that contains everything but the /.
The NE/noescape flag seems necessary here for some reason, otherwise the resulting query string will contain ?cat=products%26type=..., with the & URL-encoded.

.htaccess skip all rules if url matches

I want to skip all rewrite URLs when specific URL matches. I want to open this page:
https://www.example.com/.well-known/pki-validation/godaddy.html
If godaddy.html matches the URL. Here is what i am doing:
RewriteCond "%{REQUEST_URI}" "==/godaddy.html"
RewriteRule ^(.*)$ https://www.example.com/.well-known/pki-validation/godaddy.html [L]
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule ^(.*)$ https://www.example.com/index.php
but it does not work. I have also tried the [END] flag, but when I write flag [END] it gives me 500 internal server error.
If you want to stop rewriting, when the requested URL ends with godaddy.html, you can use a dash - as the substitution
Substitution of a rewrite rule is the string that replaces the original URL-path that was matched by Pattern. The Substitution may be a:
...
- (dash)
A dash indicates that no substitution should be performed (the existing path is passed through untouched). This is used when a flag (see below) needs to be applied without changing the path.
RewriteRule godaddy.html$ - [L]

How to mod_rewrite redirect php-file-url to new path

I want to redirect
http://api.domain.com/api.php?debug=true
to
http://api.domain.com/getData/?debug=true
What's wrong?
RewriteCond %{REQUEST_URI} !^/api\.php/.*
RewriteRule ^(.*)$ /getData/$1
Also not working
RewriteRule ^/api\.php(.*)$ /getData/$1 [PT]
That did the job
RewriteRule ^api.php$ /getData/
Let me first tell you what is wrong with your two attempts:
RewriteCond %{REQUEST_URI} !^/api\.php/.*
RewriteRule ^(.*)$ /getData/$1
This translates to: If the URI part of the url (after the domain and before the query string) does not match api.php, translate ^(.*)$ to /getData/$1. You want however to do it when the uri does match that string, making the condition obsolete.
RewriteRule ^/api\.php(.*)$ /getData/$1 [PT]
You tried to match the query string here with (.*), but that is not how it works. Besides that, in per-directory context (which is what .htaccess is), the url never starts with a slash. ^/ therefore never ever matches.
If you don't define a query string in the rewritten part, then the query string of the old url is appended to the new url. The correct rewriterule would be:
RewriteRule ^api\.php$ getData [R=301,L]
Please note that \. means "a literal dot". If I wouldn't escape it, then apisphp would redirect too. The R=301 flag will make it an external permanent redirect. The L flag will say that this is the last rule to match for this run through .htaccess. This is to prevent other rules matching on the full url, causing all kind of weird behaviour.