.htaccess extensionless url and 301 redirect loop - apache

I have spent count-less hours trying to develop a good .htaccess to offer extensionless urls for SEO purposes. Almost every modern website I see has extensionless URL's and being a fairly new site I want to take this approach.
I have been able to successfully convert the site, using .htaccess, to extensionless. For example:
example.com/page.php will become example.com/page1 in the URL
HOWEVER, existing pages that are the same location (such as contact.php page) will do a LOOP when doing a 301 redirect. So, for example, so that a search engine doesn't think /contact.php and /contact are two different pages, the existing indexed /contact.php has a 301 redirect to /contact
However, the /contact url pulls its data from /contact.php behind the scenes and .htaccess knows this and then wants to apply the 301 redirect again to the behind the scenes /contact.php to /contact causing a loop. I cannot figure out how to stop this.
Bottom line is that I want a 301 redirect from /contact.php to /contact with /contact in the URL reflecting the contents of /contact.php physical file.
Here is my .htaccess to works well except for pages that have 301 redirects.
I'm also interested in any other issues you may see in my .htaccess :)
.htaccess
Options -MultiViews
Options +FollowSymLinks
RewriteEngine on
RewriteBase /
## 301 Redirects
# 301 Redirect 1
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^contact\.php$ /contact? [R=301,NE,NC,L]
## Exclude appropriate directories from rewrite rules ^(blogsphere)
RewriteRule ^(blogsphere) - [L]
## Unless directory, remove trailing slash
# If requested URL ending with slash does not resolve to an existing directory
RewriteCond %{REQUEST_FILENAME} !-d
# Externally redirect to remove trailing slash
RewriteRule ^(.+)/$ $1 [QSA,L]
## Redirect external .php requests to extensionless url
# Any type of POST/GET should be a condition so that it doesnt rewrite without that data (end fileames in submissionscript)
RewriteCond %{REQUEST_URI} !^/([a-z-]+)\-(submissionscript)(.*)$
#Request has to end in .php
RewriteCond %{THE_REQUEST} ^(.+)\.php([#?][^\ ]*)?\ HTTP/
RewriteRule ^(.+)\.php$ $1$2 [QSA,L]
## If it is not a directory then internal resolve request to end with .php for extensionless php urls (/page will internally resolve to /page.php)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^((?!(\.|\.php)).)*$ $0.php [QSA,L]

Have it like this:
Options -MultiViews
Options +FollowSymLinks
RewriteEngine on
RewriteBase /
# skip blogsphere directory for rewrite
RewriteRule ^(blogsphere) - [L]
## Unless directory, remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} \s(.+?)/+[?\s]
RewriteRule ^(.+?)/$ $1 [R=301,L]
# remove .php extension from URL - external redirect
RewriteCond %{REQUEST_URI} !^/([a-z-]+)-(submissionscript)(.*)$
RewriteCond %{THE_REQUEST} \s/+(?:index)?(.*?)\.php[\s?] [NC]
RewriteRule ^ %1 [R=301,L,NE]
# internally rewrite a file to file.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]

Related

.htaccess 301 redirect with exclusion does not work

I try to use a simple 301 redirect
from domain1.com/folder/ to domain2.com/
but excluding domain1.com/folder/subfolder
I use the following code in .htaccess:
RedirectMatch 301 ^/folder/((?!subfolder).*)$ https://domain2.com/$1
but it simply redirects all the requests, including the requests to subfolder.
Please, help to fix the line to make it work as described. Thank you!
here is the complete code of .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /folder/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /folder/index.php [L]
</IfModule>
RedirectMatch 301 ^/folder/((?!subfolder).*)$ https://domain2.com/$1
Try it like this using mod_rewrite instead:
(NB: This assumes the .htaccess file is located in the document root.)
# /.htaccess
# Redirect all direct requests, except "subfolder"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $1 !^subfolder($|/)
RewriteRule ^folder/(.*) https://domain2.com/$1 [R=301,L]
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /folder/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /folder/index.php [L]
</IfModule>
It is important that the redirect goes before the rewrite to your front-controller.
You will need to ensure your browser cache is cleared before testing and test with a 302 (temporary) redirect to avoid potential caching issues.
UPDATE:
Yes, /folder has it's own .htaccess (this is the file I am working at all this time). Yes, /folder is where Wordpress is installed.
In that case you would need to change the above redirect to read as follows (it won't do anything otherwise):
# /folder/.htaccess
# Redirect all direct requests, except "subfolder"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $1 !^subfolder($|/)
RewriteRule (.*) https://domain2.com/$1 [R=301,L]
Basically, you need to remove folder/ from the start of the regex that matches the URL-path. The URL-path that the RewriteRule pattern matches against is relative to the directory that contains the .htaccess file.
The addition of the check against the REDIRECT_STATUS env var is to ensure that rewritten requests to the WP front-controller (when subfolder is requested) are not redirected.
You can also "simplify" the WordPress directives that follow (although if these are enclosed in # BEGIN WordPress / # END WordPress comment markers then you should leave the directives as they are since they are maintained by WordPress). For example:
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
The RewriteBase directive is not required. And neither is the <IfModule> wrapper. (But as I said above, only change this if you are hand-coding the .htaccess and not letting WordPress maintain it.)

SEO URL and Rewrite Rule force on one domain

I have a rewrite rule to force user to go from example.com to www.example.com. This is for SEO reasons so that I have no duplicated websites and content on my Google results.
# BEGIN Spark
AddDefaultCharset UTF-8
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule (.*) https://www.example.com/$1 [R=301,L]
</IfModule>
<IfModule mod_deflate.c>
<FilesMatch "\.(html|php|txt|xml|js|css|ttf|otf|ico|json|svg|)$">
SetOutputFilter DEFLATE
</FilesMatch>
</IfModule>
# END Spark
My question. If now people post a link example.com/news they always will redirect to the frontpage like www.example.com. How can I manage that they still can use and post short URLs like example.com/news1 or example.com/news2 and will redirect to www.example.com/news1 or www.example.com/news2 respectively.
You've put the rule in the wrong place. It needs to go before the internal rewrite (to the front-controller: index.php). eg. at the top of the file, not at the end.
By placing it last it will only correctly redirect physical directories (which includes the homepage) and static resources (images, CSS, JS, etc.). All other "short URLs" that are routed through the front-controller will be redirected to index.php and you'll see the "frontpage".
And... to avoid a double redirect when requesting example.com with a URL that contains a trailing slash then include an absolute URL in the trailing slash removal rule and include your non-www to www rule immediately after that.
For example:
RewriteEngine On
# Remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ https://www.example.com/$1 [L,R=301]
# Redirect non-www to www
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule (.*) https://www.example.com/$1 [R=301,L]
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
# Front-controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
You will need to clear the browser cache before testing since the erroneous 301 (permanent) redirects will have been cached by the browser. (Test with 302 - temporary - redirects to avoid caching issues.)
Aside: An additional concern is that these directives are inside a # BEGIN Spark ... # END Spark code block - which makes it look as if these directives are perhaps maintained by some automated process? In which case, they might be overwritten?

the right way redirect url using .htaccess

what is the right way to redirect page using .htaccess?
for ex i want to redirect myweb.com/dorama/901110204/todome-no-kiss--paralel to myweb.com/dorama/1101071510/todome-no-kiss--parallel
but when i try to access old link, link direct to myweb.com/dorama/1101071510/todome-no-kiss--parallel?cat=dorama&idp=901110204&post=todome-no-kiss--paralel
my full .htaccess file
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
#Redirect Dead Link
Redirect 301 /dorama/901110204/todome-no-kiss--paralel http://www.piratefiles.org/dorama/1101071510/todome-no-kiss--parallel
Redirect 301 /dorama/601181905/life-as-a-girl http://www.piratefiles.org/dorama/1101072233/life-as-a-girl
Redirect 301 /dorama/801130021/todome-no-kiss http://www.piratefiles.org/dorama/1101071405/todome-no-kiss
RewriteRule ^([A-Za-z]+)/([0-9]+)/([\w-]+)/?$ view.php?cat=$1&idp=$2&post=$3&%{QUERY_STRING} [NC,L]
RewriteRule ^category/([\w-]+)/?$ category.php?cat=$1&%{QUERY_STRING} [NC,L]
# To externally redirect /dir/abc.php to /dir/abc
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+(.+?)\.php[\s?] [NC]
RewriteRule ^ /%1 [R=301,L,NE]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [QSA,NC,L]
</IfModule>
ErrorDocument 404 http://www.piratefiles.org/404.php
RewriteRule directives "run" before Redirect ones do. Thus, if you want to force the redirections to run in a particular order, you need to convert them all to Rewrite directives.
Replace the three Redirect directives with:
RewriteRule ^dorama/(\d+)/(todome-no-kiss--paralel|life-as-a-girl|todome-no-kiss)$ http://www.piratefiles.org/$1/$2 [R=301]
Tweak as necessary, but that's the reason it's failing, and a proposed solution.
(Also, standard note here: If you have access to your main server config, .htaccess files should be avoided whenever possible. .htaccess files are for people that don't have access to the main config.)

Conflict with Redirect to index.php and folder

I rent an Apache web server. The folder architecture is like this:
root
src
template
less
www
css
js
jpeg
The web server serves only the www directory. And I use a .htaccess to redirect to HTTPS, remove the www. and redirect all request to the index.php except if a file exist in the www folder.
RewriteEngine On
# Redirect to HTTPS
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Remove WWW
RewriteCond %{HTTP_HOST} ^www\.domaine\.com$ [NC]
RewriteRule (.*) https://domaine.com%{REQUEST_URI} [R=301,QSA,NC,L]
# Redirect all route to index.php
# Except the files
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) /index.php?$1/ [NC,L,QSA]
The problem is the when I request a folder name. The folder is redirected twice to index.php!
Example: When I request http://domaine.com/css, the request is redirected to https://domaine.com/index.php?css/?css/.
How to solve the double redirect?
You need to either exclude directories from your last rule OR add a trailing slash using a redirect rule to directories to avoid this behavior
Otherwise last rule rewrites directories without slash to /index.php and due to missing slash mod_dir module redirects by appending a trailing slash.
Also you should move www rule before http->https rule to avoid multiple 301 redirects for a request that is http://www.domaine.com/.
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
Options -Indexes
RewriteEngine On
# Remove WWW and use https
RewriteCond %{HTTP_HOST} ^www\.(domaine\.com)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,NE,L]
# Redirect to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
# add trailing slash for directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301]
# Redirect all route to index.php
# Except the files
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php?$0/ [NC,L,QSA]
Make sure to clear your browser cache before you test this change.
I resolv my problem. I remove the automatic slash at the end with the DirectorySlash directive. Now that's work and all my directories are hidden. Only the file are visible.
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
Options -Indexes
DirectorySlash Off
RewriteEngine On
# Remove WWW and use https
RewriteCond %{HTTP_HOST} ^www\.(domaine\.com)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,NE,L]
# Redirect to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* /index.php?$0 [NC,L,QSA]

trailing slashes in 301 redirect

I've tried to look through the multiple mod_rewrite questions, so I apologize if this is a duplicate.
I'm trying set it so that if you go to domain.com/about.php it removes .php and if you go to domain.com/about it simply remains like that.
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /$1.php [L,QSA]
RewriteRule ^(.*)/$ /$1 [L,R=301]
So, right now if you go to domain.com/about it displays the page, but if you go to domain.com/about.php it doesn't remove the extension.
Additionally, I have 301 redirects
redirect 301 /our-clients http://www.domain.com/about-ourclients
That works perfect, but if the user goes to domain.com/our-clients/ with the trailing slash, they are directed to about-ourclients.php
Any advice on how to rewrite my rules?
This should do the job:
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
# remove .php ONLY if requested directly
RewriteCond %{THE_REQUEST} (\.php\sHTTP/1)
RewriteRule ^(.+)\.php$ /$1 [R=301,L,QSA]
# remove trailing slash ONLY if it is not an existing folder
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# rewrite to FILENAME.php if such file does exist and is not a folder
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ /$1.php [L,QSA]
It will redirect all direct requests to php files: /something.php will be redirected to /something
Will remove the trailing slash IF requested resource is not directory. So if you requesting /home/ and you do have such folder, then it will NOT be redirected to /home.
Will internally rewrite requests to the same named PHP file IF it does exist. If you are requesting /about and you have /about.php then it will do rewrite; If you have no /about.php then nothing happens (well, at least not on these rules -- if you have more rules then such request can be matched later .. or 404 error page will be shown).
If you are requesting /about, you have /about.php and you also have /about folder, then request will go into folder. If you do not want this to happen ( /about should always be rewritten to /about.php) then you need to remove RewriteCond %{REQUEST_FILENAME} !-d from last block. But since you have exactly the same condition in your current .htaccess then I assume it is desired behaviour.