How to search and replace url using .htaccess (regex) - regex

Below is the code from my .htaccess file:
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php74” package as the default “PHP” programming language.
<IfModule mime_module>
AddHandler application/x-httpd-ea-php74 .php .php7 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit
Below is what I want to search and replace:
https://example.com/video-17i8mp51/27628401/0/ok-ask-me-right
to
https://example.com/video-17i8mp51/ok-ask-me-right
https://example.com/search/full+movie?top&id=57448561
to
https://example.com/search/full+movie
This URL is in over 10k of my site content's
https://anothersiteurl.com/search/full+movie
to
https://mysiteurl.com/search/full+movie

I'm assuming these are static one-to-one redirects, as seemingly confirmed in comments.
Both the following rules should go after the first rule (the canonical HTTP to HTTPS and www to non-www redirect) and before the front-controller pattern.
https://example.com/video-17i8mp51/27628401/0/ok-ask-me-right
to
https://example.com/video-17i8mp51/ok-ask-me-right
RewriteRule ^(video-17i8mp51)/27628401/0/(ok-ask-me-right)$ /$1/$2 [R=302,L]
Where the $1 and $2 backreferences contain the captured subgroups from the RewriteRule pattern, ie. video-17i8mp51 and ok-ask-me-right respectively. This simply saves repetition in the RewriteRule substitution string.
https://example.com/search/full+movie?top&id=57448561
to
https://example.com/search/full+movie
RewriteCond %{QUERY_STRING} ^top&id=57448561$
RewriteRule ^search/full\+movie$ /$0 [QSD,R=302,L]
The $0 backreference contains the full match of the RewriteRule pattern (ie. search/full_movie). Note that the literal + needs to be backslash escaped in the regex to negate it's special meaning in the regex.
The QSD (Query String Discard) flag removes the original query string from the redirect response.
You should not repeat the RewriteEngine directive.
Note that these are currently 302 (temporary) redirects. If these are intended to be permanent then change to 301 but only after you have tested that they work as intended, to avoid potential caching issues.
This url is in over 10k of my site content's
https://anothersiteurl.com/search/full+movie
to
https://mysiteurl.com/search/full+movie
This is not something you should be trying to do with .htaccess. If this URL appears in the site "content" then you need to modify the content of your pages before sending the response.
(Technically, you can use mod_substitute to do this - to modify the response body - but really that would be a last resort.)
Aside: The RewriteBase directive is not being used here and can therefore be removed.
Summary
Your resulting .htaccess file would then look like this:
RewriteEngine On
# Canonical redirect (HTTP to HTTPS and www to non-www)
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
# Point#1
RewriteRule ^(video-17i8mp51)/27628401/0/(ok-ask-me-right)$ /$1/$2 [R=302,L]
# Point#2
RewriteCond %{QUERY_STRING} ^top&id=57448561$
RewriteRule ^search/full\+movie$ /$0 [QSD,R=302,L]
# Front-controller pattern
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php74” package as the default “PHP” programming language.
<IfModule mime_module>
AddHandler application/x-httpd-ea-php74 .php .php7 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit

I was able to meet all three of your criteria with the following rules:
RewriteEngine On
RewriteBase /
# First request:
# Convert https://example.com/video-17i8mp51/27628401/0/ok-ask-me-right to
# https://example.com/video-17i8mp51/ok-ask-me-right
RewriteRule ^(video-[^/]+)/.+/(.+)/?$ $1/$2 [L]
# Second request:
# Convert https://example.com/search/full+movie?top&id=57448561 to
# https://example.com/search/full+movie
RewriteRule ^ %{REQUEST_URI}?
# Third request:
# Convert https://anothersiteurl.com/search/full+movie to
# https://mysiteurl.com/search/full+movie
RewriteRule ^(.*)$ https://mysiteurl.com/$1 [R=301,L]
You can see them in action here.

Related

htaccess language redirect when any language set

