New site preview

My new site is coming along slowly, but surely. Even though I've had the Photoshop designs for many months (thanks, Jonny!), the actual HTML and CSS build has been quite a challenge. Getting a pixel-perfect representation of the design that works consistently across browsers has been tricky! So, I've made a few compromises along the way but overall am very happy how things are turning out.

Here is a small preview of what will become my new homepage:

Preview of the my new homepage

I'll be adding content to the other pages and tidying up over the next few weeks before letting it out in the wild. Let me know what you think!

HTML5, character encodings and DOMDocument loadHTML and loadHTMLFile

Extreme HTML Verschachteling

Whilst working on a script for my GetProThemes app recently, I came across a problem with PHP's loadHTML and loadHTMLFile methods.

The problem

I noticed that when using loadHTMLFile to parse an HTML document, the character encoding -- UTF-8 in this case -- was not being taken into consideration. Because of this, there was some mojibake after I extracted some content from the document. Here is an example of the problem:

$i18n_str = 'Iñtërnâtiônàlizætiøn';

$html = <<<EOS
<!doctype html>
<head>
  <meta charset="UTF-8">
  <title>html 5 document</title>
 </head>
 <body>
<h1 id="title">$i18n_str</h1>
</body>
</html>
EOS;

$dom = new DOMDocument();
$dom->loadHTML( $html );
echo $dom->getElementById( 'title' )->textContent;

// output: Iñtërnâtiônà lizætiøn

After some digging into the PHP source code, I discovered this function, along with loadHTML, uses Libxml for determining the character set of the HTML document automatically. It uses a function named htmlCheckEncoding for this purpose. What this function does is to look for a meta tag declaring the character set. Unfortunately, it only looks for the HTML4 style declaration:


<META http-equiv="Content-Type" content="text/html; charset=UTF-8">

This means that if your source document is HTML5, it will not pick up the newer meta tag declaration which has this form:


<meta charset="utf-8">

It seems that this glitch has been fixed in version 2.8.0 of Libxml, but if you are stuck with an older version then I have created a workaround.

The solution

I have created a drop-in replacements for the loadHTML/loadHTMLFile methods which will automatically convert an HTML5 character set declaration, if it exists, into an HTML4 character set declaration and thus allowing Libxml to parse the document correctly.

Fixing the above example is trivial:

require_once 'DOMDocumentCharset.php';

$i18n_str = 'Iñtërnâtiônàlizætiøn';

$html = <<<EOS
<!doctype html>
<head>
  <meta charset="UTF-8">
  <title>html 5 test</title>
 </head>
 <body>
<h1 id="title">$i18n_str</h1>
</body>
</html>
EOS;
		
$dom = new DOMDocumentCharset();
$dom->loadHTMLCharset( $html );
echo $dom->getElementById( 'title' )->textContent;

// output: Iñtërnâtiônàlizætiøn

So, the fix involves:

1. Including the DOMDocumentCharset class
2. Instantiating DOMDocumentCharset rather than DOMDocument
3. Calling the new loadHTMLCharset method

The class will only activate the workaround if the installed Libxml version is less than 2.8.0, so upgrading Libxml will not break this code.

The source code can be found on GitHub: dom-document-charset

An App in a Day

One thing I've really enjoyed about freelancing is the freedom to work on pet projects. When I have not been working with my paying clients, these projects have kept me busy. The trouble is, I seem to have many -- twenty at the last count -- in a perpetual state of "in progress".

So, today I had some free time and set myself a challenge -- develop and launch a useful web app in 24 hours. I decided to develop a browser for professionally-designed WordPress themes.

This challenge also allowed me to play around with some new technologies. In this case, I chose to use jQuery Masonry for the front-end Pinterest-like display.

GetProThemes screenshot

The app consists of two main parts:

1. A feed processing script that pulls in popular theme information from Mojo Themes and ThemeForest and saves them into a DB. This script is run via cron to update the themes on a weekly basis.

2. Some frontend logic that pulls out these themes and displays a preview graphic for users to click on.

In the end, I spent around eight hours on the development.

I registered a domain name, set up the hosting, added Google Analytics and affiliate referral codes and uploaded the files. The site can be found here:

GetProThemes.com

It's been a fun day, and I'll be very interested to hear if the site is useful to anyone!

Coming soon: A handy new application for freelancers, contractors and small businesses

Technical Services 7

Over the last few months, I've been working with Webwings to develop a new web application which we hope will save freelancers, contractors and small businesses a lot of time.

