Using Font Awsome icons in a file list

In a recent WordPress project, the client needed the ability to display a list of downloads on certain pages.

The site was already using the aptly named Font Awesome, which has an icon for every occasion including many for file types, so I thought why not use an icon as a nice visual aid in the list of files.

This PHP function retrieves either the Font Awesome icon class or character code based on a mime-type by looking it up in a multi-dimensional array. If it can’t find the mime-type, it falls back on a generic file icon.

function getFontawesomeFileIcon( $mime_type, $class = true )
{
	$data = array(

		'default' => array('fa-file', 'f15b'),
		'application/x-7z-compressed' => array('fa-file-archive-o', 'f1c6'),
		'application/x-bzip' => array('fa-file-archive-o', 'f1c6'),
		'application/x-bzip2' => array('fa-file-archive-o', 'f1c6'),
		'application/x-rar-compressed' => array('fa-file-archive-o', 'f1c6'),
		'application/x-tar' => array('fa-file-archive-o', 'f1c6'),

		'audio/x-wav' => array('fa-file-audio-o', 'f1c7'),
		'audio/x-aac' => array('fa-file-audio-o', 'f1c7'),
		'audio/x-aiff' => array('fa-file-audio-o', 'f1c7'),
		'audio/x-ms-wma' => array('fa-file-audio-o', 'f1c7'),
		'audio/mpeg' => array('fa-file-audio-o', 'f1c7'),
		'audio/mp4' => array('fa-file-audio-o', 'f1c7'),
		'audio/ogg' => array('fa-file-audio-o', 'f1c7'),
		'audio/webm' => array('fa-file-audio-o', 'f1c7'),
		'audio/x-wav' => array('fa-file-audio-o', 'f1c7'),

		'text/css' => array('fa-file-code-o', 'f1c9'),
		'text/x-java-source,java' => array('fa-file-code-o', 'f1c9'),
		'application/javascript' => array('fa-file-code-o', 'f1c9'),
		'application/json' => array('fa-file-code-o', 'f1c9'),
		'text/x-pascal' => array('fa-file-code-o', 'f1c9'),

		'application/vnd.ms-excel' => array('fa-file-excel-o', 'f1c3'),
		'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => array('fa-file-excel-o', 'f1c3'),
		'text/csv' => array('fa-file-excel-o', 'f1c3'),

		'image/png' => array('fa-file-image-o', 'f1c5'),
		'image/svg+xml' => array('fa-file-image-o', 'f1c5'),
		'image/tiff' => array('fa-file-image-o', 'f1c5'),
		'image/bmp' => array('fa-file-image-o', 'f1c5'),
		'image/vnd.dwg' => array('fa-file-image-o', 'f1c5'),
		'image/gif' => array('fa-file-image-o', 'f1c5'),
		'image/jpeg' => array('fa-file-image-o', 'f1c5'),
		'image/vnd.adobe.photoshop' => array('fa-file-image-o', 'f1c5'),
		'image/x-pict' => array('fa-file-image-o', 'f1c5'),

		'video/quicktime' => array('fa-file-movie-o', 'f1c8'),
		'video/x-msvideo' => array('fa-file-movie-o', 'f1c8'),
		'video/x-flv' => array('fa-file-movie-o', 'f1c8'),
		'video/x-ms-asf' => array('fa-file-movie-o', 'f1c8'),
		'video/x-ms-wmv' => array('fa-file-movie-o', 'f1c8'),
		'video/mpeg' => array('fa-file-movie-o', 'f1c8'),
		'video/mp4' => array('fa-file-movie-o', 'f1c8'),
		'video/ogg' => array('fa-file-movie-o', 'f1c8'),
		'video/webm' => array('fa-file-movie-o', 'f1c8'),
		'video/x-matroska' => array('fa-file-movie-o', 'f1c8'),

		'application/pdf' => array('fa-file-pdf-o', 'f1c1'),

		'application/vnd.ms-powerpoint' => array('fa-file-powerpoint-o', 'f1c4'),
		'application/vnd.openxmlformats-officedocument.presentationml.presentation' => array('fa-file-powerpoint-o', 'f1c4'),

		'application/msword' => array('fa-file-word-o', 'f1c2'),
		'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => array('fa-file-word-o', 'f1c2'),

		'application/zip' => array('fa-file-zip-o', 'f1c6'),
	);

	if( !array_key_exists( $mime_type, $data) )
	{
		$mime_type = 'default';
	}

	if( $class )
	{
		return $data[$mime_type][0];
	}

	return $data[$mime_type][1];

}

