Hello, Web! (circa 2002)

January 5, 2023

I recently found my first significant web site on an old hard drive. I thought revisiting the site and its source would make for a fitting start to this blog. The oldest timestamps for the source are from Nov 22 2002. This should be fun!

The Idea

I was a big fan of the Simpsons when I was a kid. I watched old reruns so much I could repeat quotes from far too many episodes. In that same time frame, my family had recently set up dial-up Internet via AOL, and I was just starting to figure out the World Wide Web.

At some point, I discovered I could create my very own web site. For free! So, I started to teach myself HTML and related technologies to create a site dedicated to the Simpsons. I think I learned HTML using this edition of HTML for Dummies I checked out from the library, and I exclusively used IE6 to test the site.

The site would contain my reviews for each episode including my favorite quote from the episode. Readers would also be able to vote for their favorite quotes from among my favorites. I also appear to have added a forum that readers could use to discuss the Simpsons? Seems very ambitious.

As is often the case for web sites created by developers, I think I got stuck focusing on the code instead of the content, and I only ended up reviewing five or so episodes. (Maybe this blog will be different? ๐Ÿ˜…). Here's a screenshot of serving the index page to Chrome:

A screenshot of the site's homepage
A look at the homepage of the site.

Wow, what an eyesore! Let's start with looking at the markup.

Markup

The following is the index.html for the site:

<html>
<head>
<title>The Simpsons' Hall of Pointless Knowledge</title>
<META NAME="description"
  CONTENT="Simpsons Quotes expressed in episode guides">
<META NAME="keywords"
  CONTENT="Simpsons, Marge Simpson, Bart Simpson, Lisa Simpson,
Maggie Simpson, Homer Simpson, Fox TV Shows, Cartoon Archives,
Simpsons' Hall of Pointless Knowledge, simpsons archive">
<script type="text/javascript" language="JavaScript"><!--
window.open('quote.php','WindowHandle','height=200,width=250');
// --></script>
</head>
<frameset frameborder="0" framespacing="0" border="0" rows="36%,64%">
<frame src="Title.html">
<frameset frameborder="0" framespacing="0" border="0" cols="19%,81%">
<frame name="menu" src="Menu.html">
<frame name="body" src="News.html" MARGINWIDTH="0" MARGINHEIGHT="0">
</frameset>
</frameset>
</html>

Not too different from a modern index.html. Here are a few things I noticed:

  • Framesets
  • The unconditional pop-up window triggered by JavaScript in the <head> tag
  • Meta elements

Framesets

I had to lookup framesets because I don't remember ever using them. Turns out that HTML5 marked them as obsolete "because using them damages usability and accessibility". Digging on that a bit more I see a lot of pages reference Why Frames Suck (Most of the Time), published on November 30, 1996, as a reason to avoid them. One of the issues mentioned in that post is that frames negatively impact the ability to link to specific content. I notice this in my site.

Navigating around the site, the URL never changes. So, if I navigate to the "Episodes" link and then click further into "Season 4", there would be no way for a user to share the link to that page. This is definitely a major downside to using frames.

I think I decided to use frames instead of a different approach because my HTML book recommended frames for creating a fixed layout with a menu and header. I could have explored using CSS2, maybe?

I could have also used a web server to include the markup for the header and menu on every page. However, I distinctly remember learning that my web hosting did not support something like Server Side Includes.

Even though the <frame> tag is obsolete, it appears the browser engines still have decent support for it. Spot checking in Safari and Firefox, I see that the site renders almost identically in all three browsers.

Pop-up Windows

Lines 10-12 have some inline JavaScript that attempts to open a pop-up to show a "quote of the day".

<script type="text/javascript" language="JavaScript"><!--
window.open('quote.php','WindowHandle','height=200,width=250');
// --></script>

As this Stackoverflow answer mentions, since this code invokes window.open unconditionally and not in response to a user gesture, browsers will block this pop-up, as they should. Initially, I did not run into this issue as pop-up blocking would not become a thing until a few years later.