Development has been swift and pain-free thus far, due in part to the choice of CodeIgniter as the framework. It's proven to be an excellent base on which to iterate and incrementally build our product.

We have been alpha testing with a select group of users, and have received very positive feedback. We are aiming to get a beta release out within the next couple of months. If you are interested in participating in this, please leave a comment at the bottom of this page, and I will be in touch.

View carriage returns, line feeds and tabs within text files

This is a useful Python one-liner for viewing characters that are usually hidden in text files;

  • Carriage returns (shown as \r)
  • Line feeds (shown as \n)
  • Tabs (shown as \t)
python -c "f = open('filename.txt', 'r'); f.seek(0); file = f.readlines(); print file"

Example output:

['Carriage return and line feed: \r\n', 'Line feed: \n', 'Tab: \t\n']

I recently used this script when trying to work out why a shell script was not executing correctly on a Debian machine -- the reason was some carriage returns inserted by a Windows-based editor.

Securing your CodeIgniter passwords with bcrypt

Safe

I've applied a small modification to the Portable PHP password hashing framework, so it can be easily used in CodeIgniter projects. An example of using it to authenticate users:

$this->load->library( 'PasswordHash' );

    $query = $this->db->query("
        SELECT
            `user_id`,`password` AS `hash`
        FROM
            `user`
        WHERE   
            `username` = ". $this->db->escape($username) ."
        LIMIT
            1
    ");

    // check to see whether username exists
    if ( $query->num_rows() == 1 ) {
        $row = $query->row();

        if ( $this->passwordhash->CheckPassword( $password, $row->hash ) ) {
            return $row->user_id;
        }
    }

To generate a hashed password:

    $this->load->library( 'PasswordHash' );

    $password = ( isset( $_POST['password'] ) ? $_POST['password'] : '' );

    if ( $password ) {
        $hash = $this->passwordhash->HashPassword( $password );

        if ( strlen( $hash ) < 20 ) {
            exit( "Failed to hash new password" );
        }
    }

For more details, please check out the repository on GitHub: github.com/glenscott/passwordhash-ci

Going Freelance Part 4 - Finding Work

Fall 2011 Student Hackathon Coding

I recently read a blog post from Alan Hollis about his first month's experience as a freelancer. Alan asked about tips on finding work, so I've collected some together in this blog post.

I've now been freelancing for 9 months, and so far I've been successful in finding work through these avenues:

Former work colleagues

My first few clients were people that I have worked with in the past, who had gone onto set up their own businesses. I remember Tweeting about being available as a freelancer when I started, and I soon received a few enquiries about my services.

The great thing about this kind of work is that you already know your client, and they know you, so the trust is there from day one.

Networking

I've been to a few networking events, including developer meet-ups and co-working sessions. I always take my business card to hand out, and on a couple of occasions I've found new work this way. Co-working sessions, such as Jelly are more "soft" networking because you are primarily going to work, and not sell, but can still lead to new clients.

Speculative e-mails

At one point I sent out a batch of speculative e-mails to local web design agencies, highlighting how my experience may be of benefit to them. A couple of agencies got back to me straight away enquiring about my rate, and I subsequently ended up doing a couple of months work with one of them.

My own site

I have a basic page advertising my services and I have had a couple of enquiries through this. I'm currently building out a more comprehensive site for myself, but it's taking a while as client work always comes first! I reluctantly added Olark to the page to enable me to chat in real-time to visitors, and I was surprised to find someone using it to contact me shortly after I had installed it.

LinkedIn

I get a lot of enquiries from recruiters via my LinkedIn profile. Whilst a lot of these opportunities are not at all relevant, every now and again there has been an interesting contract position. Contracts are a "fall-back" option for me -- if I've not got any freelance work, then I would then consider such opportunities.

Hopefully these tips are of some help to other freelancers.

Compiling PHP extensions using Xcode 4.3 and above

Prior to version 4.3 of Xcode, Apple bundled a load of command line tools with it that are used to compile native binaries, including PHP extensions. However, as of version 4.3, these tools are not bundled by default. Therefore, if you require these tools you need to take one of two actions:

1. If you already have Xcode 4.3 installed, go into the Components tab of the Download preferences panel and make sure Command Line Tools are selected

Xcode CLI tools installation

OR

2. Download and install the command line tools as an independent package from either;

a. Apple (requires Apple ID)
b. GitHub

Once you have the command line tools installed, you are able to compile native binaries.

If you found this post useful, it would be great if you could Like my Facebook page using the button in the sidebar. Thanks!