4

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';
4
  • Use [R=301,L] on the index.php? version. Commented Feb 11, 2020 at 12:55
  • What is the code ? Commented Feb 11, 2020 at 12:57
  • Have you check for $config['enable_query_string'] settings in config? Commented Feb 12, 2020 at 9:10
  • There is no such setting Commented Feb 12, 2020 at 10:47

3 Answers 3

2
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.

Summary

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...

  • The <IfModule> wrapper is not required.
  • (.*) is the same as ^(.*)$ since regex is greedy by default.
  • I've modified your existing path-info redirect (ie. /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]
    
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you @MrWhite, it is redirecting like this https://www.website.com/index.php?/my-seo-friendly-uri -> https://www.website.com/my-seo-friendly-uri?/my-seo-friendly-uri
Sorry, you need the QSD flag on the RewriteRule to discard the original query string from the target URL. I've updated my answer.
Now it works fot index.php? but not for index.php
"but not for index.php" - By that do you mean /index.php by itself and no path-info? I've modified your existing redirect to handle that scenario. What I've posted above should be all that's required - in addition to the directives you posted in the question (which was already redirecting URLs of the form /index.php/foo). I'm assuming you have no other directives in your .htaccess file that might otherwise be conflicting. I've updated my answer with a complete summary of exactly what your .htaccess file should look like.
Awesome, the last update did the trick. It is now working for both. I was not giving proper attention to identify both cases. I guess I need to learn lot. Also, this is great in depth explanation. Again, thank you very much
0

I copy index.php and .htacess from "\public" to "". and edit "\index.php" to

require FCPATH . 'app/Config/Paths.php';

modify "\app\config\app.php" as below

public string $indexPage = '';

then modify .htacess in "\public" and "" as

Options -Indexes
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On


RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)$ index.php/$1 [QSA,L]

RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
<IfModule !mod_rewrite.c>

ErrorDocument 404 index.php
</IfModule>

ServerSignature Off

It's work for me

Comments

-1

Use .htaccess................

 <IfModule mod_rewrite.c>
 RewriteEngine on
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d

 <IfModule mod_php5.c>
     RewriteRule ^(.*)$ index.php/$1 [L]
 </IfModule>

 <IfModule !mod_php5.c>
     RewriteRule ^(.*)$ index.php?/$1 [L]
 </IfModule>

</IfModule>

3 Comments

Working for index.php? but not for index.php
@sanjayojha The code above wouldn't "work for index.php?" (ie. it wouldn't canonicalise a request for /index.php?/my-seo-friendly-url) - it doesn't contain a redirect at all?!
I'm sorry, but this doesn't answer the question. It makes no attempt to remove index.php from the requested URL - in order to canonicalise incorrectly indexed URLs. The code here is simply a CodeIgniter front-controller (pretty much the same as the code already presented in the question).

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.