boogdesign blog

Web design, web development, standards compliance, Linux, events I went to related to that, and random things I found on the internet.

Rob Crowther, London, UK based Blogger, Web Developer, Web Designer and System Administrator - read my Curriculum Vitae

Buy my book!

Book CoverHello! HTML5 and CSS3 available now

Buy my other book!

Book CoverEarly access to HTML5 in Action available now

05/03/08

01:00:46 am Permalink Planning a Semantic Web site

Categories: Web, Blogging

I've been published by someone other than myself! Read my introductory article on applying Semantic Web technologies to your website on IBM's Developerworks site. Although it's mostly my own words, I had a lot of help from the guys at Backstop Media, who were great. This was an interesting experience for me, from frantic writing into the early hours of the morning to being interviewed through my mobile while standing in a fire escape stairwell. I was kind of nervous about the whole thing, but got great support all the way through.

If anyone's followed the link from the article back to here, then welcome! Please feel free to let me know what you think in the comments to this post (they're moderated, but I check a couple of times a day). In the meantime the potential influx of visitors is motivation for me to complete all those half finished posts I've got lying around from the last five or six months and try and look like less of a slacker :)


Tweet this!
1 feedback »PermalinkPermalink

04/03/08

06:17:02 pm Permalink Google Gears on Mobile Devices

Categories: Technology News, Web

Web as ubiquitous computing platform got a boost today as Google announced a version of Gears for Windows Mobile 5 and 6 devices. Google Gears is a browser extension which lets web applications work offline, which is a crucial requirement if you're planning on doing any serious application for a mobile device where the connection is likely to drop in and out relatively often (compared to your desktop PC). It's a shame that they've not started with Symbian, the most widely deployed smartphone OS outside of the US, but hopefully they'll get to it shortly.

And while on the subject of Symbian based OSes, Microsoft also made an announcement in the mobile device space today - they have agreed with Nokia to write a version of Silverlight for Series 60 (which is Symbian based) phones. I admit I hadn't really taken Microsoft's 'cross platform' claims for Silverlight that seriously up until now, because they weren't even as 'cross platform' as Flash, which is hardly the gold standard, but a few more announcements along these lines and they might convince me.


Tweet this!
Send feedback »PermalinkPermalink

03/03/08

11:37:49 pm Permalink Fixing Jack's formmail.php for register_globals = off

Categories: Server Side Web Development

For many years now, I've used various versions of Jack's FormMail.php to handle simple form submissions on various websites, mostly 'contact us' forms. The script has gotten a little more sophisticated with time, but it's still one of the simpler ways of making a website 'interactive.'

The website at work uses it to send the marketing department emails when someone fills in the contact us form. The form is somewhat sophisticated, in that it presents different information depending on a few parameters in the URL, and passes formmail.php a different subject for the email depending on what configuration it's in. It also passes a redirect URL in a hidden field, so the user is redirected to a 'thanks for contacting us' page after submitting the form. Google Analytics is set up so that any hits on the 'thanks' page after viewing the contact page counts as a Goal. And this is where I spotted the problem - as I checked through the Analytics stats I noticed we hadn't achieved any goals since the middle of last week, although a day or two here and there without any is fairly common five on the trot is pretty rare.

My first step was to go to the contact form and try submitting it, the email duly arrived in the correct mailbox but the script didn't redirect to the thanks page. So first mystery solved, no hits on the thanks page means no goals on Analytics, but the marketing department hadn't noticed because they were still getting emails. I messed around with some of the different configurations of the contact page but none of them redirected as intended. Then I realised that all the emails had the same subject, and that was the default one given by formmail.php when it doesn't get passed a subject, though the values in the form fields were appearing in the email correctly, so it wasn't like the information wasn't getting passed though.

I checked the web host's page and discovered that they had recently updated the PHP config on the server, this in order to support PHP v5. There was a new option in CPanel to select the default version of PHP, so I went and set it to v4 in case formmail was incompatible with the newer release. It didn't make any difference though, so I started looking at formmail.php itself in detail.

The first thing I noticed was that the redirect functionality required register_globals to be enabled. Although my PHP configuration page claimed that register_globals was enabled, the behaviour of the script indicated that it wasn't. Unsurprisingly, the subject field also expected register_globals to be enabled, as did several other fields which I wasn't using, but the code which builds the email uses $HTTP_POST_VARS so works fine without.