Interestingly enough, requiring a user gesture to invoke a JavaScript API is now a foundational authorization mechanism seen throughout the Web APIs offered by browsers. For example, a user gesture is a key requirement for using the Storage Access API that allows a site to get access to its first-party cookies from a third-party context, in Safari and Firefox.

Meta elements

The <head> tag also contains some <meta> tags:

<meta
  name="description"
  content="Simpsons Quotes expressed in episode guides"
/>
<meta
  name="keywords"
  content="Simpsons, Marge Simpson, Bart Simpson, Lisa Simpson,
Maggie Simpson, Homer Simpson, Fox TV Shows, Cartoon Archives,
Simpsons' Hall of Pointless Knowledge, simpsons archive"
/>

I recall adding those tags in an attempt to have my page show up in search engine results for the Simpsons. I don't think I was successful.

The description tag is still used today. Lighthouse still recommends it for SEO. The use of keywords have fallen out of use, according to this useful blog post. That post mentions that Google has not utilized keywords since at least 2009. But, back when I was creating this site, my guess is that they were still very much in use.

Let's move on to the atrocious design, shall we? ๐Ÿ˜ฌ

Design

The logo for the website, containing the text "Simpson's Hall of Pointless Knowledge" with cutouts of the Simpsons characters layered over the text
The logo for the site.

This logo was created with the help of a friend who was way better at image editing than me. I think they helped with Marge, Bart, Lisa and Maggie, cutting them out of images found elsewhere on the Web. Then we ran out of time and I tried to figure out Homer on my own. As you can tell, I did a less exact job cutting Homer out of the source image.

The font is most likely Courier but I'm not exactly sure. At least I didn't use Comic Sans!

Colors

I think I probably landed on variations of aqua for the background color of the page and logo because the Simpsons used a bright yellow and aqua in its various logos. I think the aqua looks fine in the logo but it is really hard to look at as the page background color.

I feel like using an odd background color is a hallmark of early web pages, mostly driven by the novelty and less based on actual aesthetics.

Layout

The site makes little use of CSS, and I did not write any myself. CSS2 was available to use at this point, but my guess is that I was not aware of it. As a result, there are a number of obsolete approaches in use:

  • Using HTML tables and the width attribute
  • Using &nbsp elements to implement indentation
  • Using bgcolor, link, vlink, and alink attributes on a body tag

Tooltip Hack

There is also an interesting hack in the menu frame. Here's a snippet of the HTML:

<body
  bgcolor="#0DF2F2"
  link="#008040"
  vlink="#FF0000"
  alink="#FF8000"
  OnLoad="setupDescriptions()"
>
  <div
    id="object1"
    style="position:absolute; visibility:show; left:25px; top:-50px; z-index:2"
  >
    layer hidden off the screen
  </div>
  <a
    href="News.html"
    target="body"
    onMouseOver="popLayer(1)"
    onMouseOut="hideLayer(-50)"
    >News(Home)</a
  ><br /><br />
  <a
    href="Episodes.html"
    target="body"
    onMouseOver="popLayer(2)"
    onMouseOut="hideLayer(-50)"
    >Episodes</a
  ><br /><br />
  <a
    href="Characters.html"
    target="body"
    onMouseOver="popLayer(3)"
    onMouseOut="hideLayer(-50)"
    >Character Archives</a
  ><br /><br />
  <a
    href="hall.php"
    target="body"
    onMouseOver="popLayer(4)"
    onMouseOut="hideLayer(-50)"
    >Hall of Quotes</a
  ><br /><br />
  <a
    href="/forum/"
    target="_parent"
    onMouseOver="popLayer(6)"
    onMouseOut="hideLayer(-50)"
    >Forum</a
  >
</body>

