htaccess rewrite condition that uses regex - apache

I'm a noob when it comes to regex. What I'm trying to accomplish is:
https://www.example.com/shop/product-floating-front-rotor-kit/
should redirect to
https://www.example.com/shop/product-matching-front-rotor/
product should be the name of the product, I have to do this for multiple products.
Edit: This is what I have so far, am I even close?
RewriteEngine On
RewriteRule ^/shop/([a-z]+)-floating-front-rotor-kit/ ^/shop/$1-matching-front-rotor/

RewriteRule ^/shop/([a-z]+)-floating-front-rotor-kit/ ^/shop/$1-matching-front-rotor/
This is close, except that...
In .htaccess the URL-path matched by the RewriteRule pattern (first argument) does not start with a slash.
The substitution string has an erroneous ^ prefix. This should be an "ordinary" string, not a regex.
[a-z] does not match hyphens/dashes, which you state could occur in a product name.
You have not included an end-of-string anchor ($) on the end of the RewriteRule pattern, so any trailing string will be successful and discarded. (Is that the intention?)
This is an internal "rewrite", not a "redirect" as stated. You need to include the R flag. (An internal rewrite is unlikely to work here, since the target URL requires further rewriting.)
Try the following instead. This should go at the top of the .htaccess file, immediately after the RewriteEngine directive.
RewriteRule ^shop/([a-z-]+)-floating-front-rotor-kit/$ /shop/$1-matching-front-rotor/ [R=302,L]
This is a 302 (temporary) redirect.

Related

How to redirect URL using .htaccess with dynamic parameter?

I want to redirect
https://example.com/product-info/A100001
to
https://example.com/product-info/index/index/id/A100001
using htaccess redirect rule
A100001 will be dynamic like
A100001
A100002
A100003
A100004
....
I am trying this
RewriteEngine on
RewriteCond %{QUERY_STRING} product-info/A100001
RewriteRule ^$ /routing/index/index/id/? [L,R=301]
Source
Also tried other example but not working in my scnario
Anyone who expert in htacees rules can help me in this.
RewriteCond %{QUERY_STRING} product-info/A100001
RewriteRule ^$ /routing/index/index/id/? [L,R=301]
Your example URL contains a URL-path only, it does not contain a query string. The rule you've posted would redirect /?product-info/A100001 to /routing/index/index/id/.
Try something like the following instead:
RewriteRule ^(product-info)/(A\d{6})$ /$1/index/index/id/$2 [R=302,L]
The above would redirect a request of the form /product-info/A123456 to /product-info/index/index/id/A123456.
The $1 backreference simply contains product-info, captured from the RewriteRule pattern (saves repitition) and $2 contains the dynamic part (an A followed by 6 digits).
This is a 302 (temporary) redirect. Always test first with a 302 to avoid potential caching issues.
The order of directives in your .htaccess file is important. This rule will likely need to go near the top of the file, before any existing rewrites.
UPDATE:
redirection is working with your code, Can you please let me know the parameter pattern, I need the number from A452218 to A572217
Regex does not handle numeric ranges, only character ranges. If you specifically only want to match numbers in the stated range then you would need to do something (more complex) like this:
RewriteRule ^(product-info)/A(45221[89]|4522[2-9]\d|452[3-9]\d{2}|45[3-9]\d{3}|4[6-9]\d{4}|5[0-6]\d{4}|57[01]\d{3}|572[01]\d{2}|57220\d|57221[0-7])$ /$1/index/index/id/A$2 [R=302,L]
NB: The $2 backreference now only contains the dynamic number, less the A prefix, which is now explicitly included in the substitution string.

remove //xx after directory in URL

I need to redirect all URLs like this:
example.com/podcasts//rebt
to
example.com/podcasts
I am trying to adjust this code to do both but I can't get it to work:
RewriteCond %{REQUEST_METHOD} !=POST
RewriteCond %{REQUEST_URI} ^(.*?)(/{2,})(.*)$
RewriteRule . %1/%3 [R=301,L]
To remove //<something> at the end of the URL-path (eg. /podcasts//rebt to /podcasts, try the following instead at the top of the root .htaccess file:
RewriteEngine On
RewriteCond %{THE_REQUEST} \s([^?]+?)//
RewriteRule . %1 [R=301,L]
THE_REQUEST server variable contains the first line of the initial request headers (eg. GET /podcasts/rebt HTTP/1.1) and does not change when the request is internally rewritten (unlike REQUEST_URI).
The regex \s([^?]+?)// captures the part of the URL-path before the first instance of a double slash. Anything after and including the double slash, are discarded. This regex also ensures we do not inadvertently match against the query string (if any).
The %1 backreference contains the captured subpattern (ie. everything before the first double slash in the URL-path) from the preceding CondPattern.
Aside: Note that this will not work properly if the preceding URL-path maps to a physical directory, since it will result in two redirects. eg. /directory//something to /directory to /directory/ (by mod_dir). In this case, you should avoid removing the first trailing slash.
You should test first with a 302 (temporary) redirect to avoid any potential caching issues and only change to a 301 (permanent) redirect when you are sure it's working as intended. You should clear your browser cache before testing.
A look at your existing rule...
RewriteCond %{REQUEST_METHOD} !=POST
RewriteCond %{REQUEST_URI} ^(.*?)(/{2,})(.*)$
RewriteRule . %1/%3 [R=301,L]
This code is intended to reduce multiple slashes to single slashes in the URL-path, not remove the double slash and remaining path entirely. eg. /podcasts//rebt to /podcasts/rebt. However, since it checks against the REQUEST_URI server variable (which can change throughout the request) it may not work as intended.
Also, the condition that checks against the REQUEST_METHOD would seem to be redundant, unless you are erroneously POSTing to double-slashed URLs internally? A 301 redirect removes any POST data (since the browser converts it to GET) - hence why the check may be necessary in certain cases.

