5

I have a simple question, yet I've found no posts that answer my question. I need an htaccess file that rewrites the urls so that it removes the ending / if any, and adds .php no matter what the folder it is in. Essentially, this is what I want to do:

http://example.com/login/ -> http://example.com/login.php
http://example.com/login -> http://example.com/login.php
http://example.com/user/test/login/ -> http://example.com/user/test/login.php
http://example.com/user/test/login -> http://example.com/user/test/login.php
http://example.com/$1/$2/$3/$4/ -> http://example.com/$1/$2/$3/$4.php
http://example.com/$1/$2/$3/$4 -> http://example.com/$1/$2/$3/$4.php
http://example.com/$1/$2/$3/ ... /$65/ -> http://example.com/$1/$2/$3/ ... /$65.php

I want it to rewrite the URL to remove the trailing slash if any, and add .php (but do this ONLY if the file exists). And it needs to have 'wildcard' support, meaning it works for all files without having to copy the code for each individual file. That way, the URLs 'look clean'.

I've found many posts with sample .htaccess files similar to what I want. But I haven't found one without one of these problems:

  1. It doesn't use 'wildcard' rewrites, so I would have to copy the code for each file to make it rewrite the URL

  2. It removes the trailing slash if any, then appends the filename to /index.php?file= instead of rewriting to the file.

  3. The 'wildcard' rewrite works only in the root directory. I can't use it if the files are nested like so: /$1/$2/$3/$4/.

Is this possible? I haven't seen anyone do it before.

Edit: I'll award a bounty if someone comes up with an .htaccess file that does all of this correctly, but also supports URL parameters.

1 Answer 1

4
+50

I assume you want to remove the trailing slash (if any) with an external redirect in order to canonicalise the URL and then append the .php extension with an internal rewrite (ie. hidden from the user) in order to correctly route the URL. This is a two-stage process.

NB: The trailing slash should remain if accessing a physical directory.

Using mod_rewrite in .htaccess:

RewriteEngine On

# Remove the trailing slash (if any) for non-directories
# This is essentially unconditional in order to canonicalise the URL
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ /$1 [R=302,L]

# Append ".php" if that file would exist (internal rewrite / hidden from user)
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]

Change the R=302 (ie. temporary redirect) to R=301 to make it permanent. 302s are easier to test with as they aren't cached by the browser. (Make sure the browser cache is clear before testing.)

It is "wildcard" in the sense that it works for any file depth. .* simply grabs everything.

URL parameters will be appended onto the substitution by default - nothing special you need to do in this respect.


UPDATE: Since the canonical URL would seem to be the URL with the trailing slash (to which requests are being POST'd) then the above should be changed to the following:

RewriteEngine On

# Append .php if that file exists (internal rewrite)
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*?)/?$ $1.php [L]

This will accept requests for both /path/to/file and /path/to/file/ and internally rewrite the request to /path/to/file.php. You will need to handle the URL canonicalisation in your script. If all your URLs already point to /path/to/file/ (ie. with a trailing slash) then you can modify the RewriteRule pattern and remove both ? ie. (.*)/$ - this makes the trailing slash mandatory on the request.

11
  • Alright. Here's the problem I'm having so far: /api/v1/auth/csrf/ -> /auth/csrf.php. I don't know why it is getting rid of the /api/v1 part. Any ideas?
    – Aaron Esau
    Mar 5, 2017 at 22:10
  • 1
    Is this .htaccess file in the document root? Do you have any other directives in your .htaccess file? Do you have any other .htaccess files? Just to clarify, you don't actually see /auth/csrf.php in the browser's address bar do you?
    – MrWhite
    Mar 5, 2017 at 22:15
  • The .htaccess file is in the document root. The file is an exact copy of the one in this post, including comments. I have two other .htaccess files, but they are in different directories (one in the /includes/ folder that stops people from accessing it from the web, and one in the /assets/user-icons/ folder). I don't see it in the browser address bar, it just displays a 404 page and says /auth/csrf.php does not exist. But the browser bar says /api/v1/auth/csrf/.
    – Aaron Esau
    Mar 5, 2017 at 22:20
  • 1
    Awesome, this worked! It is a little complicated to explain what the problem was, but it it was a problem on my end. Thanks a lot! I'll be able to submit a bounty in 2 days.
    – Aaron Esau
    Mar 5, 2017 at 23:11
  • 1
    There is no difference between those directives except for the HTTP status code returned to the browser - so there is no reason why they would behave differently except for a client-side (or proxy) caching issue. (?) Just to clarify, you changed the redirect back to a rewrite (as in the original code block) and it was working OK (after fixing whatever it was at your end)?
    – MrWhite
    Mar 5, 2017 at 23:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.