Coding Tips

In the course of our various projects we occasionally encounter requirements which
dictate original approaches. We publish these code examples in the hope that others
may use them to improve the performance of their sites, and to improve the quality
of service on the web in general.

In the course of our development work, we rely heavily on the work of others to
improve the efficiency and portability of our code, and we strongly endorse the
open-souce community for the improvements they have brought to the world of
computer services.

Javascript Tips

Javascript has become the scripting language of choice for we browsers since standards are almost universal.

Javascript and AJAX: clean degradation

AJAX (Asynchronous Javascript and X(HT)ML) is a wonderful method of making pages more responsive for sites which require small changes in content. However there are two serious drawbacks.

  1. Browsers with javascript disabled are unable to navigate the site, and
  2. Search engines are unable to index the site.

Current web philosophy dictates that the pages should degrade cleanly into a form which does not require javascript, although some page designers will include the ultimate insult:

        <noscript>This site requires javascript.</noscript>

In our practice, we reverse the paradigm, and serve the site in a javascript-disabled form. If javascript is enabled in the browser, we change the menu links dynamically to permit AJAX to be used. Otherwise the site will behave as a standard html-encoded web site.

The document body is coded with a javascript onload procedure:

        <body onload="fixAnchors();">

and the following script walks the necessary portions of the document to change the links to a form which allows AJAX to be active using onclick functions:

function fixAnchors() {
  var menudivs = ['head','c1','c2','c3','tabs','foot'];
  for (var i=0; i < menudivs.length; i++){
    var menuElement = document.getElementById(menudivs[i]);
    if (menuElement != null) {
      var menuElementList = menuElement.getElementsByTagName('a');
      for (var j=0; j < menuElementList.length; j++) {
        menuElementList[j].setAttribute("href", "#");
      }
    }
  }
} // end function fixanchors

If javascript is disabled, the links are unaltered, and page navigation procedes normally, as does indexing by search engines.

If javascript is enabled, the links are re-written, permitting full AJAX functionality, which becomes active even with pages found from links given by the search engines.

This technique requires a careful page design which will display pages properly without javascript enhancements, and will avoid the two major problems associated with AJAX-enabled pages.

MySQL Tips

MySQL has come of age with Version 5. We use it as the database of choice because it is fast, reliable and robust. During the course of our work we have run accress a number of times we were required to create unusual queries. We will share these query methods with you as we encounter them.

How to sort or group on CIDR

I found myself having to detect user download accesses for a client with the user possibly using different IP's within the same classless subnet. The user's IP is recorded as part of the session, and the client then updates the netmask using CIDR notation. The IP is stored as varchar(15) and the netmask may be stored as int or char(2) with a default value of 32.

CREATE TABLE logtable (
        ....    ,
        ip      varchar(15) default "0.0.0.0",
        netmask int default 32,
        .... )

MySQL has two functions, INET_ATON and INET_NTOA which convert dotted quad notation to an integer and back. It is easy to sort by IP using INET_ATON(ip). However grouping by subnet requires an understanding of the bitwise operators in MySQL.

When two numbers are compared using the MySQL bitwise operators, the numbers and the result are cast to bigint (64 bits). To create a bit mask for the network address, which is 32 bits, we must first shift the mask the required number of bits, then we have to mask the lower 32 bits to create the bit mask for the subnet:

Thus the SQL becomes:

SELECT  ip,
        INET_NTOA((INET_ATON("255.255.255.255") << (32 - netmask))
                & INET_ATON("255.255.255.255")) AS bitmask,
        INET_NTOA(INET_ATON(ip)
                & ((INET_ATON("255.255.255.255") << (32 - netmask))
                & INET_ATON("255.255.255.255"))) AS subnet
        FROM logtable;

For an IP of 123.123.123.15 and a netmask of 24, this will give:

        +----------------+---------------+---------------+
        | ip             | bitmask       | subnet        |
        +----------------+---------------+---------------+
        | 123.123.123.15 | 255.255.255.0 | 123.123.123.0 |
        +----------------+---------------+---------------+

The SQL might be a little more readable, and a tad more efficient, if we substitute the actual integer:

        INET_ATON("255.255.255.255") = 4294967295

SELECT  ip,
        INET_NTOA((4294967295 << (32 - netmask))
                & 4294967295) AS bitmask,
        INET_NTOA(INET_ATON(ip)
                & ((4294967295 << (32 - netmask))
                & 4294967295)) AS subnet
        FROM logtable;