How this regex matches in htaccess - regex

I am trying to add trailing slash to a url. I have my own logic to do so but found another one on stackoverflow (here). Now the regex in this line
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
apparently matches the RewriteRule for the url http://www.example.com/wp-admin.
What I first did was:
RewriteCond %{REQUEST_URI} /wp-admin$ [NC]
RewriteCond %{REQUEST_URI} !/+$
RewriteRule ^ %{ENV:proto}://%{HTTP_HOST}%{REQUEST_URI}/ [R=301,L]
So my question is how /wp-admin$ is similar to ^([_0-9a-zA-Z-]+/)?wp-admin$?

This is because leading slash is matched when you use RewriteCond %{REQUEST_URI} but current directory (relative to DocumentRoot) is stripped when you use a pattern in RewriteRule in .htaccess file, which is a per directory directive.
Hence a leading slash is not matched in RewriteRule but is matched in RewriteCond.

Related

Query string not redirected on deeper level directories

I want to redirect each link with a query string to a specific address by appending the string. I have the following in my WordPress .htaccess:
RewriteEngine On
RewriteCond %{QUERY_STRING} catid=([0-9]+) [NC]
RewriteRule (.*) catid%1? [R=301,L]
When a user hits example.com/?catid=10, they are successfully redirected to example.com/catid10, which is what I want.
However, when they go a directory deeper (example.com/category/?catid=10), they are not redirected to example.com/category/catid10.
I have been reading manuals but can't find the answer.
Edit
If this is helpful, this is what WordPress has defined in my htaccess:
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Providing RewriteBase / is already defined (which it normally is with WordPress and must be if your existing redirect is working) then you can do it like the following with a single rule:
RewriteCond %{QUERY_STRING} (?:^|&)catid=(\d+) [NC]
RewriteRule (.*?)/?$ $1/catid%1 [QSD,R=301,L]
The capturing group (.*?) is non-greedy so does not consume the optional trailing slash that follows.
Requests for the document root do not require RewriteBase, but all "deeper" URLs do, since the resulting substitution string will otherwise be a relative URL.
The non-capturing (?:^|&) prefix on the CondPattern ensures that it only matches the URL parameter name catid and not foocatid etc.
You just need to add the captured group from (.*) to your redirect target using $1. I'd break it up into a few rules so that you don't get duplicated slashes. Rather then ending your rewrite targets with a question mark, I would add the QSD (query string discard) flag to the rule. I would also add starts with (^) and ends with ($) to rewrite rule so you always match the whole thing. I also like to start my rules with an optional slash (/?) so that the rules can be used in both .htaccess and apache conf.
RewriteEngine On
# Home URL with catid query string
RewriteCond %{QUERY_STRING} catid=([0-9]+) [NC]
RewriteRule ^/?$ /catid%1 [R=301,L,QSD]
# Deep URL ending in slash with a catid query string
RewriteCond %{QUERY_STRING} catid=([0-9]+) [NC]
RewriteRule ^/?(.*)/$ /$1/catid%1 [R=301,L,QSD]
# Deep URL not ending in slash with a cadid query string
RewriteCond %{QUERY_STRING} catid=([0-9]+) [NC]
RewriteRule ^/?(.*)$ /$1/catid%1 [R=301,L,QSD]

RewriteRule to handle one domain two folders to two domains no folder