If you've managed to read this far without falling asleep and you know what register_globals is, then you now have enough information to fix the problem yourself and there's no need to torture yourself any further. If you currently have no idea what I'm on about, I'm now going to try and explain and then show you how to edit your script to fix the problem. register_globals is a configuration setting for the PHP interpreter, if it's set to on then PHP will helpfully make any parameters passed into the script global variables. Parameters are the bits in the URL after the question mark, or fields in a form. This can be quite handy when you're slapping together a quick script, but is also very dangerous because, if you're not careful, you can create easy opportunities for hackers to do nasty things. For this reason, register_globals = on has long been discouraged in the PHP community, unfortunately many useful scripts were written in the days before anyone realised it was an issue, so web hosts usually provide a way turn it back on even if it's not enabled by default.

However, today we're going to make formmail.php work properly with register_globals = off. You're going to need to open the formmail.php script in a text editor - Notepad will do fine. First we shall fix the redirect issue, find the following lines near the end of the file:

if ($redirect) {
   header("Location: $redirect");
   exit; 

We're going to replace $redirect, which is trying to access the global variable, with $_POST['redirect'], like so:

if (isset($_POST['redirect'])) {
   header("Location: ". $_POST['redirect']);
   exit;

The same trick works with the subject and email address, scroll up a few lines and find this:

mail_it(stripslashes($content), ($subject)?stripslashes($subject):"Form Submission", $email, $recipient); 

Replace it with:

mail_it(stripslashes($content), isset($_POST['subject'])?stripslashes($_POST['subject']):"Form Submission", $_POST['email'], $recipient);

Now upload your new version to the server and you should find things start working as before. As you can see the general rule is to replace $variable with $_POST['variable'], notice that I didn't change $recipient because I always hard code that value at the top of the script as a security precaution.


Tweet this!
59 feedbacks »PermalinkPermalink

21/01/08

11:41:55 pm Permalink Web Development for the Blackberry Pearl

Categories: Usability & Accessibility, Front End Web Development

We had a potential client which wanted to use our web application on their Blackberry Pearl devices. I figured "How hard can it be?", downloaded an emulator and got cracking :) I wanted to make the standard pages support the Pearl, I didn't want to write a whole new web app, without changing how they worked on desktop browser to avoid confusing existing customers.

The tips below are things I specifically ran into on the Pearl, I imagine they'll apply pretty well to any low end mobile browsing device.

Tables make layout inflexible - the Blackberry has a fairly narrow screen when compared to a desktop. If your form laid out is in a table which is several hundred pixels wide the chances are it's not going to fit in the width. Since your page is most likely already too long for the display this is going to leave users having to scroll in two axes to complete the form. To avoid this I changed all the forms I expected to get used on the Pearl into a tableless layout which then used CSS to achieve the same display on the desktop, and then add a mobile stylesheet to override this:

<link rel="stylesheet" href="style/handheld.css" media="handheld" type="text/css">

This meant they lay out in a grid on a desktop browser but in a linear column on mobile devices

No javascript by default - the web app I was working with has been in production for more than five years, so it has it's share of hairy code particularly in the javascript department - a mixture of inline and external. One of the main issues for me was that so much of the supporting functionality depended on JS - for instance the search form could be filled out and submitted, but the functionality for scrolling through the results depended on onclick events on buttons. I re-wrote the forward and back buttons to be wrapped in little forms of their own which submitted to the correct URLs to solve that fairly easily (and that worked just as well for full desktop browsers too).

The more difficult situation was the input form, which, although it allows free text input, also allows you to select from a list of available options. Unfortunately the way this has always worked is for users to click on a button which launches a pop-up window, then double click on the item they want out of the resulting select list. The value is then inserted into the main form and the window closed, and the whole process is driven by javascript.

So, obviously it's not going to work at all without any javascript. I should point out this represents a bad design decision, I should have started with a form which worked without javascript and layered the enhanced behaviours on top (a technique known as progressive enhancement, but way back when the decisions were made I didn't know any better and neither did anyone I worked with. So I was re-writing the page in my ASP era web app, but I wanted to keep visually identical (close enough, at least) to the previous version. Here's an example of what the form components looked like before I started (names have been changed to protect the innocent):

<tr>
<td>
  <input class="standardWidth" value="Service Group" onclick="openPopup('Default.asp?WCI=listItems','PopUp','300','680');" type="button">
</td>
<td>
  <input autocomplete="off" name="txtITEM" id="txtITEM" size="25" maxlength="20" title="Click button to display list" value="" type="text">
<div style="display: none;" class="auto_complete" id="txtITEM_complete">
</div>
<script type="text/javascript">
new Ajax.Autocompleter('txtITEM', 'txtITEM_complete', 'Default.asp?WCI=listItemUL', {minChars: 2});
</script>
</td>
</tr>

A quick note here so you don't get lost - I'm using scriptaculous for the auto complete, openPopup is a fairly standard popup function, all the server side functionality is encapsulated in a WebClass, basically a VB6 DLL embedded in an ASP page, so different pages are called up by varying the WCI= parameter.

After I'd switched to a tableless layout (see above), my first step was to comment out all the javascript, this broke everything &amp;#58;&amp;#41; Next, I changed the input element to be a submit. Every button on the form would submit it and I planned to then detect which button had been clicked on the server side. This is relatively straightforward, just give all your submit buttons a common name (but a unique id so you can reference them individually in script):

<div>
    <span class="colLeft">
        <input type="submit" name="butLogForm" id="subITEM" class="standardWidth" value="ITEM">
    </span>
    <span class="colRight">
        <input type="text" name="txtITEM" id="txtITEM" size="25" maxlength="25" value="" title="Click button to display list">
    </span>
</div>

Then, on the form target page you check the value of butLogForm, so in VB6/ASP it's Request( "butLogForm" ), and its value will be the whatever you assigned to the button which was clicked (ITEM in the above example). So if a button other than the 'main' submit button has been pressed it's easy to detect this and redirect to the appropriate selection page for the field (which would be the same page as was originally appeared in the popup window summoned by clicking the button). I then added some plumbing to direct the popup page to either submit the value as a form or populate with javascript into opener depending on how it was called and to capture all the values behind the scenes once the user had selected them.

So now the form worked fine with javascript disabled, the only task left was to make it work as it did before in a desktop browser, popup windows and auto-completes, when javascript was enabled. This was slightly complicated by the need for the javascript to know the URLs for all the pages, and these could be changed at runtime, so I decided to pass them all in as parameters to the onload function (there is a URLFor) utility function available within the webclass which calculates them). To reduce the number of URLs to be passed in I used a naming convention so that the URL for the auto-complete function could be easily generated from the popup URL by appending 'UL' to it:

