.htaccess - remove everything after third slash in path - apache

On my website, I only use 3 slashes in my URL path:
https://example.com/this/isatest/
Right now I use .htaccess which makes it possible (as a side effect) to add as many stuff on the URL as you like:
https://example.com/this/isatest/hipperdihopperdus/pizza/bacon/with/cheese
I'd like to automatically remove everything after "isatest" while keeping the trailing slash using .htaccess.
This is what my .htaccess currently looks like:
Options -Indexes
Options +FollowSymLinks
RewriteEngine on
# 301 Redirect all requests that don't contain a dot or trailing slash to
# include a trailing slash
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !\.
RewriteRule ^(.*) %{REQUEST_URI}/ [R=301,L]
RewriteCond %{THE_REQUEST} /index\.html [NC]
RewriteRule ^index\.html$ /? [R=301,L,NC]
RewriteRule ^listen/$ /console/ [NC,L]
# Rewrites urls in the form of /parent/child/
# but only rewrites if the requested URL is not a file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [L,QSA]
How can I achieve this?

As your first rule, after the RewriteEngine directive, you can do something like the following:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]
This checks if there is anything else (the dot) after two path segments and a slash, and redirects to removed "anything else".
Note that this is a 302 (temporary) redirect. Only change this to a 301 (permanent) redirect - if that is the intention - once you have confirmed that it works OK. This is to avoid the browser caching erroneous redirects whilst testing.
UPDATE: It may be more efficient to simply avoid redirecting files that end in a recognised file extension. Or perhaps exclude known directory location(s) of your static resources. For example:
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|png|gif)$ [NC]
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]
OR,
RewriteCond %{REQUEST_URI} !^/static-resources/
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]

You can add this rule just below RewriteEngine On line:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+/[^/]+/).+$ /$1 [R=301,L,NE]

Related

.htaccess redirect based on folder

I need help with .htaccess Rewrite rules.
I have a API which can be accessed over http://api.my.domain/products/all which is working fine and is returning result.
I would like to redirect users coming to http://api.my.domain/admin to admin folder.But it is not working with current rules.
I have added this to .htaccess but it is not working correctly for admin folder.
RewriteEngine On
RewriteCond %{Request_Filename} !-F
RewriteCond %{Request_Filename} !-d
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^admin admin/index.php [QSD,L]
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^ public/index.php [QSD,L]
This is the result I get when I enter http://api.my.domain/admin and is breaking all my php redirects:
http://api.drezga.hr/admin/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/admin/admin/checklogin.php
Can someone, please, tell me what I'm doing wrong? I have spent hours and I can't see it.
Aside: If /admin is a physical directory then you should be requesting /admin/ (with a trailing slash) to begin with, otherwise Apache/mod_dir will issue a 301 redirect to append the trailing slash.
RewriteCond %{Request_Filename} !-F
RewriteCond %{Request_Filename} !-d
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^admin admin/index.php [QSD,L]
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^ public/index.php [QSD,L]
The first two conditions (RewriteCond directives) are being applied incorrectly to the first rule only. They need to apply to the last rule (the rewrite to public/index.php) then the rewrite to admin/index.php is not necessary (this should be handled by the DirectoryIndex).
There's no need for the QSD flag since you are checking that the query string is already empty - there is no query string to discard!
You should probably be using the -f operator on the condition, not -F (which uses subrequests and is consequently less efficient).
Try the following instead:
DirectoryIndex index.php
RewriteEngine On
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Optimisation (prevent additional filesystem check)
RewriteRule ^public/index\.php$ - [L]
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . public/index.php [L]
RewriteRule ^$ public/index.php [L]
The RewriteCond %{REQUEST_FILENAME} !-d directive prevents requests for /admin/ being passed to public/index.php.
The additional RewriteRule at the end is to rewrite requests for the root directory, which would otherwise be omitted because of the condition mentioned above. This could be avoided by extending the DirectoryIndex directive instead, although this could change the behaviour if you have other directories that need to be accessible (or should not be routed to public/index.php). For example:
DirectoryIndex index.php /public/index.php

Add trailing slash to url using .htaccess

I would like to add trailing slash for deep level of my urls
So let's say i have this url
mysite.com/work
when user access that url, i want to be redirected to:
mysite.com/work/ (this i want to happen)
But i want this only deep levels, not for .html pages
mysite.com/testing.html/ (i don't want this to happen)
I have this .htaccess rule, but this add trailing slash to my .html pages also. i don't want that.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=301]
Any help?
You can use this rule for adding trailing slash only for non-files:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{THE_REQUEST} \s/+(.*?)[^/][?\s]
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301,NE]

Cannot make htaccess redirect www to non-www

