Web development


Using an .htaccess file to prevent people stealing bandwidth by linking directly to your images from another website is a popular and well-known technique. I needed to do this, but decided to take it a step further with a little added PHP.

Most solutions simply display another image (as polite or as rude as you like) in place of the hotlinked image. But I was curious to know who was linking to which images. Some of them might be legitimate users, in which case I could unblock them. Others might need to get a stiff warning about copyright.

For the .htaccess file, I used the technique here. But the author was actually redirecting to another page with the requested image embedded in it. Hey, I’m trying to save bandwidth here! So I wrote a PHP script that would log the access and then display a small generic image advertising the website from which the image had been, er, “borrowed”. Here’s the .htaccess file:

RewriteEngine On
# hotlinked images
RewriteCond %{REQUEST_FILENAME} \.(gif|jpe?g|png)$ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !mydomain\.com [NC]
RewriteCond %{HTTP_REFERER} !myotherdomain\.com [NC]
RewriteCond %{HTTP_REFERER} !alegitimatedomain\.com [NC]
RewriteRule (.*) /blockimage.php?imagename=$1 [NC,L]
# end hotlinked images

This file, placed in the images directory, blocks all but the authorised domains and any blank referrers from accessing images. Notice that the image requested is passed to my blockimage.php script in the query string (that’s what the $1 does), because I’m going to use it later.

I could have logged accesses to a text file, but I have a MySQL database so I might as well use it; it will let me do further statistical analysis of the accesses too. I created the following table:

CREATE TABLE Hotlinks (
hotlinkid int(10) unsigned NOT NULL auto_increment,
referrer varchar(255) NOT NULL default '',
imagename varchar(255) NOT NULL default '',
linktime timestamp NOT NULL default CURRENT_TIMESTAMP,
PRIMARY KEY (hotlinkid)
) ENGINE=InnoDB;

I used INNODB for the table type because I reckoned it would be quicker for frequent writes and infrequent reads, but you can use MyISAM if INNODB isn’t available on your server.

Now the PHP code:

<?php
// called when an image is hotlinked
// ... snipped code to connect to database ...
// get the referrer and image name
// first initialise an empty array to hold them
$values = array();
$values['referrer'] = mysql_real_escape_string($_SERVER['HTTP_REFERER']);
// get the image name from the query string thanks to .htaccess
$values['imagename'] = mysql_real_escape_string($_GET['imagename']);
// write it to Hotlinks table using my own insertrow function
$result = insertrow($DB, 'Hotlinks', $values);
// show a nice image advertising my site
$mimetype = 'image/jpeg';
$filename= $_SERVER['DOCUMENT_ROOT'].'/images/sitelogo.jpg';
header('content-type: '.$mimetype);
header('content-length: '.filesize($filename));
readfile($filename);
?>

So after silently logging the access, the PHP code sets the mime type to what the calling page is expecting (an image) and then returns the specified image to the browser. Remember you can’t have any other output (including white space) before the calls to the header function.

Now I can check the database table to see who is accessing what, and if I see any legitimate domains there, I can add them to the “allowed” list in .htaccess.

Ironically I ended up not using this code on the site it was intended for, for various reasons. But I think it’s an interesting and potentially useful technique, so I’m posting it here anyway.

It gave me migraines till I discovered jQuery. Now I can validate a form with some simple CSS and a couple of lines of jQuery code. And today I had a rather odd requirement to toggle the colour of cells in a table when you click on them. In the old days, I wouldn’t even have attempted this. In my new jQuery heaven, I did this:


(document).ready(function() {
$("td.standard").click(
function(){
var currentclass = $(this).attr("class");
if (currentclass.indexOf("highlightcell") == -1) {
$(this).addClass("highlightcell");
} else {
$(this).removeClass("highlightcell");
}
}
);
});

Voilà!

Chocs To Go The goal for students on the intermediate PHP and MySQL course that I’m running for IWA/HWG is to create a working shopping cart. The course starts in only three days, and I decided I’d better walk the walk and prove I could do it. So I have quickly mocked up a working version of the cart they are expected to build and put it online here. I think it will be helpful to students to see what they are aiming at, and it will make it easier for them to work out the logic if they can click through a real example. The design may not win any prizes, but the basics are all there.

All course materials now written and double-checked, quiz questions written and checked, SQL scripts generated and tested … just need to put week one’s materials up now!

Since 1999 I’ve been teaching online for the Open University. It may not pay brilliantly, but it’s regular income and I really enjoy doing it; OU students often overcome major barriers to achieve a qualification they missed out on earlier in life, for whatever reason, so they can be very rewarding to teach. And the fact that it’s online means I can conveniently fit it around other work. Currently I teach three courses in the Certificate in Web Application Development.

