How to remove empty query string from URL

Sometimes, there is an undesired question mark at the end of URL, e. g. /example/? instead of /example/. Question mark separates main part of the address from query string, but some browsers add it even if GET form which the URL is the result of submission of doesn’t contain fields and therefore query string is empty.

This happens, for example, when using link buttons in browsers based on Chromium / Blink (Opera 15+, Vivaldi) and WebKit (Safari) due to a bug (1, 2) they have. Trailing question mark when query string is empty can be automatically removed using server-side redirection.

PHP

A simplest solution is to use server-side scripting language PHP: full requested path is usually stored in server variable REQUEST_URI. If the first question mark in the variable value is its last character, we should redirect to URL with question mark removed.

$uri  = $_SERVER['REQUEST_URI'];
$qPos = strpos($uri, '?');

if ($qPos === strlen($uri) - 1) {
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . substr($uri, 0, $qPos));
    exit;
}

This code should be inserted into index file of your website before any other PHP code. If altering original files of your CMS is undesired (e. g. to be able to update it), then you can define your own index file (e. g. custom-index.php), put the code above into it, and then include the true CMS’s index file (typically index.php) via a require_once statement.

Apache / .htaccess

With built-in features of the popular web server Apache, it is somewhat problematic to reliably distinguish cases when query string is empty (there is only question mark at the end of URL), and when there is no query string at all (URL does not even contain question mark).

Looks like the server variable REQUEST_URI in Apache (unlike PHP) does not contain question mark at all if query string is empty.

So we are forced to analize the server variable THE_REQUEST that contains not just the requested URL, but the entire HTTP request like GET uri HTTP/1.1:

RewriteEngine On
RewriteCond %{THE_REQUEST} ^[^\s]+\s+[^?]*?\?
RewriteCond %{QUERY_STRING} =""
# For any version of Apache:
RewriteRule .? %{REQUEST_URI}? [R=301,L]
# For Apache 2.4+:
# RewriteRule .? %{REQUEST_URI} [R=301,L,QSD]

Request method (e. g. GET) and protocol (HTTP/1.1) do not typically contain question marks, so it is possible to use a simpler (though theoretically somewhat less reliable) way: checking value of the THE_REQUEST variable for question-mark existence in any part of request, not just in URL:

RewriteCond %{THE_REQUEST} \?