I am attempting to create rewrite rules to handle some specific website redirections:
I would like domain1.ca/folder1/xyz to go to domain2.ca/xyz and domain1.ca/folder2/xyz to go to domain3.ca/xyz
Right now my attempts are as following:
RewriteCond %{HTTP_HOST} ^domain1.ca$ [OR]
RewriteCond %{HTTP_HOST} ^www.domain1.ca$
RewriteRule ^(\/folder1\/)(.*)$ "https://domain2.ca/$1" [R=301,L]
RewriteCond %{HTTP_HOST} ^domain1.ca$ [OR]
RewriteCond %{HTTP_HOST} ^www.domain1.ca$
RewriteRule ^(\/folder2\/)(.*)$ "https://domain3.ca/$1" [R=301,L]
Any help would be greatly appreciated :) Thx.
A couple of problems with your existsing rules:
In .htaccess the URL-path matched by the RewriteRule pattern does not start with a slash. So, the URL-path starts folder1/xyz, not /folder1/xyz.
You are unnecessarily capturing "folder1" in the first parenthesised subpattern and using this in the substitution string (ie. $1). You should be using $2, or don't capture the first path segment.
The directives could also be tidied up a bit (eg. no need to backslash-escape slashes in the regex and the conditions can be combined).
Try the following instead:
RewriteCond %{HTTP_HOST} ^(www\.)?domain1\.ca [NC]
RewriteRule ^folder1/(.*) https://domain2.ca/$1 [R=301,L]
RewriteCond %{HTTP_HOST} ^(www\.)?domain1\.ca [NC]
RewriteRule ^folder2/(.*) https://domain3.ca/$1 [R=301,L]
Additional notes:
The end-of-string anchor ($) following (.*)$ in the RewriteRule pattern is not required since regex is greedy by default.
You only need to surround the argument in double quotes if it contains spaces.
I removed the end-of-string anchor ($) from the end of the CondPattern to also match fully qualified domain names that end in a dot.
I added the NC flag to the condition. It's technically possible that some bots can send a mixed/uppercase Host header.
Test first with 302 (temporary) redirects to avoid potential caching issues.

htaccess RewriteRule regex

I have hundreds of these old links I need to redirect.
Here is one example:
/index.php?option=com_content&view=article&id=433:seventh-character-code-categories-and-icd-10-cm&Itemid=101&showall=1
to
/seventh-character-code-categories-and-icd-10-cm
Essentially I need to remove the /index.php?option=com_content&view=article&id=433: part.
I tried this but I am getting confused with the [0-9] and : parts, so the following does not work:
RewriteRule ^/index.php?option=com_content&view=article&id=[0-9]:(.*)$ /$1 [L,R=301]
Say you want to capture from after : to right before & in the query string you mentioned, then try this expression:
^[^\:]*\:([^\&]*)\&.*$
As #starkeen mentioned in comments, you got to check against the query string. This can be done using RewriteCond %{QUERY_STRING}
So if index.php is in the root folder:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^\/index\.php$
RewriteCond %{QUERY_STRING} ^[^\:]*\:([^\&]*)\&.*$
RewriteRule ^(.*)$ http://example.com/%1 [R=301,L]
Here's another example. This one is for a sub folder:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^\/pages\/index\.php$
RewriteCond %{QUERY_STRING} ^[^\:]*\:([^\&]*)\&.*$
RewriteRule ^(.*)$ /pages/%1? [R=301,L]
Also, notice the ? at the end of the url /pages/%1?, this prevents from re-attaching the query string.
Another thing, captured groups will be set to variables %{number} since set in the RewriteCond.
BTW, depending on your server's configuration, you may need to add the NE flag, like [NE,L,R=301] Plus test whether it is necessary to double escape the literal characters.
what is about direct approach. Skip all till semicolon, mach string till & and replace all with first much
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} [^:]+:([\w-]+[^&]).*
RewriteRule .*$ \/%1? [R=301,L]
</IfModule>

Apache Replace two connected characters to one in url

With apache in the htaccess I would like to replace all periods in the url only when there is an underscore after it.
I want example.com?index.php/blog/low_vs._high to redirect to
example.com?index.php/blog/low_vs_high
Can someone tell me how to do this?
Here is what I have, not sure where to go from here or how to properly debug. Thanks.
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/(.*)\._(.*)$
RewriteRule ^(.*)\.(.*)$ /$1$2 [L,R=301]
You can use this rule:
# execute when there are multiple occurrences of ._
RewriteCond %{REQUEST_URI} ^/(.*)\.(_.*\._.*)$
RewriteRule ^ /%1%2 [L]
# execute when there is only one occurrence of ._
RewriteCond %{REQUEST_URI} ^/(.*)\.(_.*)$
RewriteRule ^ /%1%2 [L,NE,R=301]

Removing additional trailing backslash with .htacess – domain.com/page//

I have content that can display with a double-slash:
domain.com/folder/name//
Obviously this is not ideal.
I want to create a .htaccess 301 rewrite that removes the additional trailing slash:
domain.com/folder/name/
I came-up with:
RewriteRule /(.*)/(.*)// /$1/$2/ [R=301,L]
Though no-dice.
You can't match // in RewriteRule since Apache strips it to single there.
Use RewriteCond instead:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/+(.*?)/+(/.*)$
RewriteRule ^ /%1%2 [R=302,L,NE]