Reputation: 1
I'd like to know if it is possible to add a rule to the htaccess of my ZF app to redirect all the URLs that ends with the segment /index/
(such as http://domain.ext/index/
) to the same URL without the /index/
suffix.
I've tried with this simple rule:
RedirectMatch ^(.*)/(index(/)?)$ http://localhost$1
but it doesn't work as expected (with other frameworks such as FuelPHP it works like a charm).
I know that this can be done via PHP using a plugin but I'd like to make the redirect via Apache to improve the performance of the application.
Upvotes: 0
Views: 1446
Reputation: 14228
RewriteRule ^(.*)/index(?|$)$ $1$2 [R=301,L]
this works with urls
/index => /
/index?page=2 => /?page2
/index/index => /
/index/index?page=2 /?page2
you need remove trailing slash before, for url like /index/, index/index/
RewriteRule ^(.*)/$ /$1 [L,R=301]
url like /index/help will work without changes
Upvotes: 0
Reputation: 3128
I don't know why nobody jumped in here, it is not that complicated?
A config file is executed from top to bottom and certain rules cause an immediate exit. If the rule defines an external redirect the server will perform that redirect immediately and all following rules are therefore ignored. If the redirect is back to the same server and config file then it is just a new game with the rules! If the redirect rule does not apply anymore it is on to the next rule. If the rule would still apply you get a loop.
Similar thing with a RewriteRule that matches and has [L]. L means "Stop the rewriting process here and don't apply any more rewrite rules". This quote is straight from the manual
Now you simply have to define some logic in what order you want to apply certain rules. Your request about the RedirectMatch for any /index/ path is certainly something you want to have very early to the top of the config. If there is a match your config will end here and perform a redirect! The browser will send a new request and we have a new game.
The RewriteRule to an index.php is something we will add very late at the bottom. It may be our last resort like a if all fails then rule. I does not matter if this is the Zend Framework or any other application you funnel through an index.php or other script for that matter.
The following rules should cover any variation with index, including .php, .htm and .html and finally trigger the index.php file for your ZF application.
RedirectMatch ^(/.*)/(index.(php|html|htm)|index)/?$ $1
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
When testing redirect rules be careful with your browser and use one where you can totally reset all cache and history settings. All current browsers are notorious in "remembering" redirects. If they learned a redirect rule they will perform that redirect internal, i.e. they don't go to the server to see what's new!
Upvotes: 1
Reputation: 1
I resolved my problem with this (horrible) workaround: - I renamed the "index" action of IndexController to "home" - I setup a static route for home page (source) - I changed the htaccess to:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*)home(/)?$ $1 [R=301,L]
RewriteRule ^(.*)index/(.*)$ $1$2 [R=301,L]
RewriteRule ^.*$ index.php [QSA,NC,L]
So now the home page is not duplicated because http://localhost/home/ is redirected to the base domain and for other controllers the index action, if it is called specifying the action name (/controller/index/param/value) is redirected to the desired URL (/controller/param/value/)
Upvotes: 0
Reputation: 10888
Here is your ruleset laid out readably
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RedirectMatch ^(.*)/(index(/)?)$ http://localhost$1
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
RedirectMatch
is a mod_alias directive which severs the conds as from their rule. Also it's a lot less fraught not mixing mod_alias and mod_rewrite directives, so try:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(.*?)/index/?$ $1 [R=301,L]
RewriteRule ^.*$ index.php [NC,L]
(updated following posters comments)
I tried this out on my VM which mirrors my hosting service, but having root access I can see the 'production' rewrite logs. This fails because the second rules still falls through to rule (3) which dispatchs to index.php. This then returms the full content but with a 301 status and without issuing a new location. If I change the [R=301]
to [R=301,L]
then it works fine as the server now issues a 301 with a Location
header and the browser now retries with the new location.
The documentation states:
You will almost always want to use [R] in conjunction with [L] (that is, use [R,L]) because on its own, the [R] flag prepends
http://thishost[:thisport]
to the URI, but then passes this on to the next rule in the ruleset, which can often result in 'Invalid URI in request' warnings.
Upvotes: 0