Search code examples
phpapache.htaccessmod-rewrite

htaccess php file first and then folder


I am using the above in my .htaccess file

# BEGIN - Allow Sucuri Services
<IfModule mod_rewrite.c>
    RewriteRule ^sucuri-(.*)\.php$ - [L]
</IfModule>
# END - Allow Sucuri Services

<Files 403.shtml>
order allow,deny
allow from all
</Files>

# Disable MultiViews
Options +FollowSymLinks -MultiViews

RewriteEngine on

# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect non-www to www
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]

# Allow extensionless PHP URLs to work
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]

# Front-controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ ci_index.php?/$1 [L]

The issue that I am facing is whenever I try to open the file https://www.example.com/world-data it opens the folder - https://www.example.com/world-data/ instead of https://www.example.com/world-data.php

How do I prevent the folder being opened instead of the file?


Solution

  • The issue that I am facing is whenever I try to open the file https://www.example.com/world-data it opens the folder - https://www.example.com/world-data/ instead of https://www.example.com/world-data.php

    Generally, you should try to avoid this scenario when constructing extensionless URLs as it creates an ambiguity - only one can be accessible.

    This happens because mod_dir "fixes" the URL when you request a filesystem directory without a trailing slash. It does this by appending a trailing slash with a 301 (permanent) redirect. This is necessary in order to serve the DirectoryIndex from that directory (if any).

    In order to override this behaviour and prevent mod_dir appending the trailing slash (and ultimately serving the DirectoryIndex) you need to set the following near the top of the .htaccess file (after the Options directive would be a logical place to put it).

    DirectorySlash Off
    

    However, you will need to make sure the browser (and any intermediary) caches are cleared, since the earlier 301 (permanent) redirect (that appended the trailing slash) will have been cached persistently by the browser.

    Reference: https://httpd.apache.org/docs/2.4/mod/mod_dir.html#directoryslash

    However (#1), you also need to ensure that auto-generated directory listings (mod_autoindex) are disabled, otherwise you can find that your file structure is exposed even when a DirectoryIndex document is present. So, modify the Options directive accordingly:

    # Disable MultiViews and directory listings
    Options +FollowSymLinks -MultiViews -Indexes
    

    However (#2), this essentially renders all directories inaccessible if the trailing slash is omitted. If you are expecting directories to be requested without a trailing slash then you need to manually append the trailing slash, since mod_dir will no longer do this for you. For example, after the rule that appends the .php file extension (ie. after the # Allow extensionless PHP URLs to work rule in your code) add the following:

    # Append the trailing slash to directories (if required)
    RewriteCond %{DOCUMENT_ROOT}/$0 -d
    RewriteRule .*[^/]$ /$0/ [R=301,L]
    

    Where .*[^/]$ matches any URL-path that does not end in a trailing slash. If the URL-paths that map to physical directories do not include dots then this can be further optimised to exclude dots from the regex (so to avoid testing your static assets). eg. ^[^.]*[^/]$ (not also the addition of the start-of-string anchor).

    The $0 backreference contains the entire URL-path that is matched by the RewriteRule pattern.


    Sorry, I overlooked the comment you made on my earlier answer. Although this does warrant an answer in itself as it's not necessarily a trivial fix.