I have a website example.com, the default locale is English, I want to redirected to example.com/en If is not set a language.
All request without language argument should redirect to default language
sample :
example.com/blogpost/thisisapost
should redirect to :
example.com/en/blogpost/thisisapost
or
example.com/one/tow/three/etc
should redirect to :
example.com/en/one/tow/three/etc
The website Developed with Laravel.
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
You can create the redirect like this:
RewriteEngine On
rewriteRule ^/?(^((?!nl|en).)*$) https://example.com/en/$1 [R=301,L]
en and nl will not be matched now, but everything else will
You can see the result here
You can insert this rule just below RewriteEngine On line to make it work:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule !^[a-z]{2}/ /en%{REQUEST_URI} [L,NE,R=301]
Explanation:
!^[a-z]{2}/ is negative condition that succeeds when URI doesn't start with 2 lowercase letters followed by /
/en%{REQUEST_URI} prepends REQUEST_URI with /en so that we get /en as default language in URLs
RewriteCond %{ENV:REDIRECT_STATUS} ^$ is a condition that checks for empty value of REDIRECT_STATUS variable to make sure this rule doesn't fire after an internal rewrite.

Redirect does not occur if trailing slash exists

I have the following lines in my .htaccess file in a directory called blog.
RewriteCond %{HTTPS} on
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Different things happen when I do the following:
https://staging.example.com/blog/ - redirect does not work
https://staging.example.com/blog - redirect does work
When a trailing slash exists my redirect does not work, why is that the case?
Update
This is the blog/.htaccess file.
<IfModule mod_rewrite.c>
RewriteEngine On
# Froce HTTP
RewriteCond %{HTTPS} on
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteBase /blog/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /blog/index.php [L]
</IfModule>
https://staging.example.com/blog/ - redirect does not work
This could be due a presence of blog/.htaccess. If that is true then add this line on top of other rules there as well:
RewriteEngine On
RewriteCond %{HTTPS} on [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} https
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
If you have a catalog with name equal to the redirect "path", it has more priority than your rule.
In your case, if you have a "blog" directory under DocumentRoot, redirecting simply fails.
We need more informaction about your structure and other rules.
But I've not been sleeping for a bunch of nights because of existing directory which prevented my rewriting rules.

Using htaccess to force a trailing slash before the ? with a query string?

I have the following in my htaccess file:
RewriteEngine On
RewriteBase /
# Check to see if the URL points to a valid file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Trailing slash check
RewriteCond %{REQUEST_URI} !(.*)/$
# Add slash if missing & redirect
RewriteRule ^(.*)$ $1/ [L,R=301]
# Check to see if the URL points to a valid file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Send to index.php for clean URLs
RewriteRule ^(.*)$ index.php?/$1 [L]
This does work. It hides index.php, and it adds a trailing slash... except when there is a query string.
This URL:
http://example.com/some-page
gets redirected to:
http://example.com/some-page/
but this URL:
http://example.com/some-page?some-var=foo&some-other-var=bar
does not get redirected. I would like for the above to be sent to:
http://example.com/some-page/?some-var=foo&some-other-var=bar
I've reached the limits of my understanding of redirects with this. If you have a working answer, I would really appreciate a walkthrough of what every line is doing and why it works. Double bonus awesomeness for an explanation of why what I have right now doesn't work when there is a query string involved.
Try adding a [QSA] to the end of the last Redirect rule to preserve the original query string as below
# Send to index.php for clean URLs, preserve original query string
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]
a walkthrough of what every line is doing and why it works.
See my comments below
#turn mod_rewrite engine on.
RewriteEngine On
#set the base for urls here to /
RewriteBase /
### if the is not a request for an existing file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
### and the URI does not end with a /
RewriteCond %{REQUEST_URI} !(.*)/$
### redirect and add the slash.
RewriteRule ^(.*)$ $1/ [L,R=301]
### if the is not a request for an existing file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# rewrite to index.php passing the URI as a path, QSA will preserve the existing query string
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]
I believe that if you change this:
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/ [L,R=301]
to this:
RewriteCond %{REQUEST_URI} !^([^?]*)/($|\?)
RewriteRule ^([^?]*) $1/ [L,R=301]
then it should do what you want.
The changes I made are:
In both rewrite-condition and -rule, I changed (.*) and ^(.*) to ^([^?]*), to ensure that, if there's a query-string, then it is not included in either regex. ([^…] means "any character that is not in …", so [^?] means "any character that is not a question mark".)
In the rewrite-condition, I changed $ to ($|\?), so as to match either end-of-URL or end-of-part-before-the-query-string.
In the rewrite-rule, I dropped the $, since it was no longer needed.

