Supercharging Javascript, Part 6: The Internet Explorer Problem

Previous: Caching on the Client

Of course, no discourse on Web development would be complete without the inevitable "What about IE6?" question and this one is no exception.

Unpatched versions of Internet Explorer 6 do not correctly decompress data using the GZip compression method. Thankfully this is an increasingly uncommon problem because IE6 is dying and unpatched versions are increasingly rarer.

But it is still best practice to detect buggy versions and disable GZip compression (ignoring the GZip accept encoding header) on those versions. Unfortunately ob_gzhandler() does not do this automatically.

<?php
define('SCRIPT_DIR', $_SERVER['DOCUMENT_ROOT'] . '/script/');
define('CACHE_DIR', $_SERVER['DOCUMENT_ROOT'] . '/cache/');

$bundles = array(
  'site' => array(
    'jQuery-1.3.2.js',
    'jquery.bgiframe.js',
    'jquery.dimensions.js',
    'supersubs.js',
    'superfish.js',
    'site.js',
  ),
);

$site = $_GET['site'];
if (!isset($bundles[$site])) {
  error_log("javascript.php: Unknown bundle '$site' requested");
  exit;
}

$mtime = $_GET['mtime'];
$cache_file = CACHE_DIR . $site . '.js';
$cache_mtime = @filemtime($cache_file);

// we need to rebuild is the passed in mtime is newer than the cache file mtime
if ($mtime > $cache_mtime) {
  require 'jsmin-1.1.1.php';
  $scripts = '';
  foreach ($bundles[$site] as $file) {
    $contents = @file_get_contents(SCRIPT_DIR . $file);
    if ($str === false) {
      error_log("javascript.php: Error reading file '$file'");
    } else {
      $scripts .= $contents;
    }
  }
  $min_content = JSMin::minify($scripts);
  file_put_contents($cache_file, $min_content);
} else {
  $min_content = file_get_contents($cache_file);
}

header('Content-Type: text/javascript');
header('Expires: ' . gmdate('D, d M Y H:i:s', time()+365*24*3600) . ' GMT');
header('ETag: "' . md5($min_content) . '"');

if (is_buggy_IE()) {
  ob_start();
} else {
  ob_start('ob_gzhandler');
}

echo $min_content;

function is_buggy_IE() {
  $ret = false;
  $agent = $_SERVER['HTTP_USER_AGENT'];
  if (strpos($agent, 'Mozilla/4.0 (compatible; MSIE ') === 0 && strpos($ua, 'Opera') === false) {
    $version = floatval(substr($agent, 30));
    if ($version < 6) {
      $ret = true;
    } else if ($version == 6 && strpos($agent, 'SV1') === false) {
      $ret = true;
    }
  }
  return $ret;
}
?>

So that's it. The above is a fully-working, fully-tested solution for efficient delivery of Javascript that can make a profound difference to page loading times that doesn't sacrifice one of the great things about PHP: the ability to save a file, reload a Web page and see if what you've done has worked or not. There is no separate build step yet none of the caching functionality is compromised.

Feel free to use the code in any way you wish. Drop me a line or leave a comment if this was helpful to you or you find an issue or simply have a suggestion.