The goal of the hack was to show a tooltip over the menu frame links when the user's mouse pointer was over the link. The content for the tooltip is contained in the object1 div. It is placed offscreen by default and moved around with some JavaScript triggered by DOM mouse events.

The JavaScript that enables this was copied from a defunct URL from http://home.thezone.net:

// Source:  http://home.thezone.net/~rbennett/utility/javahead.htm
function setupDescriptions() {
  var x = navigator.appVersion;
  y = x.substring(0, 4);
  if (y >= 4) setVariables();
}
var x, y, a, b;
function setVariables() {
  if (navigator.appName == 'Netscape') {
    h = '.left=';
    v = '.top=';
    dS = 'document.';
    sD = '';
  } else {
    h = '.pixelLeft=';
    v = '.pixelTop=';
    dS = '';
    sD = '.style';
  }
}
var isNav = navigator.appName.indexOf('Netscape') != -1;
function popLayer(a) {
  desc = '<table cellpadding=3 border=1 bgcolor=F7F7F7><td>';

  if (a == 1) desc += 'Updates to the site and site news.';
  if (a == 2) desc += 'The Episode Explanations and the Quotes!';
  if (a == 3) desc += 'Bios of the characters';
  if (a == 4) desc += 'Results from your votes!';
  if (a == 5) desc += 'Vote for a Quote from the Episodes section';
  if (a == 6) desc += 'The Message Board for the Site';

  desc += '</td></table>';

  if (isNav) {
    document.object1.document.write(desc);
    document.object1.document.close();
    document.object1.left = x + 25;
    document.object1.top = y;
  } else {
    object1.innerHTML = desc;
    eval(dS + 'object1' + sD + h + (x + 25));
    eval(dS + 'object1' + sD + v + y);
  }
}
function hideLayer(a) {
  if (isNav) {
    eval((document.object1.top = a));
  } else object1.innerHTML = '';
}
function handlerMM(e) {
  x = isNav ? e.pageX : event.clientX;
  y = isNav ? e.pageY : event.clientY;
}
if (isNav) {
  document.captureEvents(Event.MOUSEMOVE);
}
document.onmousemove = handlerMM;

There's some really wacky stuff in this script.

navigator.appName and navigator.appVersion are used to do feature detection. As the links state, both of these properties have been deprecated and return fixed values in current browsers. These properties have probably not been useful for feature detection for a long time.

It looks like there is some specific support for older versions of IE, as the pixelLeft property appears to be a IE-specific way to set the left property of an element's CSS style.

The script makes dubious use of eval to dynamically change the elements position. There's no reason to use eval in this script. Case in point: eval((document.object1.top = a)); evaluates the result of the assignment. I definitely was not aware of the perils of using eval, and my guess is that most site authors also used eval without thinking about it.

The script also uses document.captureEvents. I was not able to find any detailed documentation on what this function does on a document. MDN has a page for window.captureEvents. I see that Netscape Navigator implemented the capturing model for events so maybe this was required to enable events to be delivered?

The script, as written, throws a bunch of type errors when moving the mouse in the menu frame. I think that is due to document.object1 not existing as well as not using the style attribute to change left and top. After making those changes, the script, surprisingly!, works pretty well. Here's a screenshot of it in action:

A screenshot showing the functional tooltip
The tooltip works!

I think this script is a good example of the use-case for JavaScript in the early 2000s: targeted, inline, small scripts to make sites more interactive.

Lighthouse Score

The score report from running Lighthouse against the site
The Lighthouse score for the site.

I ran the Chrome DevTools Lighthouse tool against the site in Navigation mode for a Mobile device. Lighthouse reported a better score than I expected!

It looks like the blocked pop-up is leading Lighthouse to conclude that the page is not rendering anything. Seems like that might be a bug in Lighthouse ๐Ÿ˜€?

Server side

