Making Friendly Javascript Errors - Client and Server

Jan 14, 2010 javascript
This post is more than 18 months old. Since technology changes too rapidly, this content may be out of date (but that's not always the case). Please remember to verify any technical or programming information with the current release.

The more I look at my code I wrote in my earlier posts about the unknown _popupControl() function and the Javascript Error Handler, I see opportunities to leverage these errors into useful user interactions.

Doing a service for your visitor

After your javascript is tried and tested and error free, there are still chances that errors can be logged using my utility. These usually are the result of Spyware that is left on the user’s machine. Sometimes some removal processes don’t capture all of it. The _popupControl() method was one such remnant.

I thought that instead of just ignoring these issues, I could gently alert the user to the issue. Perhaps, I could even get affiliate commissions for a product that I know for sure removes these threats.

There are two ways to go about handling these javascript errors: client side and server side.

Client Side

Client side javascript error handling requires a bit more front-end programming. It also shows a lot of your cards to the outside world. By looking at the code in the javascript portion of your page, visitors could see all types of errors that you’re trying to detect. While I don’t think this is a deterrent to using this method, you may feel otherwise.

First things first - if you can’t remember, check out my Javascript Error Handler and Logger entry to see the code I’ll be expanding on.

My new code is going to look something like this:

window.onerror = function (message, url, line) {
  /** log message **/
  var i = new Image();
  i.src = 'error.php?url=' 
        + escape(url) 
        + '&message;=' 
        + escape(message) 
        + '&line;=' 
        + line;

  if (message.indexOf('spywareWindowGenerator')) {
    var d = document.createElement('div');
    d.innerHTML = 'Sounds like you got spyware';
    document.body.appendChild(d);
  }
  else if (message.indexOf('otherbaddie')) {
    var d = document.createElement('div');
    d.innerHTML = 'Sounds like you got some other baddie';
    document.body.appendChild(d);
  }
}

I’ll break it down:

First, the standard logging service is initiated on error. The error.php file will log the javascript error for further research later.

Next, I evaluate the actual message that was sent to the error handler. In this example, I’m looking for two possible issues, a reference to the function _spywareWindowGenerator() and a reference to someOtherBaddie(). Both of these functions are not defined in my code and can be considered to be remnants of the spyware infestation.

The first if statement checks for the existence of spywareWindowGenerator in the message. If it exists, it creates a new div HTML element. Then, it populates it with a message regarding this error. (Note, you could also load an image, create link, etc.). Finally, just for demonstration purpose, that DIV is added to the end of the body and is displayed.

The second if statement is simply checking for the case of otherBaddie - and will do a similar process.

Like I mentioned before, this lays all of your cards out on the table - could potentially make your page load longer (especially if you have a lot of spyware you’re tracking), but be most versatile.

Server Side

With server side, I’m going to rely on the image that the javascript error handler is loading. If this image is populated by my error.php file, then I’ll show it.

First, the modified javascript for our error handler now looks like this:

window.onerror = function (message, url, line) {
  /** log message **/
  var i = new Image();
  i.src = 'error.php?url=' 
        + escape(url) 
        + '&message;=' 
        + escape(message) 
        + '&line;=' 
        + line;

  /** now check to see if we have something to show **/
  if (i.height) {
    /** add it to the page **/
    document.body.appendChild(i);
  }
}

The first part is the standard logging mechanism that we’re used to. However, after that, I check for a height of the image that was requested. If no image was generated by the PHP GET request, then the height will be 0. Otherwise, the image object will return a height. Then, just for demonstration, I append that image to the bottom of the body of the document.

This means that we put a little bit more of the responsibility for determining the message to display to the user on the back end. At first it seems like it could be a little less verbose - as it is just an image. However, we could expand the javascript error handler to detect what ’link’ it could display based on the image dimensions, etc. (This is for a different entry if need be…)

Next, I had to edit my error.php file. It now contains this code:

$keys = array();
$keys['_spywareWindowGenerator'] = 'badSypware.png';
$keys['otherBadGuy'] = 'otherBadGuy.png';

/**
 * check for an image to show
 */

$imageToShow = '';
foreach ($keys as $substring=>$image) {
  if (stripos($_GET['message'], $substring) !== false) {
    $imageToShow = $image;
  }
}

if (!empty($imageToShow)) {
  header('Content-Type: image/png');
  readfile($imageToShow);
  die();
}
else {
  error_log(
    "{$_GET['message']} occured on line {$_GET['line']} of URL {$_GET['url']}"
  );
}

The first step is to determine all of the key words that could appear in javascript error messages. Then, associate them with an image that conveys our message.

The next bit of code looks through and searches the message for any of the possibilities. If it finds one, it sets the image to be the associated value for that key.

Finally, the PHP code checks to see if there is an image to show. If so, it sends the proper header and reads the file to the output buffer. Otherwise, it assumes it is an error that we’re not familiar with and logs it.

Go to All Posts