Adding A Trailing Slash To A Zend Framework URL

“We need all our URL’s to have a trailing slash”, was a request I had in recently.

This sounds easy enough, a quick rewrite rule will do the trick, and that is what I added.

RewriteRule ^(.*[^/])$ /$1/ [R=301,L]

I look at the start of the URL, grab every character to the end of the URL, making sure the last one isn’t a slash already, then rewrite that with slashes around it, issuing a 301 redirect and informing Apache not to process any more rules.

This works great for pages already on the server, for example /guestbook becomes /guestbook/. However, what if we wanted to load /logo.gif, this would rewrite to /logo.gif/ and cause a error.

OK, so we need not to match every character in the URL, but only if it doesn’t have a dot in there. The site in question was a Zend Framework application, and this caused it’s own problems.

Zend Framework applications have their own rewriting rules…

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

This checks if the requested resource is actually a real object Apache can serve, if not it passes it over to the Zend Framework to handle internally via the index.php script.

So what happens if /guestbook is actually a Zend Framework application?

Well, the URL would be rewritten to /index.php/.

Why? Well the first rewrite we added a slash, this caused the page to re-requested, this then passed to the Zend Framework rewrites, this saw it needed to rewrite to index.php, this caused the page to be re-requested again internally, which added a slash to the end, and redirected again. Finally this request was /index.php/ which doesn’t exist and failed.

Wow, that was a mouthful, let’s look at that as a sequence diagram.

sequence diagram showing apache rewrites and Zend Framework working incorrectly

What we need is to only rewrite the requested URL if it doesn’t have a trailing slash and if it doesn’t have a dot in the request and if it isn’t an internal Apache redirect. We also only want to rewrite if the request is a GET, POSTs (DELETE’s and PUT’s too) don’t support rewriting in the browser.

This indicates a series a conditions that need to be met, so tells me we should be using Apache’s RewriteCond directive.

Let’s check for a GET request first…

RewriteCond %{REQUEST_METHOD} GET [NC]

The %{REQUEST_METHOD} variable in a rewrite rule tells us the HTTP method used to make the request, so we just need to check if that is GET. The [NC] makes the check case insensitive so matches GET, get, Get, etc…

Next we need to see if the request already has a trailing slash.

RewriteCond %{REQUEST_URI} !/$

This checks the requested URI and sees if the last character isn’t a slash.

Now we need to check if there are any dots in the request.

RewriteCond %{REQUEST_URI} !.

This just checks that there isn’t a dot in the requested URI. As dot normally matches any character, we need to escape this with a clash first.

If all these conditions match, we can issue our RewriteRule.

RewriteRule ^.*$ %{REQUEST_URI}/ [R=301,L]

This takes the requested URI, adds a slash and issues a 301 status code to force the browser to re-request the page and change the URL shown in the address bar. We add the L to tell Apache not to process any more rules.

Let’s put this all together, and insert it above the normal Zend Framework rewrites, but after RewriteEngine On.

RewriteCond %{REQUEST_METHOD} GET [NC]
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !.
RewriteRule ^.*$ %{REQUEST_URI}/ [R=301,L]

Let’s request /guestbook again, and see what happens.

sequence diagram showing apache rewrites and Zend Framework

3 thoughts on “Adding A Trailing Slash To A Zend Framework URL”

  1. Thank you Mr Price – this is exactly what I needed.

    It’s also a very well written tech-article exemplar.

Comments are closed.