New Zealand's new Copyright Law presumes 'Guilt Upon Accusation' and will Cut Off Internet Connections without a trial. Join the black out protest against it!

FogBugz “Active Project” notification tool

At Turboweb we’ve recently subscribed to a 5-user on-demand license for an awesome case tracking system called FogBugz.  For us it means that we have controlled workflow of cases (bugs, features, enquiries etc.) along with awesome estimation reporting and time tracking.  FogBugz was built with development teams in mind and it’s a very nice tool.

Anyway, one of the things it has is a nice API which you can use to interrogate the product (read and write) and this got me thinking about how I could use the API to remind me what I should currently be working on.  Thus was created the “FogBugz Notification Tool”.

This script does the following:

  1. Connects to your FogBugz installation
  2. Runs a query to see what things have been worked on today
  3. If there are any items that don’t have an end date, then it’s the case that’s currently being worked on
  4. Get the details of the case
  5. Use notify-send to pop up a notification bubble showing case number, title, estimated time and time remaining.

FogBugz Active Case Notification

I have found this most effective if I put it in my crontab to run every 5 minutes.

Requirements:

  • Ubuntu Linux (or any version of Linux that supports the “notify-send” command)
  • PHP5 CLI (simply because this script is written with PHP)
  • The “libnotify-bin” package (this provides the “notify-send” command, try “sudo apt-get install libnotify-bin”)

The script requires a little configuration for your circumstances, but this is easily done by editing the defined constants in the script:

	// Adjust these defines to suit your installation
	define( 'FBBASEURL', 'https://mywebsite.fogbugz.com/' );
	define( 'FBUSERNAME', 'my@email.address.com' );
	define( 'FBPASSWORD', 'mypassword' );

And to add it to your crontab, simply add this line (note the */5 means every time the current number of minutes in the hour is evenly divisible by 5)

*/5 * * * * DISPLAY=:0.0 /usr/bin/php /home/bob/fogbugz-notify.php

Of course, adjust the path appropriately.

Changing the location of your working copy with Subversion

svnSubversion is a popular version control system that will allow you to keep track of any changes to any files (normally text files or source code). If you’re a developer and you’re not using a version control system it’s kind of like being dragged behind a Jeep instead of driving it, except you don’t realise that’s what’s happening.

Anyway, when using Subversion you “check out” from the repository your own “working copy” of the code. This is where you then make your changes before either reverting them (throwing them out) or committing them (storing them in the repository as the latest version).

There may be situations where the location of the repository (which is usually specified as a URI) may change, and you would prefer to keep your working directory intact rather than having to check out a fresh copy from the new URI.

This is easy enough to do with the “switch” command, like so:

  1. Start a shell and change into the working directory that you’re using, e.g. cd /home/bob/projects/myproject
  2. Issue the svn switch command, with the –relocate option, followed by the old URI and the new new URI, e.g. svn switch –relocate http://hostname.com/svn/myproject http://newhostname.com/svn/myproject

In my particular case I had checked out a working copy from a subversion repository available on my LAN at my workplace, but then when working remotely I could not update or commit files.  The repository is accessible remotely however via HTTPS.  Even though it’s the same physical repository, the URI that I access it by had changed so my command was:

svn switch --relocate http://ace/svn/myproject https://work/svn/myproject

To find the URI of your current working directory, use the “svn info” command and look for the Repository Root:

bob@bob-laptop:/var/www/myproject$ svn info
Path: .
URL: https://work/svn/myproject
Repository Root: https://work/svn/myproject
Repository UUID: a13b7e41-fee6-4c75-a229-83425febcc85
Revision: 498
Node Kind: directory
Schedule: normal
Last Changed Author: bob
Last Changed Rev: 498
Last Changed Date: 2009-11-30 14:01:35 +1300 (Mon, 30 Nov 2009)

CodeIgniter – Form Validation and Optional Fields

I’ve been doing a bit of work lately with CodeIgniter.  It’s been OK but the framework seems quite wrong in most places.  My main gripe is that the “helpers” define themselves as functions in the global namespace (rather than as objects that hook into the CodeIgniter object) which results in some stupidity like a function called “set_value” which just happens to retrieve the value as validated by the form validation “helper”.  Anyway, that’s a lesson learnt.

I’ve been trying to get the form validation to allow me to use set_value for fields that aren’t required, but unless your rules specify the field and a validation rule for it the value won’t be available when set_value is called.  The trick here is to use “echo” as the rule which means that the validation passes and you get back what you put in.  This is not documented in the CodeIgniter manual (it’s implied by the fact that you can use any PHP function as a “rule”).

Example:

$rules = array(
  array(
    'field' => 'name',
    'label' => 'Name',
    'rules' => 'required'
  ),
  array(
    'field' => 'nickname',
    'label' => 'Nickname',
    'rules' => 'echo'
  )
);
 
$this->form_validation->set_rules( $rules );

In this case any calls to set_value(‘nickname’) will return the correct value, rather than an empty string.

Web 2.0 Reflection using HTML and CSS only

You’re most probably familiar with the Web 2.0 reflection technique.  This technique is used to make products appear as if they’re on a shiny surface.  Apple most probably have it in use in their current campaign on the Apple website.

I was thinking about this technique as it can be quite fiddly to put together.  Normally you would use Photoshop or The Gimp or Inkscape to apply a gradient to an existing image, and then save that image as a seperate one, making sure you keep your original should you need it.

I then realised that by using a combination of CSS background images, background-position and opacity you could reproduce this effect purely with HTML and CSS.  I’m yet to wrap up the finer points but here’s the idea.

  1. Include your image on the page with an <img …/> tag as per usual.
  2. Underneath the image, include a number of 1px high empty <div> tags.
  3. On each div tag, set the background-image to be the same as the image referenced in step 1, set the background-position such that the 1px high div is displaying the correct row from the image, and set the opacity such that it fades out a little more on each subsequent div.

This image illustrates the effect up close:

My concerns at this point are:

  1. What effect will this technique have on older browsers?
  2. How will this break across browsers? (I’m assuming it won’t be perfect)
  3. The extra HTML for one image is maybe acceptable, but many images on a page would significant slow down load time for the sake of some shine
  4. What effect – if any – will this have on SEO?

I’m considering writing a jQuery plugin that you could use to apply this technique.  You can see the technique in actual use on this page.  View the source code to see how it’s done.

Installing MagentoCommerce – problems

MagentoCommerce

MagentoCommerce is an open-source enterprise level ecommerce system suitable for high end ecommerce websites. We’re in the throes of developing a large solution for a local company, and the developers involved in provisioning the site are installing local copies of Magento on their Apache servers to test with.

Here’s a list of issues that I’ve come across with installing Magento, and how I’ve solved them. For the record I’m using Magento 1.3.2.2 (released 19.07.2009)

1. Can’t get past the second install step

This is the step that asks you for your database password. If the database you’re specifying doesn’t exist then you can’t proceed. I’m sure there’s a bug here because it’s like an error message isn’t displayed. Would love to dig into this but our project is on a tight time frame. MAKE SURE YOU CREATE THE DATABASE YOURSELF FIRST (no tables required).

2. Can’t log in after installation

If after logging in you go to the /admin directory and you can’t log in, it’s probably because of the URL that you used to install it. I tried installing it to http://localhost/, http://127.0.0.1/ and http://192.168.2.10/ (my IP) all with the same result. After googling it seemed to be something to do with Magento refusing to set a cookie for a top-level domain (or somesuch). Workarounds are to use a host name that has a dot in it, e.g. http://localhost.localdomain/ (or in my case, http://bob-desktop.local). Add this to your hosts file, you may have to restart your browser for it to pick it up.

3. Firefox keeps asking you to download a PHTML file.

After doing a completely fresh install of Apache2, PHP5, mysql, Magento etc on a fresh machine (Ubuntu 9.04, Firefox 3.0.11) Firefox kept asking me what I wanted to do with the PHTML file when accessing the freshly untarred Magento directory. It took me ages to find an answer to this, but it was as simple as clearing your cache in Firefox. I dicked around with the Apache configuration, permissions, .htaccess files etc and finally found a comment about the Firefox cache.

4. AllowOverride All

Magento uses a .htaccess file in the root directory. I noticed that the default for /var/www is AllowOverride None which prevents Apache from looking at the content of .htaccess files. While this didn’t cause me trouble, I did set it to “AllowOverride All” while trying to solve #3. The file is /etc/apache2/sites-enabled/000-default, line 11. Note there may be security implications of doing this if you’re the administrator of a shared hosting environment and as such you should read about the AllowOverride directive.

Installation requirements:

From a stock Ubuntu 9.04 machine I had to install the following packages to support Magento:

  • libapache2-mod-php5
  • php5-curl
  • php5-mcrypt
  • php5-mysql
  • php5-gd
  • mysql-server

Also, I have this command on standby to reset the Magento environment back to scratch (deletes the magento directory, drops the database, untars the source file and creates the empty database again)

cd /var/www ; rm -Rf magento ; tar xvfz /home/bob/magento-1.3.2.2.tar.gz ;
   chmod -R a+rw magento ; mysqladmin -uroot -proot -f drop magento ;
   mysqladmin -uroot -proot create magento

That’s all for now.

Screen scraping with jQuery