if ($('subITEM')) {
    $('subITEM').onclick = function () {openPopup(urlITEM + '&IsForPage=Log','PopUp',width,height); return false;};
    if (!$('txtITEM').readOnly) {
        var elTxtITEM = $('txtITEM');
        acDiv = document.createElement('div');
        acDiv.className = "auto_complete";
        acDiv.id = "txtITEM_complete";
        elTxtITEM.parentNode.appendChild(acDiv);
        new Ajax.Autocompleter('txtITEM', 'txtITEM_complete', urlITEM + 'UL', {minChars: 2});
    }
}

The code is fairly simple. First I check to see if the relevant submit button actually exists (there are configuration settings in the app to turn each field on and off) and, if it does, adds the old popup code to the button. Next I check to see if the text field is editable (another configurable option) and add both the div required by the Ajax.Autocompleter and then initialise the control itself.

The <button> element is useless - well it might not be completely useless, I didn't try too hard, but I decided I was only using it in the first place to show off my l33t HTML skills so I just switched them back to regular input elements.

No CSS by default - the browser on the Blackberry Pearl will not use CSS by default, though you can change the configuration to enable it and it will then respect the mobile stylesheet. The main problem this posed for me was that, in a lot of places, I was relying on padding and borders to provide spacing between text elements, eg:

<div><span><strong>Status:</strong></span><span>Active</span></div>

So when CSS is turned off you end up with tall the text running together with no spaces in between, making it hard to read. Since in this situation it's impossible to control the presentation with CSS I resorted to using markup for it and added &nbsp; glyphs inside the spans in every place where the text needed a space.