Redirect a URL with two query string parameters to a new domain with a changed path using Apache's rewrite rules

I'm trying to do the following thing:
Transform URL: https://example.com/human/?system=jitsi&action=SYSTEM
to: https://new.example/?action=SYSTEM&system=jitsi
RewriteEngine On
RewriteCond %{REQUEST_METHOD} GET
RewriteCond "%{QUERY_STRING}" action=(.+)
RewriteRule / https://new.example/?action=SYSTEM&system=%1?
Unfortunately I can't get the expected result.
Your rules have several problems:
You aren't matching the human/ in the URL path that you are trying to remove.
Neither your condition nor your rule has regex markers for "starts with" (^) or "ends with" ($) which means that they are matching substrings rather than full strings.
Your rule starts with a slash which means that it can't be used in .htaccess, only in Apache's conf files. I recommend starting rules with an optional slash /? so that they can be used in either context.
Your query string condition is only matching one of the two parameters that you say need to be present to redirect.
(.+) in your query string condition can match too much. It would include other parameters separated by an ampersand (&). This should be changed to ([^&]+) meaning "at least one character not including ampersands"
You have an extra stray ? at the end of your target URL that would be interpreted as part of the value of the system parameter.
You don't explicitly specify flags for redirect ([R]) or last ([L]) which are best practice to include.
RewriteEngine On
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{QUERY_STRING} ^system=([^&]+)&action=([^&]+)$
RewriteRule ^/?human/$ https://new.example/?action=%2&system=%1 [R,L]

htaccess RewriteRule : Problem to omit all after 1st argument

Goal: Want to rewrite all URLs of type
https://www.example.com/page/1234/?/blog/foo/bar/
to
https://www.example.com/page/1234/
In .htaccess I tried many variations along the line
RewriteEngine On
RewriteBase /
RewriteRule ^page/(\d+)/(.*)$ /page/$1 [R=301,L]
Using an .htaccess tester I see that at least the matching pattern is valid.
I would expect that the rewrite would not include anything after $1, but it does, and show the complete original URL.
What am I missing?
https://www.mypage.com/page/1234/?/blog/foo/bar/
Everything after the first ? is the query string part of the URL. By default, Apache passes the query string unaltered from the request to the target URL (unless you create a new query string yourself on the RewriteRule substitution). This explains why you are seeing the same query string on the target URL, without seemingly doing anything with it.
Incidentally, the RewriteRule pattern only matches against the URL-path only - this notably excludes the query string. To match the query string in mod_rewrite you need an additional condition that checks the QUERY_STRING server variable.
On Apache 2.4+ you can use the QSD (Query String Discard) flag to remove the query string from the target URL. Or, specify an empty query string on the substitution - by including a trailing ? (the ? itself does not appear on the resulting URL).
For example (on Apache 2.4):
RewriteCond %{QUERY_STRING} .
RewriteRule ^page/(\d+)/ /page/$1/ [QSD,R=301,L]
The RewriteCond directive checks for the presence of a query string, which is necessary to prevent a redirect loop.
The trailing (.*)$ on the RewriteRule pattern was superfluous.
You had omitted the trailing slash on the end of the substitution (that is present on the example URL). This would have also prevented a redirect loop, but as mentioned, this is not as per your example. (Alternatively, you could include the slash in the captured backreference.)
If you are still on Apache 2.2 then you would need to include a trailing ? instead of the QSD flag. For example:
RewriteRule ^page/(\d+)/ /page/$1/? [R=301,L]
You will need to clear your browser cache before testing, as 301 (permanent) redirects are cached persistently by the browser. For this reason, it is often easier to first test with 302 (temporary) redirects.

Conditional rewrite in the regex, not with RewriteCond

I wrote a regex for a rewrite rule that includes a negative lookahead to replace the rewriteCond line, because WordPress only accepts two values: pattern -> substitution.
It should find findme.html _here, regardless of where it's requested to be:
mydomain.com/_here/findme.html
e.g.
(Sorry, I can't modify the swf which will request findme.html in the wrong places)
So, given findme.html could be requested to be in, e.g.:
mydomain.com/findme.html
mydomain.com/directory/findme.html
mydomain.com/directory/findme.html?someparam=3
The rewrite should make them all
mydomain.com/_here/findme.html
So, I made a rewrite rule that Wordpress will accept me as follow
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^.*(?!_here)/*findme\.html$ /_here/findme.html [R=301,L]
So it only matches URLs which doesn't contain "_here" in it, to prevent extra rewriting or a loop.
The problem is IT DOES loop.
What did I miss?
It looks to me like you want to move the .* that is before (?!_here) to after it because (?!_here) is a negative lookahead, so it check that the text _here does not come after it. What your regular expression is actually checking is whether your url starts with some character sequence that is not followed by _here, and _here is a character sequence not followed by _here. Then your rule becomes
RewriteRule ^(?!_here).*/*findme\.html$ /_here/findme.html [R=301,L]
Also, it looks like your pattern will exclude paths with subdirectories such as
mydomain.com/directory/subdirectory/findme.html
If you also want to include those, the pattern should be
RewriteRule ^(?!_here)(.*/)*findme\.html$ /_here/findme.html [R=301,L]