The voting system for the quotes was implemented in PHP, using a MySQL database for persistence. It looks like I deployed phpmyadmin 2.5.4, released on Oct 18 2003, to administer the MySQL database, under the /phpmyadmin/ path. It would be a fun experiment to deploy that version as a honeypot, and see how long it takes for it to be compromised.

As this point, I knew very little about programming. Prior to this, my only experience with programming was from using Learn to Program Basic. The PHP was probably cobbled together over many, many hours of trial and error.

There were three pages generated by PHP:

  • Displaying the quote of the day in a pop-up (as discussed in Pop-up Windows).
  • Displaying the "Hall Of Quotes", showing the top ten quotes for each season, as voted on by readers.
  • Processing votes for episode quotes

The PHP scripts are rough!

The username used to access the DB is root and the credentials are hard-coded in every script. The password is also a password I used everywhere back in the day. ๐Ÿ˜ฌ

The quote of the day script will update the quote of the day the first time the page is accessed on a particular day. That is, a GET request side-effects the DB. Pretty sure I didn't learn about HTTP method safety until at least a decade later.

As you might expect, the vote processing script has a SQL injection vulnerability:

<?
$id=$_POST['clip'];

$username="root";
$password="๐Ÿ™ˆ";
$database="votes";

mysql_connect(localhost,$username,$password);
@mysql_select_db($database) or die("Unable to select database");
$query = "SELECT * FROM clipvotes WHERE id = '$id'";
$result=mysql_query($query);
$vote=mysql_result($result,"0","votes");
$vote++;
$update= "UPDATE clipvotes SET votes='$vote' WHERE id = '$id'";
mysql_query($update);
mysql_close();

print("Thanks for Voting");
?>

The clip POST parameter is assigned to $id, which then gets passed directly to the SQL parser without sanitization. Interestingly enough, the damage that could be done with this vulnerability is somewhat limited in that mysql_query does not support multiple queries in a single function invocation. So, you cannot do something like SELECT * FROM clipvotes WHERE id = ''; DROP TABLE clipvotes;--', I think.

Forum

As mentioned in The Idea, there was also a forum, hosted at /forum. I'm not going to dig too much into this part. But, the forum uses phpBB 2.0.10, released some time in 2004 per the CVS inline comments. phpBB is still actively maintained. Very cool!

Development Environment

I think I upgraded the family desktop to Windows XP from Windows 95 around the time I was working on the site. I recall using MS Notepad to write the code, and then later on using Notepad++ when it came out in 2003.

I was definitely not aware of source control at the time so I see a lot of .bak files alongside the source. I recall that deployment was done by manually copying the files to a destination on a server using a visual FTP client. I vaguely remember that the client was configured to ignore .bak files.

Observations

If you've made it this far, thanks for taking a stroll down memory lane with me! Writing this post gave me some perspective on the current day experience of developing for the web.

I found that exploring the code did not feel as archaic as I expected. I was really shocked that the frontend for the site worked pretty much without issue. It was fun to see some weird baggage in the Web APIs that probably won't ever be removed, despite the deprecation warnings and otherwise. Kudos to those that work tirelessly to maintain the backward compatibility of the Web!

It really resonated with me that CSS2 was available to use but I did not use it, leading to a bunch of hacks to get the desired user experience. The core technologies of the Web, CSS and JS in particular, have started to change at a much higher rate than the past. This high rate of change leads to a near-infinite amount of ways to achieve the same user experience in a browser. As a result, I feel like each developer has a unique subset of knowledge about these technologies, and this shows in the features they choose while developing for the Web.

I was pleasantly surprised that there was a SQL injection vulnerability in the PHP scripts. When I first saw that I had written some PHP, I knew there had to be a SQL injection vulnerability. That was definitely my favorite part of this experience!

Questions/comments?

Contact me on Twitter or LinkedIn

Get notified for future posts?

โฌ‡๏ธ Email or ๐Ÿ—ž๏ธ RSS

One email per post. No spam.

No open or click tracking.

Unsubscribe anytime.