htaccess Tips

Editing htaccess files on an Apache webserver is one of those tasks which I don’t do often enough for anything more than the most basic commands to stick in my brain.

Of course you can go to the Apache manual, but it is not the easiest read.

So, more often than not, I end up at Perishablepress’s ‘Stupid htaccess tricks’ which has loads of solid examples which are really easy to understand.

Checking if tables exist in a MySQL database

I recently needed to create an add-on for a shopping cart system which required it’s own database table and relied on database tables from other add-ons.

It needed an install method to create it’s own tables and needed to check for the existence of other tables.

Previously, I’ve needed to check for the existence of one table, which is easy enough:

SHOW TABLES LIKE 'TABLE_NAME'

And, retrieving all tables allows you to check the result for multiple tables in the application layer:

SHOW TABLES

But I wondered if there might be a more elegant solution to checking for multiple tables.

The answer is to query the information_schema database directly which provides a bit more flexibility:

SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'DB_NAME' 
AND (TABLE_NAME = 'TABLE1_NAME' OR TABLE_NAME = 'TABLE2_NAME')

The application can use the result for a simple boolean check if all required tables exist by counting the number of results and can also determine which tables need creating from the list.

The query can also be modified with more criteria, such as whether the table is a view or base table.

HTML and CSS test page

This is some HTML markup I use for testing CSS styling and layout.

It’s developed over time from an original I found here a while ago. I’ve added images and other bits such as sub lists.

It’s useful to paste into a template or CMS to check the styling of all HTML elements you or the end user might end up using.

<h1 id="top">CSS Basic Elements</h1>
 
<p>This HTML is to test the CSS styling of all possible HTML Elements.</p>

<p>Paragraph before a hr element.</p>
 
<hr />
 
<p>Paragraph after a hr element.</p>

<h1>Headings</h1>
 
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
 
<small><a href="#top">[Anchor to top]</a></small>
<hr />

 
<h1>Paragraphs</h1>
 
<img src="http://i.istockimg.com/file_thumbview_approve/47763528/6/stock-photo-47763528-driving-on-the-acadia-national-park.jpg" alt="Image outside of any element" test="Image outside of any element" />

<p>Lorem ipsum dolor sit amet, adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus. Maecenas ornare tortor. Donec sed tellus eget sapien fringilla nonummy. Mauris a ante. Suspendisse quam sem, consequat at, commodo vitae, feugiat in, nunc. Morbi imperdiet augue quis tellus.</p>

<h1>Preformatted Text</h1>

<pre>Lorem ipsum dolor sit amet, adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus. Maecenas ornare tortor. Donec sed tellus eget sapien fringilla nonummy. Mauris a ante. Suspendisse quam sem, consequat at, commodo vitae, feugiat in, nunc. Morbi imperdiet augue quis tellus.</pre>

<h1>Blockquote</h1>

<blockquote>
	<p>Lorem ipsum dolor sit amet, adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus.</p>

	<p>Maecenas ornare tortor. Donec sed tellus eget sapien fringilla nonummy. Mauris a ante. Suspendisse quam sem, consequat at, commodo vitae, feugiat in, nunc. Morbi imperdiet augue quis tellus.</p>
</blockquote>

<h1>Inline elements</h1>

