Returning A 410 HTTP Status Code In Apache

I had an SEO requirement to return a 410 HTTP status code for any URL’s with /advanced-search/ in them.

The following snippet can be added to your Apache config to achieve this.

# Return a 410 for any URL's with advanced-search in
RewriteCond %{REQUEST_URI} /advanced-search/
RewriteRule ^.*$ - [G]

Here we’re looking in the URI for the words /advanced-search/ and if found, the RewriteRule below is activated.

The RewriteRule takes the URL, keeps it intact and sets the [G] flag. The [G] flag forces the server to return a 410 Gone status as it’s response.

If Apache sees a [G] flag, it returns immediately and no further rewrite rules are evaluated.

A 410 HTTP status code indicates that a resource was once available, but isn’t any more.

Allowing Apache To Write To The Vagrant Directory

I had a problem with a website I was developing in Vagrant where the site neeeded to write out to the /vagrant directory (well actually a symlink that pointed there).

Apache doesn’t have permission to write there by default, but the following change to my Vagrantfile sorted it out.

config.vm.share_folder("v-root", "/vagrant", ".", :owner => "www-data", :group => "www-data")

This makes sure that the /vagrant directory is owned by a user that apache has permission to read and write with.

I hope this helps out others who have had the same problem.

Vagrant Update – October 2013

Newer versions of Vagrant have renamed v-root to vagrant-root, so the line for the VagrantFile is now

config.vm.share_folder("vagrant-root", "/vagrant", ".", :owner => "www-data", :group => "www-data")

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