jQuery logoDuring the course of my job I often find myself faced with the task of migrating information from an existing website to our own content management system.  In the past my approach to this task has been to assess the source code of the existing site and see whether it’s feasible to use a combination of curl, regular expressions and string manipulation.  Sometimes this is straightforward but increasingly this method is becoming less and less viable as it’s too intensive.

I’ve been using jQuery a lot recently and it occurred to me that I could use jQuery’s selectors to target the information that I’m interested in a web page, and then using Ajax POST it to my own script that would be ready waiting to then do something useful with the data, e.g. validate it and save it in a database.  For educational purposes I was keen to keep this completely client-side if possible (except for a script to receive the information).  See later on for a server-side solution.

The situation I was up against was a page that had a heap of data in a table (about 90 items), but the table was interspersed with random images to split it up and make it more pleasing to the eye.  Fortunately for me, all of the data that I wanted was neatly wrapped in <div class=”information”></div> tags.  Selecting these div tags with jQuery is really easy by using $(‘div.information’).

My first problem was that in order to use jQuery, the web page you’re looking at has to be using it.  Fortunately there’s a quick bookmarklet called jQuerify that allows you to load jQuery onto any web page.  Once you’ve got that then you can write further bookmarklets of your own to do stuff.

So, my evil evil plan was to combine a jQuery selector, jQuery’s each() construct, and jQuery’s ajax support to post the content of each div to a “scraper” script, like so:

$('div.information').each(function(){
  $.post('http://localhost/scraper.php',{
    data: this.innerHTML
  });
});

I loaded my source page, clicked the jQuerify bookmarklet and then pasted the code above into the Firebug console (what, oh you’ll need that…) and it was flawless … except that the browser security model stepped in and prevented the ajax call because the XHTTPRequest object is not allowed to post information from one domain to another.  I was stuck – I googled around for a while looking for workarounds, and investigated the use of JSONP but the transport method seemed more weighted at retrieving information rather than posting it.

So, I was stuck with a simple question: “How can I get information from one site to another by using the browser?” – the simplest answer to this question is of course to have a form on the source website, that when submitted posts to the target.  Thanks to the power of JavaScript, modifying the DOM of a loaded web page is a doddle.  Therefore it should be simple to create a form on the page after it has loaded (client side, remember), create and populate some form fields with data and then submit the form to my scraper script.

Suddenly my intentions had outgrown a bookmarklet, but I would still need one for jQuerify and one for my “Scraper Utils”.  My new bookmarket simply asked jQuery to load a local JavaScript file in exactly the same was that jQuery was loaded in the first place:

javascript:$.getScript('http://localhost/scraper.js');

Now I had the freedom of writing chunk loads of stuff in my local scraper.js file.

Scraper = {};
Scraper.createForm = function()
{
  var form = document.createElement('form');
  form.setAttribute('method', 'POST');
  form.setAttribute('action', 'http://localhost/scraper.php');
  document.getElementsByTagName('body')[0].appendChild(form);
  return form;
}
 
Scraper.createSubmitButton = function()
{
  var button = document.createElement('input');
  button.setAttribute('type', 'submit');
  return button;
}
 
Scraper.createFormField = function(name)
{
  var field = document.createElement('textarea');
  field.setAttribute('name', name);
  field.setAttribute('rows', 10);
  field.setAttribute('cols', 50);
  return field;
}		
 
var ScraperForm = Scraper.createForm();
$('div.information').each(function(){
  var field = ScraperForm.appendChild(Scraper.createFormField('data[]'));
  field.value = this.innerHTML;
});
// Create a field that we can post with:
ScraperForm.appendChild(Scraper.createSubmitButton());

You can see here that I’ve set up a few functions, createForm(), createFormField(), createSubmitButton() and then at the bottom I wrap them all together with the $(‘div.information’).each(…) construct.  The end result of this is that when I click my bookmarklet that includes the scraper.js script, a form is created at the bottom of the page and a textarea for each div.information is created that holds the innerHTML from that div.

Then, by clicking the Submit button, the browser posts all of that information across to http://localhost/scraper.php where I then collect the information from $_POST['data'] and poke it into a database.

It’s pretty rough and ready but could easily be extended to do other things like allow you to specify the selector and target URL for the post when you click the Scraper bookmarket.

Server Side Solution

On my travels I also came across the “PHP Simple HTML DOM Parser” which claims a similar ability like so:

// Create DOM from URL or file
$html = file_get_html('http://www.google.com/');
 
// Find all images
foreach($html->find('img') as $element)
       echo $element->src . '<br/>';
 
// Find all links
foreach($html->find('a') as $element)
       echo $element->href . '<br/>';

You can get a hold of this from Sourceforge at the PHP Simple HTML DOM Parser website.

WordPress Themes