Turning on javascript leads to memory errors (slowly) - just like CSS, the browser on the Blackberry Pearl will not use javascript by default. This leads to the issues I already covered above, but a more amusing issue occurs if the user happens to enable javascript. The Pearl is a low memory device, even compared to other smart phones, and if your web app has several hundred kilobytes of javascript for it to download it will use up all of that memory in a vain attempt to parse the file. Since all the javascript gets downloaded in a standard header this led to a long wait and then an error message when you even tried to access the login page on my app. I made an extremely cut down javascript file, basically the standard field validation and date formatting functions, the openPopup function and some empty function stubs for all the onload functions (to avoid error messages). Since I didn't have the time or resources to implement WURFL or DeviceAtlas and this is only ever likely to be used in controlled corporate environments, I made a user configuration setting in order to send the cut down version to the Blackberry instead of the regular JS .

Only onchange on inputs, no onblur or onfocus - the final thing that caught me out was to do with my validation and formatting helpers on text inputs, these were all hanging off onblur and were not getting fired on the Pearl. The quick solution was to change everything to onchange instead, though the reason I'd used onblur in the first place was because I'd experienced some unreliability in the desktop browsers so this was not ideal. Unfortunately I had to wrap up this project before I had chance to get into it in more detail.


Tweet this!
Send feedback »PermalinkPermalink

25/11/07

10:37:40 pm Permalink DDD 6

Categories: Web Develop

Review: DDD6 at Microsoft UK Campus, Building 3, Thames Valley Park, Reading, Berkshire. RG6 1WG. 08:45 to 17:00

I'm more of a web developer than a 'Microsoft developer', but I use a lot of the MS stuff at work and I really enjoyed WebDD last February so I thought I'd give the more .Net focussed parent event a try.

Why IronRuby? (Presentation) Dave Verwer - I'd been to a couple of Dave's talks at the WebDD event and enjoyed them tremendously, so I went in to this one with high expectations. The talk started with some of the benefits of Ruby - a dynamic language with elegant syntax designed for simplicity and productivity, before going on to discuss how IronRuby and the DLR are implemented in .Net. The DLR is basically a layer for dynamic languages on top of the standard CLR, it is an abstraction of the what was developed in the course of getting IronPython up and running. At this point Dave admitted that IronRuby wasn't yet ready for use, so the rest of his talk would be about (C based) Ruby 1.8 - which IronRuby is targeting for compatibility. This was a bit of a disappointment for me, because really I was after a more practical demonstration of IronRuby than another presentation on Ruby - but it's possible I was in the minority given the audience. Check out the IronRuby website if you want to learn more.

Entity Framework (Presentation) James Winters - I had no idea what this was before the talk, but the title sounded more interesting than the others available in this slot, and it saved me leaving the room when I knew I wanted to see the talks either side. In the event, I was glad I stayed. To give a simple sound bite - Entity Framework is like an ORM on steroids, which will allow transparent mapping to non-relational stores, such as LDAP, as well as the more usual SQL stuff. The plan is for all MS server products to move to Entity Framework for their data access, though at the time of the talk the only backend available was SQL Server and all the examples were basic ORM stuff. The logical model of Entity Framework is made up of three levels:

  • O-SPACE - the object model, eg. LINQ
  • C-SPACE - the conceptual model, eg. Entity Client
  • S-SPACE - the store - eg. ADO.Net.SqlProvider

All levels are scoped by an entity container, which defines a namespace and an object model, and the goal of the MS Visual Studio team is to be able to generate the lower levels using visual tools.

Entity Framework supports multiple querying methods:

  • ESQL - very similar to HQL in Hibernate
  • Object Query - a generic object interface with caching and lazy loading, which can either be read only or mergeable
  • Use Entities directly
  • LINQ

There are some limitiation, there is no locking by default and, while it's going to be possible to map stored procedures the visual tools aren't going to support it for some time so you have to write up the XML manually. Generally, though it has a slight whiff of the architecture astronaut, it looks like an interesting addition to the .Net toolbox (Slides available here).

Why do I need an Inversion of Control Container? (Presentation) Mike Hadlow - I'd heard of Inversion of Control (IoC), but hadn't really understood what it was for. The presenter, Mike, had been in a similar position until he started studying it seriously, and now he was here to share his epiphany. The main problems IoC is trying to address is that the relationship between component size and complexity is not linear - double the size of your components and you quadruple the complexity - but breaking components into smaller pieces tends to lead to increased dependencies. Inversion of control reduces the complexity of large components and manages the dependencies between them. The principals of inversion of control (paraphrased from Robert Martin) are:

  • High level modules should not depend on low level modules
  • Abstractions should not depend on details
  • Details should not depend on abstractions