ExpressionEngine mod_rewrite Rule to Redirect URLs with Underscores to Dashes

I'm using ExpressionEngine as my CMS and would like to remove underscores from my site's URLs and replace them with dashes.
For example, I've got a URL that is formatted like this:
http://example.com/index.php/menu/friday-lunch
To remove index.php from the URL, I'm using the following mod_rewrite rule:
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
Which works, since I can just type in: http://example.com/menu/friday-lunch
On the old site I used underscores instead of hyphens for page URIs, so I wrote a mod_rewrite rule to to redirect URIs with underscores to use dashes.
So friday_lunch becomes friday-lunch using the following RewriteRule:
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
This rule works rather well, except that it 301 Redirects to example.com/index.php/menu/friday-lunch instead of example.com/menu/friday-lunch — notice the addition of index.php.
Here's the entire .htaccess I'm currently using:
<IfModule mod_rewrite.c>
RewriteEngine On
# Removes index.php
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
</IfModule>
How can I redirect all of my URLs with underscores to the equivalent with dashes?
Bonus: to make matters worse, URLs that lead to /system, must not be rewritten with a hyphen, e.g.: example.com/system/login_in/.
Here's a complete set of RewriteRules that should do what you need:
<IfModule mod_rewrite.c>
# Enable Apache's RewriteEngine
RewriteEngine On
# Ignore Matching Directories
RewriteRule ^(images|themes|system) - [L,NC]
# Replace Underscores with Dashes
RewriteRule ^([^_]*)_([^_]*)_(.*)$ /$1-$2-$3 [R=301,L]
RewriteRule ^([^_]*)_(.*)$ /$1-$2 [R=301,L]
# Remove index.php from ExpressionEngine URLs
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
To have your mod_rewrite rules ignore the ExpressionEngine system folder and not replace underscores _ with dashes - use the following:
RewriteRule ^(images|themes|system) - [L,NC]
Dissecting the RewriteRule into plain English:
The - flag instructions Apache to do nothing, and to not rewrite the URI
The L flags means this should be last rule; ignore everything following
The NC flag means no-case (so "System" or "SYSTEM" is also matched)
This "ignore" rule is especially important and you may need to add additional directories to exclude depending on your directory structure.
Otherwise, you may end up with images and other files saved with underscores that get replaced with dashes.
Note: If your URLs contain more than three underscores, you'll need to add another RewriteRule above the existing ones for each Word Separator for URL Titles you want to replace:
RewriteRule ^([^_]*)_([^_]*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4-$5 [R=301,L]
RewriteRule ^([^_]*)_([^_]*)_(.*)_(.*)$ /$1-$2-$3-$4 [R=301,L]
You included 'index.php' in your replacement string.
RewriteRule ^(.*)$ index.php/$1 -> RewriteRule ^(.*)$ $1

htaccess: redirect old domain and all pages to a new domain

I know that there is a lot of examples on Stackoverflow but I still miss something.
I'm trying to redirect http://old.domain.com/fr/ to http://brand.new-domain.com/fr/ with the following rules, but that doesn't work:
# Enable Rewrite Engine
RewriteEngine On
RewriteBase /
# Add a trailing slash to paths without an extension
RewriteCond %{REQUEST_METHOD} !=POST
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule ^(.*)$ $1/ [L,R=301]
# Redirect domain
Options +FollowSymLinks
RewriteCond %{HTTP_HOST} ^old.domain.com [OR]
RewriteCond %{HTTP_HOST} ^other-old.domain.com [NC]
RewriteRule ^(.*)$ http://brand.new-domain.com/$1 [r=301,L]
# Remove index.php
# Uses the "exclude method"
# http://expressionengine.com/wiki/Remove_index.php_From_URLs/#Exclude_List_Method
# This method seems to work best for us, you might also use the include method.
# http://expressionengine.com/wiki/Remove_index.php_From_URLs/#Include_List_Method
# Exclude root files
RewriteCond $1 !^(index\.php) [NC]
# Exclude EE folders
RewriteCond $1 !^(assets|ee-admin|images|templates|themes|fr|nl)/ [NC]
# Exclude user created folders
RewriteCond $1 !^(assets|css|img|js|swf|uploads)/ [NC]
# Exlude favico, robots, ipad icon
RewriteCond $1 !^(favicon\.ico|robots\.txt|pple-touch-icon\.png) [NC]
# Remove index.php
RewriteCond %{QUERY_STRING} !^(ACT=.*)$ [NC]
RewriteCond %{QUERY_STRING} !^(URL=.*)$ [NC]
RewriteRule ^(.*)$ /index.php?/$1 [L]
It correctly redirect when I call the root URL, but not when I call a page. What am I doing wrong?
Thanks in advance!
Pv
When writing mod_rewrite rules, the rules get applied in the order that they appear.
To redirect an old domain to a new domain, you'll want that rule to be first in your .htaccess or httpd.conf file — all other rules should appear after it.
If you only want to redirect a certain directory, the following rule will do so, while allowing the rest of the site to function normally:
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirect Only Matching Directories
RewriteCond %{REQUEST_URI} ^/(fr|fr/.*)$
RewriteRule ^(.*)$ http://brand.new-domain.com/fr/$1 [R=301,L]
</IfModule>
If you want to redirect the entire site, the following rule will do so:
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirect Entire Site to New Domain
RewriteCond %{HTTP_HOST} ^old.domain.com$ [OR]
RewriteCond %{HTTP_HOST} ^other-old.domain.com$ [NC]
RewriteRule ^(.*)$ http://brand.new-domain.com/$1 [R=301,L]
</IfModule>
If you care about letting crawlers know your content has moved and want to make the transition as seamless as possible, be sure to keep the 301 Redirect flag in the RewriteRule.
This will ensure that users and search engines are directed to the correct page.
While we're on the subject, as part of the EE 2.2 release, EllisLab now "officially" offers limited technical support for removing index.php from ExpressionEngine URLs.
Simply add or update your code to the following, making sure to consider any rules you may already have in place:
<IfModule mod_rewrite.c>
RewriteEngine On
# Removes index.php
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
# If 404s, "No Input File" or every URL returns the same thing
# make it /index.php?/$1 above (add the question mark)
</IfModule>
Try to use the following ruke as the first one:
# Redirect domain
Options +FollowSymLinks
RewriteCond %{HTTP_HOST} ^old.domain.com [OR]
RewriteCond %{HTTP_HOST} ^other-old.domain.com [NC]
RewriteRule ^(.*)$ http://brand.new-domain.com/$1 [R=301,L]
Also mind the upper case R with is the short form for the lower case redirect.
Have you tried using mod_alias simple redirect instructions (a core module that you have), before trying the hacky-mod-rewrite thing?
I would do a VirtualHost with ServerName old.domain.com and in this VH I would add this rule:
Redirect /fr http://brand.new-domain.com/fr
from doc:
Then any request beginning with URL-Path will return a redirect request to the client at the location of the target URL. Additional path information beyond the matched URL-Path will be appended to the target URL.
So get a separate VirtualHost for brand.new-domain.com (with ServerName brand.new-domain.com) and in this one do not set the Redirect Rule.
If you still want to handle the 2 domains in the same VirtualHost then you'll have to use mod-rewrite as even RedirectMatch cannot check the request domain on the query.