skip to Main Content

I recently started working with the rewrite engine and asked for help on removing the PHP extension and adding a trailing slash to URLs. A perfectly working solution was provided by anubhava here. For a quick reference, the configuration file is provided below:

.htaccess

RewriteEngine On

# removes .php and adds a trailing /
# i.e. to externally redirect /path/file.php to /path/file/
RewriteCond %{THE_REQUEST} s/+(.+?).php[s?] [NC]
RewriteRule ^ /%1/ [R=307,NE,L]

# adds a trailing slash to non files 
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=307,NE]

# internally rewrites /path/file/ to /path/file.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)/$ $1.php [L]

This configuration works as intended for URLs like:

https://example.com/test.php
https://example.com/test
https://example.com/test/

The URLs above are all rewritten to:

https://example.com/test/

So far so good, except that if the PHP file contains a query string, it works a little differently than I would like. For example, if the URL is:

https://example.com/test.php?lang=en&id=3

Then it is rewritten to:

https://example.com/test/?lang=en&id=3

Unfortunately, I did not anticipate this problem, which is causing me issues because I cannot capture the query string in the PHP file below.

test.php

<?php
session_start();

if(isset($_GET['lang']))
{
    $_SESSION['lang'] = $_GET['lang'];
}
?>

To resolve this, I need a method to capture the PHP query string. I think rewriting the URL to https://example.com/test?lang=en&id=3/ could work. However, I’m open to alternative solutions.

Edit: Given the complexity of the problem, the trailing slash is optional, but I would like to remove the PHP extension and be able to capture the query string.

2

Answers


  1. Considering our discussion in the comments, this (though only very roughly tested on a flawed online htaccess tester) should work.

    Noticed I removed the adding of the ‘/’ exceptif there is a real directory. Adding a / has a significant meaning for an URL (it refers to a directory, not to a file!) so just adding it for beauty makes no sense, it is exactly why everything became complicated and went wrong.

    If you use routing (for instance in Laravel or another platform) of course you can do with the url whatever you want, but since you don’t seem to be, and seem to need the URL match to a file on your server, you just really don’t want to add random slashes.

    # removes .php
    # i.e. to externally redirect /path/file.php to /path/file
    RewriteCond %{REQUEST_URI} /+(.+?).php$ [NC]
    RewriteRule ^ /%1 [R=307,NE,L]
    
    # adds a trailing slash to directories 
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=307,NE]
    
    # internally rewrites /path/file to /path/file.php
    RewriteCond %{REQUEST_FILENAME}.php -f
    RewriteRule ^(.+)$ $1.php [L]
    

    NOTE: this example now choses the directory if both a directory and a file exists, i.e. with path/name/* and path/name.php both existing, the dir is chosen. If you don’t want that, I think switching the last two blocks around will do the trick.

    Login or Signup to reply.
  2. The RewriteRule directive allows for a QSA flag that copies the query string to the rewritten URL.

    When the replacement URI contains a query string, the default behavior of RewriteRule is to discard the existing query string, and replace it with the newly generated one. Using the [QSA] flag causes the query strings to be combined.

    So your [L] flags should be something like [L,QSA].

    For additional doc, you can find the list of available flags for the RewriteRule directive.

    I found this out by reading the Fat-Free Framework .htaccess sample.

    RewriteEngine On
    
    RewriteRule ^(app|dict|ns|tmp)/|.ini$ - [R=404]
    
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule .* index.php [L,QSA] <------------------------------------ HERE
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search