<p><a href="#" title="test link">test link</a> lorem ipsum dolor sit amet.</p>

<p>Lorem ipsum dolor sit amet, <em>emphasis</em>.</p>

<p>Donec faucibus, <sub>subscript</sub>.</p>

<p>Lorem ipsum dolor sit amet, <sup>superscript</sup>.</p>

<p>Nullam dignissim convallis est <code>code</code> .</p>

<p>Quisque aliquam. Donec faucibus <abbr title="HTML Abbreviation element ">abbr</abbr>.</p>

<p>Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl <cite>[citation]</cite>.</p>

<p>Praesent mattis, massa quis luctus fermentum, <strong>strong</strong>.</p>

<p>Maecenas ornare tortor <big>big text big text big text </big>.</p>

<p>Suspendisse quam sem, consequat at, commodo vitae, feugiat in, nunc. <small>small text small text small text </small>.</p>

 
<small><a href="#top">[Anchor to top]</a></small>
<hr />
 
<h1>Lists</h1>
 
<h2>Definition List</h2>
<dl>
	<dt>Definition List Title 1</dt>
	<dd>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec,</dd>
	<dt>Definition List Title 2</dt>
	<dd>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec,</dd>
	<dt>Definition List Title 3</dt>
	<dd>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec,</dd>
</dl>
 
<h2>Ordered List</h2>
<ol>
	<li>List Item 1</li>
	<li>List Item 2</li>
	<li>List Item 3</li>
	<li>List Item 4
		<ol>
			<li>Nested List Item 1</li>
			<li>Nested List Item 2</li>
			<li>Nested List Item 3</li>
			<li>Nested List Item 4</li>
			<li>Nested List Item 5</li>
		</ol>
	</li>
	<li>List Item 5</li>
</ol>
 
<h2>Unordered List</h2>
<ul>
	<li>List Item 1</li>
	<li>List Item 2</li>
	<li>List Item 3</li>
	<li>List Item 4
		<ul>
			<li>Nested List Item 1</li>
			<li>Nested List Item 2</li>
			<li>Nested List Item 3</li>
			<li>Nested List Item 4</li>
			<li>Nested List Item 5</li>
		</ul>
	</li>
	<li>List Item 5</li>
</ul>
 
<small><a href="#top">[Anchor to top]</a></small>
<hr />
 
<h1>Fieldsets, Legends, and Form Elements</h1>
 
<fieldset>
	<legend>Legend</legend>
 
	<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus.</p>
 
	<form>
		<h2>Form Element</h2>
 
		<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui.</p>
 
		<p><label for="text_field">Text Field:</label><br />
		<input type="text" id="text_field" /></p>
 
		<p><label for="text_area">Text Area:</label><br />
		<textarea id="text_area"></textarea></p>
 
		<p><label for="select_element">Select Element:</label><br />
			<select name="select_element">
			<optgroup label="Option Group 1">
				<option value="1">Option 1</option>
				<option value="2">Option 2</option>
				<option value="3">Option 3</option>
			</optgroup>
			<optgroup label="Option Group 2">
				<option value="1">Option 1</option>
				<option value="2">Option 2</option>
				<option value="3">Option 3</option>
			</optgroup>
		</select></p>
 
		<p><label for="radio_buttons">Radio Buttons:</label><br />
			<input type="radio" class="radio" name="radio_button" value="radio_1" /> Radio 1<br/>
				<input type="radio" class="radio" name="radio_button" value="radio_2" /> Radio 2<br/>
				<input type="radio" class="radio" name="radio_button" value="radio_3" /> Radio 3<br/>
		</p>
 
		<p><label for="checkboxes">Checkboxes:</label><br />
			<input type="checkbox" class="checkbox" name="checkboxes" value="check_1" /> Radio 1<br/>
				<input type="checkbox" class="checkbox" name="checkboxes" value="check_2" /> Radio 2<br/>
				<input type="checkbox" class="checkbox" name="checkboxes" value="check_3" /> Radio 3<br/>
		</p>
 
		<p><label for="password">Password:</label><br />
			<input type="password" class="password" name="password" />
		</p>
 
		<p><label for="file">File Input:</label><br />
			<input type="file" class="file" name="file" />
		</p>
 
 
		<p><input class="button" type="reset" value="Clear" /> <input class="button" type="submit" value="Submit" />
		</p>
 
 
 
	</form>
 
