Force trailing slash if the URL exists - apache

I need some help to a particular redirect in htaccess. It's not a simple "force trailing slash".
So my problem is to redirect all URLs that don't have a trailing slash to a trailing slash. I accomplish this with this mod_rewrite rule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteCond %{REQUEST_FILENAME} !\.(gif|jpg|png|jpeg|css|js|xml|php)$ [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1/ [R=301,L]
but there is a big problem doing this: if i fire for an URL that doesn't exists and doesn't have a trailing slash, Apache fires a 404 error, but for the URL that doesn't exists WITH TRAILING SLASH. So initially is redirected 301, then 404. This seems to make no sense.
How should I fix this?

Test existence first (with [OR]) and not non-existence:
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME} !\.
RewriteRule !/$ %{REQUEST_URI}/ [NE,R=301,L]

Related

Force trailing slash and 301 redirect in existing RewriteRule

I have a rewrite rule that shows the contents of a directory. For example, if I go to https://www.example.com/bob/, it will show the contents of the file https://www.example.com/profile/index.php?username=bob
Here is the code:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([\w-]+)/$ profile/index.php?username=$1 [QSA,L]
But how can I 301 redirect https://www.example.com/bob to https://www.example.com/bob/ (force trailing slash)?
You can place this rule before above rule to force a trailing slash:
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301,NE]

Redirect to index.php and remove trailing slash .htaccess

There appears to be many questions like this here but can't find an answer that fits my current code:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ public/index.php [QSA,L]
This redirects everything to public/index.php which works fine but I want to get rid of the trailing slash so that example.com/foo/ becomes example.com/foo
You can insert a trailing slash removal code before your current rule:
RewriteEngine On
## Unless directory, remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^(.+)/+$
RewriteRule ^ %1 [R=301,NE,L]
## forward all requests to public/index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ public/index.php [L]

.htaccess redirect /abc/def/ to /abc/def but not URLs starting with /xxx/yyy/?

I have this in .htaccess to redirect /abc/def/ to /abc/def, removing trailing slash:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
Which works well. Now I want to exclude URLs starting with /xxx/yyy/ to NOT be redirected by the above rule, e.g. /xxx/yyy/12345/ which need to stay as it is without being redirected to /xxx/yyy/12345, retaining trailing slash.
So I have:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/xxx/yyy/
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
But it doesn't work as /xxx/yyy/12345/ is still being redirected to /xxx/yyy/12345. What am I doing wrong here?
Use THE_REQUEST variable instead of REQUEST_URI as REQUEST_URI may change due to execution of other rules:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} !\s/+xxx/yyy/ [NC]
RewriteCond %{REQUEST_URI} ^(.+)/$
RewriteRule ^ %1 [L,R=301,NE]
Make sure to use a new browser for testing.
It seems it's because I have this in a .htaccess:
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule ^ index.php [L]
RewriteRule ^(.*)$ public/$1 [L]
In one of the upper directory. So what I have to use is this:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/public/xxx/yyy/
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
Adding /public/ before /xxx/yyy/ though the public URL is actually /xxx/yyy/.

Vanity URLs without trailing slashes on Apache

The code below rewrites all URLs in the /profiles/ directory on our site from example.com/profiles/name/ to example.com/name/, but we'd also like to remove the trailing slashes to further simplify the resulting URLs to the prettier example.com/name -- just like on modern social media.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /profiles/$1 [NC,L]
How can this be done (and done safely)? We have seen several solutions on Stumble Upon that if combined possibly could work, but all profiles on our site currently have their own physical directories rather than being assembled on the fly by a script.
Update: #jon-lin offered a solution to a similar situation at How to access directory's index.php without a trailing slash AND not get 301 redirect -- but we didn't figure out how to apply it to ours (described above).
You could try doing
RewriteRule ^(.*)/+$ $1 [R=301,L]
Which should work for any url
You need to disable directory slash
Try :
DirectorySlash Off
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /profiles/$1 [NC,L]
Use the following redirection:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /(.+)/+$
RewriteRule ^ /%1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /profiles/$0 [NC,L]
By adding part of the code suggested by #jon-lin at How to access directory's index.php without a trailing slash AND not get 301 redirect (internally rewriting the trailing slash back in), we actually made this work:
# Vanity URLs
DirectorySlash Off
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /profiles/$1 [NC,L]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*[^/])$ /$1/
The profile for Gucci on FASHION NET (located at /profiles/gucci/) can now be accessed at https://www.fashion.net/gucci -- with no trailing slash! Thank you, #jon-lin!!!!

htaccess, append a forward slash, then remove and process without altering the URL

I would like to rewrite all urls from say, www.example.com to www.example.com/
I have a rule that adds the forward slash:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*[^/])$ /$1/ [L,R=301]
I would like to create another rule. It's purpose is to check if a trailing slash is present. If so, it then removes it for processing without altering the URL shown in the browser.
Can this be done?
You can use these 2 rules for that:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{THE_REQUEST} \s/+(.*?)[^/][?\s]
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+?)/$ /$1 [L]