I got an old project and it has some bizarre issue. Its CodeIgniter project (version 2.X).
Google is indexing our URLs with index.php?. Below is an example
https://www.website.com/index.php?/my-seo-friendly-uri
I can see my pages from above url and with 2 more variants as below
https://www.website.com/index.php/my-seo-friendly-uri
https://www.website.com/my-seo-friendly-uri
We have used https://www.website.com/my-seo-friendly-uri
throughout the site.
My question is how I can redirect https://www.website.com/index.php?/my-seo-friendly-uri
and https://www.website.com/index.php/my-seo-friendly-uri
to https://www.website.com/my-seo-friendly-uri
?
The thing I already did
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^index.php/(.*)$ /$1 [R=302,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
This redirects index.php
to normal URLs, but index.php?
version of url is still not redirecting
In my config.php
, I have the following settings
$config['index_page'] = '';
$config['uri_protocol'] = 'REQUEST_URI';
https://www.example.com/index.php?/my-seo-friendly-uri
This URL contains a query string and so requires a slightly different rule in order to match it. The RewriteRule
pattern matches against the URL-path only (just index.php
in this case). The query string is available in its own variable.
Add the following, before your existing directives (in addition to the directive that matches /index.php/my-seo-friendly-url
- which is passed as path-info):
# Redirect URLs of the form "/index.php?/my-seo-friendly-uri"
# And "/?/my-seo-friendly-uri"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^(/.*)
RewriteRule ^(index\.php)?$ %1 [QSD,R=302,L]
The query string is captured (2nd condition), and the backreference (%1
) is used to construct the redirect.
The first condition that checks against the REDIRECT_STATUS
environment variable is required in order to prevent a redirect loop, since you appear to be using the query string method to route the codeigniter URLs in the later rewrite. The REDIRECT_STATUS
env var is empty on the initial request, but set to "200" (as in 200 OK HTTP status) after the first successful rewrite.
The QSD
flag (Apache 2.4+) is required to discard the original query string from the redirected request. If you are still on Apache 2.2 then append a ?
(empty query string) to the substitution string instead. ie. %1?
By making the match for index.php
optional (ie. ^(index\.php)?$
) it will also canonicalise URLs that omit index.php
, but still include the query string (that may or may not currently be a problem). eg. /?/my-seo-friendly-uri
.
Note that this is currently a 302 (temporary) redirect (as is your existing redirect). Only change this to a 301 (permanent) redirect once you have confirmed it works OK. 301s are cached persistently by the browser so can make testing problematic.
Your .htaccess
file should look like this:
RewriteEngine On
# Query string...
# Redirect URLs of the form "/index.php?/my-seo-friendly-uri"
# And "/?/my-seo-friendly-uri"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^(/.*)
RewriteRule ^(index\.php)?$ %1 [QSD,R=302,L]
# Path-Info...
# Redirect URLs of the form "/index.php/my-seo-friendly-uri"
# Also handles "/index.php" only
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index.php(?:/(.*))?$ /$1 [R=302,L]
# CodeIgniter Front-controller
# (NB: Using query string method to pass the URL)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?/$1 [L]
Additional notes...
<IfModule>
wrapper is not required.(.*)
is the same as ^(.*)$
since regex is greedy by default./index.php/foo
) to also redirect requests for /index.php
only. This now requires an additional condition to avoid a redirect loop.Your CodeIgniter front-controller is using the query string method to pass /my-seo-friendly-url
to the backend (as used in the question). However, you have set $config['uri_protocol'] = 'REQUEST_URI';
- which contradicts with this (although shouldn't necessarily be a problem). However, if you are using the REQUEST_URI
method then you can remove the ?/$1
part from the end of the final RewriteRule
substitution string. For example:
For example, from this:
RewriteRule (.*) index.php?/$1 [L]
To this:
RewriteRule . index.php [L]