</fieldset>
 
<small><a href="#wrapper">[top]</a></small>
<hr />
 
<h1 id="tables">Tables</h1>
 
<table cellspacing="0" cellpadding="0">
	<tr>
		<th>Table Header 1</th><th>Table Header 2</th><th>Table Header 3</th>
	</tr>
	<tr>
		<td>Division 1</td><td>Division 2</td><td>Division 3</td>
	</tr>
	<tr class="even">
		<td>Division 1</td><td>Division 2</td><td>Division 3</td>
	</tr>
	<tr>
		<td>Division 1</td><td>Division 2</td><td>Division 3</td>
	</tr>
 
</table>
 
<small><a href="#wrapper">[top]</a></small>
<hr />

Preventing Web HTML Form Spam

Form spam is a problem most web developers have to deal with at some point. It’s often a matter of days after a site is indexed by Google that a site’s forms start getting hit by spambots trying to advertise dodgy products, trick you into clicking dodgy links or trying to get links back to dodgy sites.

This is often an issue when you manage a site for a business. After the site is marketed and gets ‘out there’, the client gets annoyed by spam and wants something done about it.

Many developers resort to the quick fix of a captcha or a captcha is requested by a client because they have seen it elsewhere. However, captcha’s are not user friendly and can be a real turn off for visitors with a short attention span. How many times have you been frustrated by repeatedly having to complete a barely legible captcha test?

Instead, there are quite a few methods that don’t impact on normal users at all, especially when used in combination:

Validation

Simple server-side validation will eliminate a lot of automated spam. Spam bots don’t hang around to change how they format their submission, they just move on to the next easier target.

Checking the format of an email address is probably one of the most common validation operations and, as a result, a lot of spam bots will recognise email fields and enter dummy addresses.

But what about the other fields in a form? What if we spent some time validating them?

For example, a name field should probably only contain characters from A to Z, spaces, hyphens and periods. It should also have a limited length, maybe 30/40 characters.

A phone number should only include numbers, periods, hyphens and commas depending on where in the world you are.

Validation even has a role to play in non-specific fields such as a contact form message. Rejecting messages containing HTML tags, URLs (or too many URLs) and too many characters can be very effective.

Timing

The speed of submissions is another factor that can identify spam. It is relatively straightforward to use sessions to store the time when a form is requested and the time when it is submitted.

Very fast submissions (less than 1 second) or submissions with no start time (i.e. data was posted straight to the form URL) indicate that it wasn’t a human completing the form.

Honeypots

Honeypot fields are fields that are hidden from human visitors by CSS but are found by spam bots. If a form submission has content in the honeypot fields it can be rejected as spam.

This is a very effective, yet simple to implement technique. There can be issues with accessibility – screen reading software may identify honeypot fields – but this can be overcome by clearly labelling the fields as being present to catch spam and hiding the labels as well.

Session Token

A session token is a cryptographic hash stored in the session variable server-side when a page with a form is served and repeated client-side in a hidden field in the form.

When a form is submitted, the two tokens are compared and if they don’t match, chances are it is a spam submission directed straight at the page.

The one downside of this approach is that the session can time out (e.g. if a user leaves the page open for a long time before submitting a form), but this can be handled by providing an error message, replacing the content in the form fields and asking the user to re-submit.

IP, Sender & Content Filtering

Maintaining a list of spammer IPs and detecting spam content by filtering is another effective method but takes a lot of work and many submissions.

Luckily there are services that do it for you, like Akismet for WordPress.