Search code examples
.htaccesshttp-redirectmod-rewritefriendly-url

.htaccess file adding trailing slash to URL


I have a blog, the pages are suppose to redirect to 'pretty URLS' like the following:

https://www.example.org/blog-post-title

I am using this code:

RewriteEngine On

# SSL
RewriteCond %{HTTPS} off 
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# GENERAL
RewriteRule ^([a-z-0-9]+)$ post.php?blog_slug=$1
RewriteRule ^top-picks$ top.php
RewriteRule ^privacy-policy$ privacy.php
RewriteRule ^sitemap$ sitemap.php
RewriteRule ^([a-z-A-Z-0-9]{8})$ link.php?redirect=$1

I have used it many times before (in one variation or another) - but it is adding a trailing slash and not finding the page everytime like so:

https://www.example.org/blog-post-title/

Anyone have any idea what I am doing wrong?? The other pages work just fine - the code on the post.php page is calling the $_GET variable correctly, I can't seem to get rid of the trailing slash and it doesn't happen on any of my other sites?!


Solution

  • There is nothing in your .htaccess file that appends a trailing slash. However, Apache (mod_dir) will append the trailing slash (with a 301 redirect) if /blog-post-title happens to exist as a physical directory on the filesystem. (You also state that "the other pages work just fine".)

    In this case, attempting to remove the trailing slash (without first setting DirectorySlash Off) will result in a redirect loop.

    If this is the case then you need to remove/rename the physical filesystem directory.

    But note that this "permanent" redirect will have been cached persistently by the browser and any intermediary caches, so you will need to make sure any caches are cleared after resolving the cause of the redirect.

    RewriteRule ^([a-z-0-9]+)$ post.php?blog_slug=$1
    RewriteRule ^top-picks$ top.php
    RewriteRule ^privacy-policy$ privacy.php
    RewriteRule ^sitemap$ sitemap.php
    RewriteRule ^([a-z-A-Z-0-9]{8})$ link.php?redirect=$1
    

    However, there are other errors with your rules that will prevent them from working as intended...

    1. [a-z-0-9] - Hyphens (-) in a regex character class are a special meta character that indicates a range of characters, eg. a-z. To match a literal hyphen it should be at the start or end of the character class OR backslash-escaped. You have an unescaped hyphen in the middle of the character class. As it happens this does actually match a literal hyphen in this case, but it is arguably ambiguous (and you run the risk of inadvertently matching a range of characters). However, in the last rule you have two unescaped hyphens (you have interspersed every character with a hyphen), which makes me wonder what the true intention is here? Again, as it happens these two unescaped hyphens match a literal hyphen (although I have doubts whether that is intentional)?

    2. Coupled with point #1, these rules are in the wrong order. The first rule will match top-picks, privacy-policy and sitemap, rewriting all requests to post.php. Consequently, the last rule (that rewrites to link.php) will never be processed unless the requested URL contains an uppercase letter. The last rule should be before the first rule (but the first "generic" rule should be last).

    3. You are missing the L flag on all the rewrites. Not that this should cause a problem in this particular instance (since the rewritten URL contains a dot and none of the patterns match a dot), it could cause an issue in the future and the very least it results in additional (unnecessary) processing.

    Your rules should be rewritten like this instead:

    Options -MultiViews
    
    RewriteEngine On
    
    # SSL
    RewriteCond %{HTTPS} off 
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    
    # GENERAL
    RewriteRule ^top-picks$ top.php [L]
    RewriteRule ^privacy-policy$ privacy.php [L]
    RewriteRule ^sitemap$ sitemap.php [L]
    RewriteRule ^([a-zA-Z0-9]{8})$ link.php?redirect=$1 [L]
    RewriteRule ^([a-z0-9-]+)$ post.php?blog_slug=$1 [L]
    

    I've assumed that 8-character URLs that should be passed to link.php do not contain hyphens.

    I've also disabled MultiViews (it may be disabled anyway - but to be sure) since you are also dealing with extensionless URLs (eg. sitemap to sitemap.php). If MultiViews is enabled then this will conflict with your mod_rewrite rules.