November 11, 2009

Frames without frames. AJAH selective insertion

And W3C said Let there be frames, and frames were made, and frames were used (and abused) and all was rigth, and W3C said That was good (we're gonna deprecate them soon) and there was much rejoicing.

Is not new that web developers hate all made with frames. They're a burden nobody wants to carry, so confusing, so "nineties", so... well, deprecated, that's it. So you may think I'm just delving into the past. Frames, as we know it, are dissapearing into extinction but, the main idea, more or less, is still needed nowadays.

I'm talking about AJAH web applications. In these, the default click action is overriden with Javascript, making an asynchronous request to the URI and inserting the HTML result into a DOM object. It's simpler with a picture of a sample layout:

<h1>#Header</h1>
<u1>#Menu</u1>
<div>#App</div>

When you click on a link in #menu, you want to call the URL and set the result as the content of #application. This can be done setting the XMLHttpRequest onreadystatechange event more or less like this:

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if(this.readyState === 4 && this.status === 200) {
        document.getElementById('App').innerHTML = this.responseText
    }  
};
xhr.open('GET', url, true); // the url of the request
xhr.send(null)

Wasn't it easy? Now, if your request returns "<h2>Option 1</h2>" the content of the App DOM Object changes.

How about changes in more than one "frames"? Let's say you want to modify the contents of App and set Footer to a status text. First you must modify your application to wrap the result within the appropriate tags:

<div id="App">This must go inside the App container</div>
<p id="Footer">This is the new stats of the application, and goes into the Footer</p>

In the onreadystatechange event, create an anonymous node and set the response as innerHTML.

...
var node = document.createElement('div');
node.innerHTML = this.responseText;
...

Then, iterate over its direct children. If the child has an id, search the real DOM with getElementById, replacing the node, when found. If the child has no id or doesn't match to a node in the document, append it to a default DOM object, say body (or whatever fits).

var child = node.childNodes;
var default = document.getElementsByTagName('body')[0];
while(child.length) {
    if(child[0].id) {
        var replacement = document.getElementById(child[0].id);
        if(replacement) {
            replacement.parentNode.replaceChild(child[0], replacement);
            continue;
        }
    }
    default.appendChildren(child[0])
}

This could be achived easily with jQuery:

$(this.response)
    .filter(function(){
        var u = document.getElementById(this.id);
        return !(u && u.parentNode && u.parentNode.replaceChild(this, u))
    })
    .appendTo('body')

Nice one, isn't it?

November 09, 2009

Refactoring code smell

I work every day with PHP, developing management tools for the company where I work, but when I accepted this job I was a pure noob in this language. In fact I was hired for some C++ programming, but soon my tasks evolved so that wherever there's code, I was there too. So, learning PHP was the logical evolution in this case.

Well, my early days of PHP were all a mess of "write and test" so even the maintenance of my own code is little better than a nightmare with ninja killer rabbits. The skills take time to develop as you're learning. But then, one day, you're illuminated by finding "The Path".

Change "The Path" with functions, objects, inheritance, aggregation, design patterns, MVC, reflection... whichever fits best. It's hammer time, and everything around seems like a nail. You browse through all your finished projects, changing things to match your "new mood", so you and your (old) code are in communion. But adding no value to the old applications.