I can now announce that I’m also going to start teaching an online course with eClasses.org, the online learning branch of IWA/HWG. The course uses PHP and MySQL to build a shopping cart, and is aimed at intermediate PHP developers (you don’t have to know anything about MySQL, but it certainly helps if you do). I’m really lookng forward to this; you can see the full course description here, and registration is now open.

We built Corbières Web almost exactly ten years ago, when we first moved to France. The primary aim was to have a site we could put in the portfolio of our budding web development company. We had a wonderful time travelling around the area taking hundreds of photos and discovering all sorts of out-of-the-way places. And we landed our first large contract as a direct result of someone seeing Corbières Web. As the first website dedicated to the area, it built up a fair amount of traffic and even won an award from the Comité Régional de Tourisme. So it certainly wasn’t a waste of time.

Then we got busy and the site got pushed so far away from the stove it wasn’t even anywhere near the back burner. I added links to it occasionally, when people emailed me and asked, and we added a few pages to it for local businesses, for a small charge. But the last time the design was touched was in 1999, and it was beginning to look a bit embarrassing. It wasn’t just the surface appearance that was old-fashioned; the code was a mess of font tags, nested tables, and invalid HTML. And this mass of 150 or so static pages was time-consuming to update, so it just didn’t get done.

I started converting it to use a CMS about a year ago in order to make updates easier, but once again didn’t have the time to complete the job. But then thanks to an online CSS workshop class he was taking, Steve picked it up as a challenge for his final project. The old design was completely scrapped and he came up with a classy new design that is valid XHTML Strict. We merged this with my work on the CMS and were able to launch the converted site within a week.

One of the challenges of the site was that it is bilingual English-French, and each page linked to its equivalent in the other language. Using SPIP for the content management means that you can easily link different language versions of the same content so that links to translations appear automatically, and when visitors choose which language they want to view the site in, that choice is automatically retained. This is the third SPIP site we’ve done, and the more I use SPIP the more impressed I am with it. Its syntax for “squelettes” (templates) and “boucles” (loops) takes a bit of getting used to, but it’s very powerful and I haven’t yet found anything I couldn’t do — even if some things require a fair amount of fiddling to get right. The documentation is superb, some of the best I’ve seen for an open-source web application, and spip-contrib is a good source of extra tips.

A few years ago, when dynamic, interactive websites were not as common as they are now, we decided to showcase our database skills by setting up a simple demonstration website that would allow site visitors to edit the content online. Looking around for some suitable application I hit on my small collection of recipes that I’d been emailing to friends, and the Archetype recipe database was born.

I created two versions — the “play” versions, that visitors could edit, and a live uneditable version that contained myoriginal recipes. I’ve since found it a genuinely useful application — when I find a recipe in a magazine or on a website that I particularly like, I add it to the website and I can then easily find it again, no matter where I am.

But rather embarrassingly, it seems a lot of other people find it useful too. Our website is supposed to promote our web design services, but the recipe pages have become by far the most popular on the site — without bringing in hordes of prospects eager for us to make them a dynamic website too! Looking at the stats for search terms used to find our site is revealing:

sauce beurre citron 133 5.7 %
sauce pour poisson 121 5.2 %
tartiflette 72 3.1 %
tartiflette recipe 32 1.3 %
recette croustillon 27 1.1 %
pitta bread 20 0.8 %
pitta bread recipe 20 0.8 %
brochette de gambas 20 0.8 %
sauce citron beurre 20 0.8 %
recette sauce beurre citron 18 0.7 %
sauce mandarine 17 0.7 %
orange sauce for duck 16 0.6 %
pintade aux choux 16 0.6 %

… and so it goes on. I’m sure it can’t do our site much good in the search engines, in terms of ranking highly for web design!

But perhaps I should see this as an opportunity. When I realised how popular these pages were, I thought I might as well put some Amazon ads on them, but those have earned me about one cookbook every three years. Now I’ve decided to try putting Google AdSense ads on them — we’ll see if those do any better. So it’s turned out to be a useful space for experimentation with revenue models, and it helps me get aninsight into the economics of web publishing.

More generally, looking at the terms people use to find your site can be a useful exercise. It may alert you to new services you could offer them, if they are searching for products and services related to your business, but which you don’t currently offer. Hmm, on this evidence maybe we should start bottling and selling lemon butter sauce …

Once you’ve established the purpose of your website, and who will be using it, you can start to plan the basic structure of the site, which will determine the all-important site navigation system.

Too many sites reflect the internal politics of the committee that created them — don’t let yours fall into this trap! The structure of the site should reflect the perspective of your target audience, not your own internal organization. If you have identified several audiences (e.g. investors, customers, employees) you may need to offer different paths through the site to help them find what they need.