Typical problems of OO code without IoC are:

Inversion of control helps with all these by allowing constructor injection and property injection. If these can be injected into components at runtime, rather than hard-wired into the components, then it becomes possible to modify the behaviour of components without having to modify the components thus satisfying the open/closed principal and reducing the coupling (property injection) and also to easily mock objects for unit testing (constructor injection). Mike then moved on to some detailed demonstrations using the Windsor component from the Castle project, before concluding that IoC is really just the thorough application of design patterns and other OOP best practices. Therefore you should only start considering inversion of control once you're already familiar with these and have already implemented things like unit testing (Slides available here).

Dynamic Languages on .NET (Presentation) Michael Foord - My first session of the afternoon and by this point I was flagging a bit after having to get up early and make the trip out to Reading. Michael is one of the authors of Resolver, a spreadsheet based application environment, aimed at the financial markets and written in IronPython. The app is approximately 30000 lines of code, thus refuting the myth that it's impossible to write large applications in a dynamic language, and it's spreadsheet model is implemented in a Python hash table, making it very easy to extend Resolver with new types and operators. After a discussion of what constitutes a 'dynamic language' and the overall benefits of Python and IronPython in particular, Michael moved on to some practical examples based on his IronPython Web IDE (Slides available here)

Testing Your Applications With MbUnit Gallio (Presentation) Ben Hall - unit testing is a popular topic on programmer blogs these days, and this was reflected in a fairly full room for one of the 'minor' talks (ie. we weren't in one of the big rooms). Ben covered some best practices of automating unit testing on .Net with MbUnit and Gallio, starting at the database layer (use transactions and rollbacks or COM+ transactions), the business object layer (mocking and inversion of control) and the user interface (don't try and automate it!). An interesting if slightly hurried talk which I was unfortunately too tired to pay full attention too (Slides available here)

Overall a good day, I definitely learned more than one new thing per talk and the Microsoft conference room facility is a good venue for these sorts of things, so 4 out of 5, and I'll almost certainly try and get to the next one.

Technorati tags for this review:  

Tweet this!
Send feedback »PermalinkPermalink

16/11/07

07:32:19 pm Permalink IE6 & 7 Up/Down Keypress Issues with Ajax.Autocompleter in Scriptaculous 1.8.0

Categories: Front End Web Development

I started a new project at work today, adding some ajaxy interactivity to a slightly long in the tooth web application. In a previous iteration I'd plugged prototype.js 1.5.1 into this app, now I wanted snazzy effects and autocomplete fields. Figuring it was a good time to move up to the latest version of scriptaculous, I downloaded the recently released 1.8.0 version (which includes prototype 1.6.0).

I had to do some hacking around in my 'legacy' javascript to get things working in Firefox (that's how long in the tooth this application is), and then I added my Ajax.Autocompleters, got my afterUpdateElement callbacks working and was starting to feel generally quite chuffed with myself at how well it was all going. Then I thought I'd give it a quick check in IE...

In IE7 the up and down arrows didn't scroll up and down the autocomplete list, which made the whole thing kind of useless. A quick check in IE6 confirmed the same issue there, so I immediately resorted to Google. Unfortunately the answer wasn't immediately apparent in the search results and it was only when I started searching the Ruby on Rails Trac directly I finally homed in on the answer. Hoping that I can help future searchers home in on this more quickly, here's the defect: "some keypress events don't work in IE6/7"; and here's the fix.


Tweet this!
1 feedback »PermalinkPermalink

27/10/07

01:03:38 am Permalink GMail now available via IMAP

Categories: Technology News

Following up on the increased storage (now over 4Gb) and the improved support for mobile phones, this week Google rolled out IMAP support for Gmail. I access all my other mail accounts through IMAP, so I don't need to be convinced of the benefits - mostly (for me) a consistent view of your entire inbox (including sent items) across all the mail clients on all the different PCs I use to read my email (currently six, and now my mobile phone). If you're not so sure, try reading "Why IMAP is better than POP" or "POP vs IMAP for Inboxes."


Tweet this!
1 feedback »PermalinkPermalink