Then, one day, a new "The Path" (there's always one more) enters your life, illuminating it from another point of view, and all your code begins to smell like a horde of skunks bathing in a sewer. Face it, you've entered an endless loop. Welcome to the real world.

I've been in the programming world since 1994 and I've been hit by tons of bugs, mistakes and bad habits, some (tons) made by me, some not. While maintaining others' code, more often than not I found scripts that follow the lovely paradigm of "spaggetti code". No classes involved. Not even a f****g function. Nothing. Zero... Nada. That was GREAT.

Have you heard about the "$i++; // increases $i" comment?
I've seen one of those too. Not so funny, actually, IRL. I have no idea yet of what it does exactly.

Refactoring is the tool we need in this cases. In words of Wikipedia, refactoring is the process of changing a computer program's internal structure without modifying its external functional behavior or existing functionality, in order to improve internal quality attributes of the software. In my own words, refactoring is to improve code so you won't go crazy when adding new functionalities.

Refactoring is not a new science. I think when the first programmer had to mantain others' code, refactoring was, more or less, invented. But I think I'm right saying that it was Martin Fowler with its book Refactoring. Improving the Design of Existing Code who put more efforts to make it a standard.

From things as simple as to change the name of a local variable to as sophisticated as replacing an enum with a strategy pattern, every tool in the box exists to make your code more readable. To the extent that there is no need to comment the code: it speaks for itself.

Which of the following two do you prefer?

// Transform user input from celsius to fahrenheit
$a = f($argv[1]);
$celsius = $argv[1];
$result = convertCelsiusToFahrenheit($celsius);

This is a quite simple example. Of course, Fowler's book is tons more interesting than this, but I hope this one delves into the open wounds left by some developers. If refactoring today, spending two hours, you save three tomorrow when adding functionality, it will be worthwile.

Although I wonder if I have not found another "The Path" and all this is just another iteration of the loop.

July 10, 2009

Real IP Problem and X-Forwarded-For header

Someone has been in a situation like this? I bet it

  • We need a way to know whether a user is logged in or not.
  • Easy as pie. Go on sessions with him.
  • We can't rely on the user's browser to allow cookies.
  • Well, we rely on the user's browser to have JavaScript, so why...?
  • I said no cookies. Use the IP address.

Then the system went into production, users connected to it, they paid for the services and user's IP were logged into the server and into the database, being checked in every request he made to the server, until the server logged them out. Not perfect, you may think, and you're right, because one day:

  • We've been receiving many tickets from our users asking they want their money back
  • Why?
  • They paid for a service they never were able to enter.
  • And no error was shown? Was all in the billing system OK?
  • No error. No problem. But they were not allowed to enter the site
  • I must investigate

And later on, after mailing nearly every customer and checking every log and pinging every IP, the problem arises: Proxies.

Proxies acts between client and server in order to speed the user experience on the web. Proxies can cache, redirect to nearby mirrors, filter content, provide anonymity and intranet connectivity, and so forth.

Proxies adds a X-Forwarded-For header to the request (or updates an existing one) with the user IP and, then, after some more magic, redirects the request to the destination. Answer goes also from the server to the proxy, then it's redirected to the real end user.

So, when a request comes directly from users, 'REMOTE_ADDR' PHP var contains the user's real IP. While browsing through a proxy, the 'REMOTE_ADDR' is the proxy's IP and the 'HTTP_X_FORWARDED_FOR' contains a list of one or more IP's, one of them being the user's one.

So you make a script to get the client's real IP, like this one:

function get_real_ip(){
  return isset($_SERVER['HTTP_X_FORWARDED_FOR'])
           ? $_SERVER['HTTP_X_FORWARDED_FOR']
           : $_SERVER['REMOTE_ADDR'];
}

Not a really good one, it can be improved by filtering IPs from the forwarded list and selecting only one, but, nevertheless, all version suffer the same problem: Header injection.

What happens if somebody changes (and it's not that difficult to do it!) the headers sent to the browser?

Let's say you add a X-Forwarded-For header and set its value to some IP, maybe one you 'sniffed' from the site traffic. Now you're superseding another user! If this user buys some content, now you're allowed to get it too.

Also, if the Proxy allows anonymity, your server will receive no X-Forwarded-For header thus confusing the proxy's IP with the real one. Now, every computer passing through this Proxy can access the private content, as long as one of them purchased it.

That's not a security hole. It's a crater as big as a full moon.

So, while developing "security measures" think for yourself: Are these making the hole smaller or even bigger?

June 30, 2009

HTML Tip: Think semantics

As said in Best Practices for Building Web Applications, one of the things to have in mind when developing Web Applications (or any simple HTML website) is to Think on Semantics

HTML is for content and semantics, so, when a browser sends an HTML request, it expects to receive content. The browser does not know what information to display, so you must educate it. HTML has tags for everything is needed to learn and speak the "browser language". <p> for paragraphs, <a> for links, <ol> and <ul> for lists, <span> and <div> for custom blocks, and so on... So, semantics is to make the tags meaning to match the content inside them. Better seeing it with an example:

<div>
  <a>One Link</a><br/>
  <a>Another Link</a><br/>
  <a>One More Link</a><br/>
</div>

This can be upgraded to semantical form as:

<ul>
  <li><a>One Link</a></li>
  <li><a>Another Link</a></li>
  <li><a>One More Link</a></li>
</ul>

Not too different from the previous one, is it? Well, not for the browser, of course. There are several advantages:

  1. The browser knows how to display an unordered list. You don't have to put those ugly <br> nor special classes and CSS to have a list rendered as it's expected.
  2. Best accesibility. Imagine a special browser that allows sight-impaired people to hear the text inside the <li>'s one at a time, or to skip the entire list. For this app, the former is only a bunch of text with links on it.
  3. No bloat. As you don't need those little <br/> buddies, no code bloat is added to your HTML and it remains as it should be. Only content and related tags.
  4. Nice to Bots. This may seem rather stupid, but when a bot enters your site, it only sees pure HTML. You want Google Bot to be able to read and understand your text, doesn't you?

June 18, 2009

CSS Refresh

While developing a web application, I often need to reload a whole site for every change I do in its CSS file, only to test it.

Under Firefox I used to change the link tags href manually (well, in fact with Firebug) to add some query string, in order to by-pass the cache and request the brand-new version of the file. This job was often harder than that, since I'm still maintaining some old school applications using frames (Eek!).

While writing my jQuerify Bookmarklet I thought this CSS refresher is the perfect job for a bookmarklet, so I ended writting this:

(function(){
  var a = [];
  function f(f){
    a = a.slice.call(f.getElementsByTagName('link')).concat(a)
  };
  f(document);
  for(var i = window.frames.length - 1; i > 0; --i){
    f(window.frames[i].document);
  }
  var date = new Date().valueOf();
  for(var i = a.length - 1; i >= 0; --i){
    var s = a[i];
    if(
      s.href &&
      s.rel.toLowerCase().indexOf('stylesheet') >=0 &&
      (!s.sheet || !s.sheet.disabled)
    ){
      var h = s.href.replace(/[&?]_=\d+/,'');
      s.href = h + (h.indexOf('?') >= 0 ? '&' : '?') + '_='+date;
    }
  }
}());

The code is pretty straighforward: It collects every <link> tag in any frame (even the main one) and modifies their href with a dummy parameter. First, the script tries to remove the dummy parameter, in case it exists, and then adds the dummy parameter with the current timestamp, so no two refreshes are equal.

Now CSS refreshing is only a click away for every project. Nice!

You can download the bookmarklet dragging the next link and dropping into your bookmarks toolbar. I hope it helps you as well as it does to me!

June 04, 2009

Best Practices for Building Web Applications

If there´s something I´ve learned during my developer life, is to make a list of basic rules and to be faithful to them. These rules are the skeleton on which all my own applications shall be built. Of course, these rules also evolved as time goes by, growing stronger or falling into obsolescence, often unpredictably.

Web development is not different from C++ coding, so it also has its own ruleset in order to avoid "bad habits". In my case these are:

    HTML

  • Think semantics
  • Markup, not bloat
  • Put a DOCTYPE in your life

    CSS

  • Reset your CSS
  • Avoid "hard" classes
  • Don't hack

    JS

  • Choose your JS weapon!
  • Be gentle. Be usable
  • Progressive & Gracefull

    ALL

  • Keep them separated
  • Call the specialist
  • S is for Standards

I think they are pretty self explanatory, but I'll be digging deeper onto them in forthcoming entries.

I hope this list, at least, makes you think. Does you follow your own set of rules while developing? Why? Why not? What are yours? How they evolved?

There's no absolute answer to those question, you must be saying. And that's obviously certain as no two people are alike. Sharing our points of view would be a good way to learn from ourselves, doesn't it?

swfLink: Simple, unobtrusive, Flash embedding

Update:Now returns the resulting <object> on success

I was in need of some simple Javascript to add SWF objects. Hoping for a simple, cross-browser, ie-proof, eolas-respectful and graceful-degradable solution is a difficult praise to attend, so I began, as always, to write my own.

The routine is so simple because it does nothing more than add a <object> tag so it can embed the flash movie. No plugin or software checks. I didn`t need them.

The markup is easy as pie:

<a href="path/to/file.swf?parms" width="320" height="240">Alternate content</a>

A straightforward link to our swf, so, in non-js environments, the user can access it as well. The width and height must be specified too in order to create the <object> tag within the script.

Now the guts, the JS code to convert our links into fully-functional swf objects:

var links = document.getElementsByTagName('a');
for(var idx = links.length - 1; idx >= 0; --idx) {
  var item = links[idx];
  if(/\.swf[$?#]/.test(item.href)) {
    swfLink(item.href, item, {
      width: item.getAttribute('width'),
      height: item.getAttribute('height')
    })
  }
}

All it does is to get all links and filter the ones not corresponding to swf files. The /\.swf[$?#]/ regex is responsible for this to happen. You´re allowed to change that and make it more secure, but, for now, it fits my needs.

Next we move into the details of the swfLink script.

function  swfLink(url, elm, opts, parms) {
  // Default values
  opts = opts || {};
  parms = parms || {};
  !opts.type && (opts.type = 'application/x-shockwave-flash');
  !parms.allowscriptaccess && (parms.allowscriptaccess = 'always');
  !parms.wmode && (parms.wmode = 'transparent');
  // Checks for IE
  if(!+"\v1") {
    opts.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
    // Split URL onto movie and flashvars params
    url = url.split('?');
    parms.movie = url[0];
    url[1] && (parms.flashvars = url[1]);
  } else {
    opts.data = url;
  }
  var result = ['<object'];
  // Add options as object attributes
  for(var idx in opts) {
    result.push(' ', idx, '="', opts[idx], '"');
  }
  result.push('>');
  // Add params
  for(var idx in parms) {
    result.push('<param name="', idx, '" value="', parms[idx], '"/>');
  }
  result.push(elm.innerHTML, '</object>');
  var cont = document.createElement('div');
  cont.innerHTML = result.join('');
  // Replace source link with embedded object
  elm.parentNode.replaceChild(result = cont.firstChild, elm);
  return result
}

As you may note, I´ve used the 7 byte IE detection script in order to detect our natural enemy. The code is pretty straighforward, I think. It does only what it needs to be done.

I hope this helps somebody. At least I enjoy coding it.

How boring life would be without IE spicing up our coding time...