So your next job is to create a structure which will support the site’s objectives. Always keep in mind that visitors to your site are looking for information. Its purpose should be immediately obvious, and it should be easy to navigate. Great content is no use if people can’t find it!

The first thing you need to do is to establish a “content inventory” by asking yourself two questions:

  • What sort of information are my visitors looking for? Remember different audiences may have different requirements.
  • What will visitors want to do? This could include buying goods, searching for information, personalising content, signing up for a newsletter …

Make a list of all the ideas you come up with, if necessary categorized by audience. Then check that these ideas are consistent with the goals of the site — throw out any that aren’t. The next step is to take all these elements and organize them into a logical structure. Use whatever means you are comfortable with for this — it might be a flowchart, a mind map diagram, or even a collection of index cards which you can shuffle about on a table and divide into piles representing different sections of the site. It can also be helpful to visualize your site using a metaphor — for example, if you are selling groceries, a supermarket is an obvious organizational model. It’s a good idea to involve people from different parts of your organization in this process — they will bring valuable perspectives which you may have overlooked.

Once you are happy with your structure, draw up a formal site plan and get everyone involved to agree on it. This document will ultimately determine the basic navigational structure which will be used for every page on the site. You (or your designer) will also be able to use it to create a list of all the pages which need to be created, and the elements they must include. This list will later be used to allocate tasks and manage the development process.

The major navigation elements of the site should now be obvious. For example, you have probably identified major sections of the site which should be accessible from every page. If the site is quite small, this may be all the navigation you need. If you have a deep, many-layered structure, you will probably want to add a sub-menu of items specific to each section, to avoid cluttering every page with a confusing mass of options.

A well-defined site structure means you know from the outset what the scope of the project is, and it makes designing consistent page layouts and templates a much easier task. In the long run, it will simplify maintenance and updating of the site, so you can keep content fresh and add new features in response to customer demand without busting your budget. Result — more happy customers and a boost to your bottom line!

So you’ve decided to create a new Web site, or renovate your existing one. We all know that in Internet time, the best time to launch a new project is always last week, so it’s very tempting to plunge straight in, call your web designer, and fix up a meeting. But stop and reflect before you grab that phone. Here are three questions you should ask yourself first, whether you are creating the site yourself or paying a professional to do it for you. In the long run you’ll save yourself both time and money.

What is the site for?

Yes, this sounds like a dumb question. But you must have visited websites where even after viewing three or four pages, you couldn’t work out what the point was! If you aren’t clear about your goals, your visitors won’t be either. So the very first thing you should do is to define the purpose of your site. Try to distil out the essence of your site into a single short paragraph — or even a single sentence. If you can’t do this, your site will lack focus. For example, “The goal of this site is to generate leads for Product X”. Of course the site may have other, subsidiary objectives — if that’s the case note these down too, so that you can take them into account during the design process.

Who are you trying to reach?

Now you know what your site is for, imagine the people who will use it. Try to get inside their heads — how old are they? Are they male or female? What are their interests? What other sites do they visit? What do they want from you? Some people find it helpful to invent characters representing different types of visitor, and picture them using the site.

If you are revamping an existing site you already have some very valuable information about your customers in your server log files. Use a log analysis package to identify which are the most and least popular pages or sections of your site. The terms people entered into search engines to find you are a good indicator of their interests. And looking at the paths people take through your site can often indicate where navigation is confusing, or suggest areas that could be expanded.

Whatever the overall goal of your site, remember it must please the end users if it is to succeed — look at it from their point of view, and try to provide information and services of value to them.

How will you know you have succeeded?

It’s easy to say “The goal of my site is to sell more widgets”. Or “We want to increase page views and hence advertising revenue.” But how will you know when you have achieved your goal? Try to come up with some specific, measurable objectives related to your primary goal. For example, “We expect the new website to increase sales of widgets by 30% in the first 6 months”. This is important for at least two reasons:

  • It gives you a specific target to aim for. If everyone working on the project keeps this target in mind, it will focus their efforts on the tasks that need to be done to achieve it. And with proper planning, you can evaluate how the designer’s proposals will advance your goals. If that cool 500K Flash movie on the home page doesn’t contribute to a specific objective, then dump it!
  • It gives you something to measure results against. If after 6 months sales have only increased by 10%, what went wrong? Were your objectives realistic? What could you have done differently? Of course if sales increase by 60%, you can give yourself a well-earned pat on the back!

It needn’t take a long time to come up with answers to these questions. Doing this preliminary groundwork will help your web designer come up with an appropriate solution, and save you expensive consultancy time. And while this approach doesn’t guarantee success, it will greatly improve your chances of building a website that works.