The 3 comments in the code explain fairly accurate what I want to achieve.
<IfModule mod_rewrite.c>
RewriteEngine On
# Change secretdiary.org/index.php?url=URL to secretdiary.org/URL on the browser's url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
# Redirect http://www.secretdiary.org/ to http://secretdiary.org/
RewriteCond %{HTTP_HOST} !^secretdiary.org$ [NC]
RewriteRule ^(.*)$ http://secretdiary.org/$1 [L,R=301]
# Add trailing slash / if there's none
RewriteCond %{REQUEST_URI} !(/$|\.)
RewriteRule (.*) %{REQUEST_URI}/ [R=301,L]
</IfModule>
However, I am finding some problems and I think they come from putting the conditions together. When I enter www.secretdiary.org/about , it gets (showing it in the browser) to secretdiary.org/index.php?url=about, deleting the www but ignoring the first rule. Switching the order did not help at all nor messing with RewriteBase. However, if I enter normally without the www, the uri is shown normally, secretdiary.org/about, without any rewriting. Why is this and how can I fix it?
Besides, I've followed this answer and this other attempting to add automatically a trailing slash to the uri if missing. I could achieved it with PHP ( if (substr($_GET['url'], -1) != "/") header("Location: " . htmlspecialchars($_GET['url']) . '/');, but now it bothers me that I cannot achieve it with .htaccess, so if you could also spot where's the problem here it'd be very helpful.
Try this .htaccess code :
RewriteEngine On
# Change secretdiary.org/index.php?url=URL to secretdiary.org/URL on the browser's url
RewriteCond %{HTTP_HOST} ^secretdiary.org$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L]
# Redirect http://www.secretdiary.org/ to http://secretdiary.org/
RewriteCond %{HTTP_HOST} !^secretdiary.org$ [NC]
RewriteRule ^(.*)$ http://secretdiary.org/$1 [R=301]
# Add trailing slash / if there's none
RewriteRule ^([^/]*)[^/]$ $1/ [R=301,L]
I'm not sure for the last rule.
The main problem I faced was with Firefox storing the 301 redirect, which made the changes in .htaccess "not work". I deleted the cache and now it's working perfectly, although I made the trailing slash to be added with PHP to avoid headaches.
.htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
# For some shady reason, this redirect should be first.
# Redirect http://www.secretdiary.org/ to http://secretdiary.org/
RewriteCond %{HTTP_HOST} !^secretdiary.org$ [NC]
RewriteRule ^(.*)$ http://secretdiary.org/$1 [L,R=301]
# Change secretdiary.org/index.php?url=URL to secretdiary.org/URL on the browser's url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
</IfModule>
index.php:
<?php
// Redirect if there's no trailing slash
if (!empty($_GET['url']) && substr($_GET['url'], -1) != "/")
{
header ('HTTP/1.1 301 Moved Permanently');
header ("Location: http://secretdiary.org/" . htmlspecialchars($_GET['url']) . "/");
}
// The rest of the php

Non www to www redirect doesn't removes trailing backslash

I'm having a bit of problem with Apache redirect.
While bellow rules work for any page on site, mydomain.com will get redirected to mydomain.com//, which ignores trailing slash removal rule.
Also is it efficient to use multiple rules such as this or should I try to combine them or chain them somehow together in order to avoid multiple redirects for single url?
Thanks
#Turn on options for url rewriting
Options +FollowSymlinks
RewriteEngine on
#lovercase all urls
RewriteMap lc int:tolower
RewriteCond %{REQUEST_URI} [A-Z]
RewriteCond %{REQUEST_URI} ^/fonts/.*
RewriteCond %{REQUEST_URI} ^/css/.*
RewriteCond %{REQUEST_URI} ^/js/.*
RewriteRule (.*) ${lc:$1} [R=301,L]
#redirect all requests made to http:// to http://www.
RewriteCond %{HTTP_HOST} ^mydomain\.com$ [NC]
RewriteRule ^(.*)$ http://www.mydomain.com/$1 [R=301,L]
#removes trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} !^\.localhost$ [NC]
RewriteRule ^(.+)/$ http://%{HTTP_HOST}$1 [R=301,L]
The reason the mydomain.com gets redirected to www.mydomain.com// is because you have an extra "/" in your rewrite rule target:
RewriteRule ^(.*)$ http://www.mydomain.com/$1 [R=301,L]
^----here
When you have rules in your server/vhost config, the leading slash isn't removed so that gets match and used as a backreference, so mydomain.com is / which matches ^(.*)$ and the target becomes http://www.mydomain.com//. So you can either remove the slash in the target or add one to the regex:
RewriteRule ^(.*)$ http://www.mydomain.com$1 [R=301,L]
or
RewriteRule ^/(.*)$ http://www.mydomain.com/$1 [R=301,L]
Your other rule you have:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} !^\.localhost$ [NC]
RewriteRule ^(.+)/$ http://%{HTTP_HOST}$1 [R=301,L]
are fine. They are for removing trailing slashes when there is something between them, e.g. /something/, because of the (.+). It wouldn't match // anyways because that inherently gets turned into just /. You just need to prevent redirecting to http://www.mydomain.com//

Remove trailing slash if not a directory with apache

I have the following rewrite rules:
#remove the www.
RewriteCond %{HTTP_HOST} ^www.website.co.uk$ [NC]
RewriteRule ^(.*)$ http://local.website.co.uk/$1 [R=301,L]
#this removes php extention
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
# stops you accessing url with.php
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^.?\ ]+)\.php
RewriteRule ^([^.]+)\.php(/.+)?$ /$1%{PATH_INFO} [R=301]
I want to add in a rule that removes the trailing slash if someone tries to access site with one.
eg
website.co.uk/cheese/ should redirect to /cheese
as you can see I have a rule that redirects ursl with the .php extention, not sure where to begin.
I do have directory in the root folder which I do not wish to remove the trailing url, but I can add a ignore rule for those.
Cheers
Make the change below to your .htaccess file
RewriteEngine on
RewriteBase /
#existing rule
#remove the www.
RewriteCond %{HTTP_HOST} ^www.website.co.uk$ [NC]
RewriteRule ^(.*)$ http://local.website.co.uk/$1 [R=301,L]
#new Rule
#if its not a directory
RewriteCond %{REQUEST_FILENAME} !-d
#and it has a trailing slash then redirect to URL without slash
RewriteRule ^(.+)/$ /$1 [L,R=301]
# rest of your existing rules go here