CSS Query Selectors for A:

You are developing a web page by using HTML5 and CSS3.
Hyperlinks on the page must be rendered with a style that reflects the last user action performed.
You need to style the four anchor elements in the document.

In what order should you specify the four anchor selectors?

  • a:active
  • a:link
  • a:hover
  • a:visited

Here’s a cool way to remember the order of the four selectors, “LVHA (link visited hover active)”,….

Just think ‘LOVE’ (LV) and ‘HATE’ (HA)….

  • a:link
  • a:visited
  • a:hover
  • a:active


Updating controls via JQuery from inside an UpdatePanel

Recently we encountered an issue when we were trying (unsuccessfully) to update a link outside an Ajax UpdatePanel using jQuery.
We wrote the change events and we noticed that they only fired once and no more. Clicking on the tickbox proved to be futile. Not even 317 clicks seemed to work.

After a bit of research, we found out that the Update Panels only subscribe to the page load event once and afterwards they drop the events, unless you rebind them once more.
To rebind them, you need to call the PageRequestManager and connect to the endRequest method.

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {…});

$('#ctl00_ContentPlaceHolder1_chkLinkedSuppliers').on('change', function () {
        if ($('#ctl00_ContentPlaceHolder1_lnkAuditReport2').length > 0)
            var href = $('#ctl00_ContentPlaceHolder1_lnkAuditReport2').attr("href");
            href = href.replace("&ShowAllLinked=1","").replace("&ShowAllLinked=0","");
            if($(this).is(":checked")) {
                href = href + "&ShowAllLinked=1";
                href = href + "&ShowAllLinked=0";

            $('#ctl00_ContentPlaceHolder1_lnkAuditReport2').attr("href", href);


    var prm = Sys.WebForms.PageRequestManager.getInstance();

    prm.add_endRequest(function () {
        // re-bind your jQuery events here

        $('#ctl00_ContentPlaceHolder1_chkLinkedSuppliers').on('change', function () {
            if ($('#ctl00_ContentPlaceHolder1_lnkAuditReport2').length > 0) {
                var href = $('#ctl00_ContentPlaceHolder1_lnkAuditReport2').attr("href");
                href = href.replace("&ShowAllLinked=1", "").replace("&ShowAllLinked=0", "");
                if ($(this).is(":checked")) {
                    href = href + "&ShowAllLinked=1";
                } else {
                    href = href + "&ShowAllLinked=0";

                $('#ctl00_ContentPlaceHolder1_lnkAuditReport2').attr("href", href);


It worked like a charm!

    function BindControlEvents() {
        //jQuery is wrapped in BindEvents function so it can be re-bound after each callback.
        //Your code would replace the following line:
            $('#').limit('100', '#charsLeft_Instructions');

    //Initial bind
    $(document).ready(function () {

    //Re-bind for callbacks
    var prm = Sys.WebForms.PageRequestManager.getInstance();

    prm.add_endRequest(function() {

Koalas to the Max – Cool HTML5 Canvas Painter

This awesome website uses hovers over a circle area to split the circle into four other circles and then four more and four more – each time reducing the size of the circle and the colour of the circles and making sure none of the circles meet.


The JS Code:


"use strict"

* Made with love by Vadim Ogievetsky for Annie Albagli (Valentine's Day 2011)
* Powered by Mike Bostock's D3
* For me on GitHub:  https://github.com/vogievetsky/KoalasToTheMax
* License: MIT  [ http://koalastothemax.com/LICENSE ]
* If you are reading this then I have an easter egg for you:
* You can use your own custom image as the source, simply type in:
* http://koalastothemax.com?
* e.g.
* http://koalastothemax.com?http://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Flag_of_the_United_Kingdom.svg/200px-Flag_of_the_United_Kingdom.svg.png
* also if you want to use a custom image and want people to guess what it is
* (without seeing the url) then you can type the url in base64 encoding like so:
* http://koalastothemax.com?
* e.g.
* http://koalastothemax.com?YXN0bGV5LmpwZw==
* (try to guess the image above)

var koala = {
  version: '1.8.2'

(function() {
  function array2d(w, h) {
    var a = [];
    return function(x, y, v) {
      if (x < 0 || y < 0) return void 0;
      if (arguments.length === 3) {
        // set
        return a[w * x + y] = v;
      } else if (arguments.length === 2) {
        // get
        return a[w * x + y];
      } else {
        throw new TypeError("Bad number of arguments");

  // Find the color average of 4 colors in the RGB colorspace
  function avgColor(x, y, z, w) {
    return [
      (x[0] + y[0] + z[0] + w[0]) / 4,
      (x[1] + y[1] + z[1] + w[1]) / 4,
      (x[2] + y[2] + z[2] + w[2]) / 4

  koala.supportsCanvas = function() {
    var elem = document.createElement('canvas');
    return !!(elem.getContext && elem.getContext('2d'));

  koala.supportsSVG = function() {
    return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', "svg").createSVGRect;

  function Circle(vis, xi, yi, size, color, children, layer, onSplit) {
    this.vis = vis;
    this.x = size * (xi + 0.5);
    this.y = size * (yi + 0.5);
    this.size = size;
    this.color = color;
    this.rgb = d3.rgb(color[0], color[1], color[2]);
    this.children = children;
    this.layer = layer;
    this.onSplit = onSplit;

  Circle.prototype.isSplitable = function() {
    return this.node && this.children

  Circle.prototype.split = function() {
    if (!this.isSplitable()) return;
    delete this.node;
    Circle.addToVis(this.vis, this.children);

  Circle.prototype.checkIntersection = function(startPoint, endPoint) {
    var edx = this.x - endPoint[0],
        edy = this.y - endPoint[1],
        sdx = this.x - startPoint[0],
        sdy = this.y - startPoint[1],
        r2  = this.size / 2;

    r2 = r2 * r2; // Radius squared

    // End point is inside the circle and start point is outside
    return edx * edx + edy * edy <= r2 && sdx * sdx + sdy * sdy > r2;

  Circle.addToVis = function(vis, circles, init) {
    var circle = vis.selectAll('.nope').data(circles)

    if (init) {
      // Setup the initial state of the initial circle
      circle = circle
        .attr('cx',   function(d) { return d.x; })
        .attr('cy',   function(d) { return d.y; })
        .attr('r', 4)
        .attr('fill', '#ffffff')
    } else {
      // Setup the initial state of the opened circles
      circle = circle
        .attr('cx',   function(d) { return d.parent.x; })
        .attr('cy',   function(d) { return d.parent.y; })
        .attr('r',    function(d) { return d.parent.size / 2; })
        .attr('fill', function(d) { return String(d.parent.rgb); })
        .attr('fill-opacity', 0.68)

    // Transition the to the respective final state
      .attr('cx',   function(d) { return d.x; })
      .attr('cy',   function(d) { return d.y; })
      .attr('r',    function(d) { return d.size / 2; })
      .attr('fill', function(d) { return String(d.rgb); })
      .attr('fill-opacity', 1)
      .each('end',  function(d) { d.node = this; });

  // Main code
  var vis,
      maxSize = 512,
      minSize = 4,
      dim = maxSize / minSize;

  koala.loadImage = function(imageData) {
    // Create a canvas for image data resizing and extraction
    var canvas = document.createElement('canvas').getContext('2d');
    // Draw the image into the corner, resizing it to dim x dim
    canvas.drawImage(imageData, 0, 0, dim, dim);
    // Extract the pixel data from the same area of canvas
    // Note: This call will throw a security exception if imageData
    // was loaded from a different domain than the script.
    return canvas.getImageData(0, 0, dim, dim).data;

  koala.makeCircles = function(selector, colorData, onEvent) {
    onEvent = onEvent || function() {};

    var splitableByLayer = [],
        splitableTotal = 0,
        nextPercent = 0;

    function onSplit(circle) {
      // manage events
      var layer = circle.layer;
      if (splitableByLayer[layer] === 0) {
        onEvent('LayerClear', layer);

      var percent = 1 - d3.sum(splitableByLayer) / splitableTotal;
      if (percent >= nextPercent) {
        onEvent('PercentClear', Math.round(nextPercent * 100));
        nextPercent += 0.05;

    // Make sure that the SVG exists and is empty
    if (!vis) {
      // Create the SVG ellement
      vis = d3.select(selector)
          .attr("width", maxSize)
          .attr("height", maxSize);
    } else {

    // Got the data now build the tree
    var finestLayer = array2d(dim, dim);
    var size = minSize;

    // Start off by populating the base (leaf) layer
    var xi, yi, t = 0, color;
    for (yi = 0; yi < dim; yi++) {
      for (xi = 0; xi < dim; xi++) {
        color = [colorData[t], colorData[t+1], colorData[t+2]];
        finestLayer(xi, yi, new Circle(vis, xi, yi, size, color));
        t += 4;

    // Build up successive nodes by grouping
    var layer, prevLayer = finestLayer;
    var c1, c2, c3, c4, currentLayer = 0;
    while (size < maxSize) {
      dim /= 2;
      size = size * 2;
      layer = array2d(dim, dim);
      for (yi = 0; yi < dim; yi++) {
        for (xi = 0; xi < dim; xi++) {
          c1 = prevLayer(2 * xi    , 2 * yi    );
          c2 = prevLayer(2 * xi + 1, 2 * yi    );
          c3 = prevLayer(2 * xi    , 2 * yi + 1);
          c4 = prevLayer(2 * xi + 1, 2 * yi + 1);
          color = avgColor(c1.color, c2.color, c3.color, c4.color);
          c1.parent = c2.parent = c3.parent = c4.parent = layer(xi, yi,
            new Circle(vis, xi, yi, size, color, [c1, c2, c3, c4], currentLayer, onSplit)
      splitableByLayer.push(dim * dim);
      splitableTotal += dim * dim;
      prevLayer = layer;

    // Create the initial circle
    Circle.addToVis(vis, [layer(0, 0)], true);

    // Interaction helper functions
    function splitableCircleAt(pos) {
      var xi = Math.floor(pos[0] / minSize),
          yi = Math.floor(pos[1] / minSize),
          circle = finestLayer(xi, yi);
      if (!circle) return null;
      while (circle && !circle.isSplitable()) circle = circle.parent;
      return circle || null;

    function intervalLength(startPoint, endPoint) {
      var dx = endPoint[0] - startPoint[0],
          dy = endPoint[1] - startPoint[1];

      return Math.sqrt(dx * dx + dy * dy);

    function breakInterval(startPoint, endPoint, maxLength) {
      var breaks = [],
          length = intervalLength(startPoint, endPoint),
          numSplits = Math.max(Math.ceil(length / maxLength), 1),
          dx = (endPoint[0] - startPoint[0]) / numSplits,
          dy = (endPoint[1] - startPoint[1]) / numSplits,
          startX = startPoint[0],
          startY = startPoint[1];

      for (var i = 0; i <= numSplits; i++) {
        breaks.push([startX + dx * i, startY + dy * i]);
      return breaks;

    function findAndSplit(startPoint, endPoint) {
      var breaks = breakInterval(startPoint, endPoint, 4);
      var circleToSplit = []

      for (var i = 0; i < breaks.length - 1; i++) {
        var sp = breaks[i],
            ep = breaks[i+1];

        var circle = splitableCircleAt(ep);
        if (circle && circle.isSplitable() && circle.checkIntersection(sp, ep)) {

    // Handle mouse events
    var prevMousePosition = null;
    function onMouseMove() {
      var mousePosition = d3.mouse(vis.node());

      // Do nothing if the mouse point is not valid
      if (isNaN(mousePosition[0])) {
        prevMousePosition = null;

      if (prevMousePosition) {
        findAndSplit(prevMousePosition, mousePosition);
      prevMousePosition = mousePosition;

    // Handle touch events
    var prevTouchPositions = {};
    function onTouchMove() {
      var touchPositions = d3.touches(vis.node());
      for (var touchIndex = 0; touchIndex < touchPositions.length; touchIndex++) {
        var touchPosition = touchPositions[touchIndex];
        var prevTouchPosition = prevTouchPositions[touchPosition.identifier]
        if (prevTouchPosition) {
          findAndSplit(prevTouchPosition, touchPosition);
        prevTouchPositions[touchPosition.identifier] = touchPosition;

    function onTouchEnd() {
      var touches = d3.event.changedTouches;
      for (var touchIndex = 0; touchIndex < touches.length; touchIndex++) {
        var touch = touches.item(touchIndex);
        prevTouchPositions[touch.identifier] = null;

    // Initialize interaction
      .on('mousemove.koala', onMouseMove)
      .on('touchmove.koala', onTouchMove)
      .on('touchend.koala', onTouchEnd)
      .on('touchcancel.koala', onTouchEnd);

How to check for HTML content in contact forms? Spam proof without Captcha.

If you ever wanted to stop receiving spam about luis vuitton bags, you wondered how you can spam-proof your contact page without the addition of captchas.

The contact form HTML Code (make sure you include max length for all the fields:

<form name=”contactform” id=”contactform” method=”post” action=”send_form_email.php”>
<ul class=”row form”><li class=”col left”>
<input type=”text” id=”Name” name=”Name” class=”required” placeholder=”Name” maxlength=”100″>
<input type=”text” id=”Email” name=”Email” class=”required” placeholder=”Email” maxlength=”100″>
<input type=”text” id=”Subject” name=”Subject” class=”” placeholder=”Subject” maxlength=”50″></li>
<li class=”col right”><textarea id=”Message” name=”Message” placeholder=”Message”></textarea></li></ul>


The PHP code in send_form_email.php:

function spamcheck($field)
    //filter_var() sanitizes the e-mail 
    //address using FILTER_SANITIZE_EMAIL 
    $field = filter_var($field, FILTER_SANITIZE_EMAIL);
    //filter_var() validates the e-mail 
    //address using FILTER_VALIDATE_EMAIL 
    if (filter_var($field, FILTER_VALIDATE_EMAIL)) {
        return TRUE;
    } else {
        return FALSE;

function linkcheck($message)
    //$message = 'Check this out <a href="http://www.something.com">Click here</a>. Click it';
    if (preg_match('/<a[s]+[^>]*?href[s]?=[s""']+(.*?)[""']+.*?>([^<]+|.*?)?</a>/', $message)) {
        // DO SOMETHING
        return TRUE;
    } else {
        return FALSE;

function clean_string($string)
    $bad = array(
    return str_replace($bad, "", $string);

function died($error)
    // your error code can go here
    echo "We are very sorry, but there were error(s) found with the form you submitted. ";
    echo "These errors appear below.<br /><br />";
    echo $error . "<br /><br />";
    echo "Please go back and fix these errors.<br /><br />";

if (isset($_POST['Email'])) {
    //check if the email address is invalid 
    $mailcheck = spamcheck($_POST['Email']);
    if ($mailcheck == FALSE) {
        died("The Email Address you entered does not appear to be valid.");
    //send email 
    $email_to      = "YOUR EMAIL";
    $email_subject = "Query Submitted ";
    // validation expected data exists
    if (!isset($_POST['Name']) || !isset($_POST['Subject']) || !isset($_POST['Email']) || !isset($_POST['Message'])) {
        died('We are sorry, but there appears to be a problem with the form you submitted. Please make sure all fields are filled in!');
    $first_name = $_POST['Name']; // required
    $email      = $_POST['Email']; // required
    $subject    = $_POST['Subject']; // not required
    $comments   = $_POST['Message']; // required
    $error_message = "";
    $string_exp    = "/^[A-Za-z .'-]+$/";
    if (!preg_match($string_exp, $first_name)) {
        $error_message .= 'The Name you entered does not appear to be valid.<br />';
    if ((strlen($comments) < 2) || (linkcheck($comments) == TRUE)) {
        $error_message .= 'The Message you entered do not appear to be valid.<br />';
    if ((strlen($subject) < 2) || (linkcheck($subject) == TRUE)) {
        $error_message .= 'The Subject you entered do not appear to be valid.<br />';
    if (strlen($error_message) > 0) {
    $email_message = "Dear AdventExhibitions Administrator,nn A new query has been submitted on the website. Details below: nn";
    $email_subject .= $subject;
    $email_message .= "Name: " . clean_string($first_name) . "n";
    $email_message .= "Subject: " . clean_string($subject) . "n";
    $email_message .= "Email: " . clean_string($email) . "n";
    $email_message .= "Comments: " . clean_string($comments) . "n";
    // create email headers
    $headers = 'From: YOUR EMAIL' . "rn" . 'Reply-To: YOUR EMAIL' . "rn" . 'X-Mailer: PHP/' . phpversion();
    mail($email_to, $email_subject, $email_message, $headers);
Thank you for contacting us. We will be in touch with you very soon.

Fireworks for Bonfire Night Safety CSS Skills

With Bonfire Night approaching in the UK, Col Morley and Igor Krestov of Blue Claw decided to put their CSS skills to work creating this fire safety infographic aimed at school-age children.


When viewed in a suitable browser, some elements of the infographic will animate. Rather than aiming at supersmooth, in-your-face visual effects, the flickering of the flames and the sparkling of the sparklers is simple, subtle – and, we think, all the more effective for it.

Inspired by Firefox’s homepage Olympic flame over the summer of 2012, the infographic was created using layered graphics and CSS3 to aid in the process of transition of scale, movement and speed, explains Morley. “The bonfire is made up of several layered ‘fire’ shapes then playing around with key frames enabled stretching, opacity and by adding a warm glow renders a realistic flame effect.

Inspired by Firefox’s homepage Olympic flame over the summer of 2012, the infographic was created using layered graphics and CSS3 to aid in the process of transition of scale, movement and speed, explains Morley. “The bonfire is made up of several layered ‘fire’ shapes then playing around with key frames enabled stretching, opacity and by adding a warm glow renders a realistic flame effect.

“The spark that appears throughout the page was created using a similar technique. Three images were used to pulsate at different rates of scale, similar effect to how we animated the ‘fearful cat’. The movement of the eyes on the hot dog was produced by mouse tracking code adding further interest to those who spotted that.

“The styling of the traditional blackboard theme gives the piece the right level and tone for the audience and enabled us to experiment with textures and fonts.”


Are photoshop-like blend modes possible in HTML5?

If you’re a user of our design applications such as Photoshop and Illustrator, you know how you can create very cool effects with blend modes. An Amazon search returns many books and a Google search on ‘photoshop blending tutorial’ returns more than 200,000 results. This points to a very widely known and used feature.

Adobe: http://blogs.adobe.com/webplatform/2012/04/04/bringing-blending-to-the-web/


To be able to blend to images together like Photoshop does, we will need to use the HTML5 canvas feature. The images are loaded dynamically using Javascript.

The easy way to blend two images together can be summarized into

// Might be an 'offscreen' canvas
var over  = someCanvas.getContext('2d');
var under = anotherCanvas.getContext('2d');

over.blendOnto( under, 'screen', {destX:30,destY:15} );

The full example is featured below:


Blending mode
</div> <canvas id="canvas2" width="300" height="300"></canvas> </section> <section class="result"> <canvas id="result" width="300" height="300"></canvas> </section> </div>

The Javascript Code

At first we define the blending modes:

var blendingModes = {
	normal: function(a, b) {
		return a;

	lighten: function(a, b) {
		return (b > a) ? b : a;

	darken: function(a, b) {
		return (b > a) ? a : b;

	multiply: function(a, b) {
		return (a * b) / 255;

	average: function(a, b) {
		return (a + b) / 2;

	add: function(a, b) {
		return Math.min(255, a + b);

	substract: function(a, b) {
		return (a + b < 255) ? 0 : a + b - 255; 	}, 	difference: function(a, b) { 		return Math.abs(a - b); 	}, 	negation: function(a, b) { 		return 255 - Math.abs(255 - a - b); 	}, 	screen: function(a, b) { 		return 255 - (((255 - a) * (255 - b)) >> 8);

	exclusion: function(a, b) {
		return a + b - 2 * a * b / 255;

	overlay: function(a, b) {
		return b < 128
			? (2 * a * b / 255)
			: (255 - 2 * (255 - a) * (255 - b) / 255);

	softLight: function(a, b) {
		return b < 128 			? (2 * ((a >> 1) + 64)) * (b / 255)
			: 255 - (2 * (255 - (( a >> 1) + 64)) * (255 - b) / 255);

	hardLight: function(a, b) {
		return blendingModes.overlay(b, a);

	colorDodge: function(a, b) {
		return b == 255 ? b : Math.min(255, ((a << 8 ) / (255 - b)));

	colorBurn: function(a, b) {
		return b == 0 ? b : Math.max(0, (255 - ((255 - a) << 8 ) / b));

	linearDodge: function(a, b) {
		return blendingModes.add(a, b);

	linearBurn: function(a, b) {
		return blendingModes.substract(a, b);

	linearLight: function(a, b) {
		return b < 128
			? blendingModes.linearBurn(a, 2 * b)
			: blendingModes.linearDodge(a, (2 * (b - 128)));

	vividLight: function(a, b) {
		return b < 128
			? blendingModes.colorBurn(a, 2 * b)
			: blendingModes.colorDodge(a, (2 * (b - 128)));

	pinLight: function(a, b) {
		return b < 128
			? blendingModes.darken(a, 2 * b)
			: blendingModes.lighten(a, (2 * (b - 128)));

	hardMix: function(a, b) {
		return blendingModes.vividLight(a, b) < 128 ? 0 : 255;

	reflect: function(a, b) {
		return b == 255 ? b : Math.min(255, (a * a / (255 - b)));

	glow: function(a, b) {
		return blendingModes.reflect(b, a);

	phoenix: function(a, b) {
		return Math.min(a, b) - Math.max(a, b) + 255;

The Blending Code

/** @type CanvasRenderingContext2D */
var ctx1 = null;

/** @type CanvasRenderingContext2D */
var ctx2 = null;

/** @type CanvasRenderingContext2D */
var ctx3 = null;

/** Current blending mode */
var mode = 'normal';

/** Current blending opacity */
var alpha = 1;

var totalImages = 2;
var img1 = new Image;
var img2 = new Image;

img1.onload = img2.onload = imageReady;

function imageReady() {
	if (--totalImages == 0) {

function setupScene() {
	ctx1 = document.getElementById('canvas1').getContext('2d');
	ctx2 = document.getElementById('canvas2').getContext('2d');
	ctx3 = document.getElementById('result').getContext('2d');

	drawImage(img1, ctx1);
	drawImage(img2, ctx2);
	drawImage(img1, ctx3);

 * Draw image on specified canvas context
 * @param {Image} img
 * @param {CanvasRenderingContext2D} ctx
function drawImage(img, ctx) {
	ctx.canvas.width = img.width;
	ctx.canvas.height = img.height;
	ctx.drawImage(img, 0, 0);

function updateScene() {
	// create rect for smallest image
	var width =  Math.min(ctx1.canvas.width, ctx2.canvas.width);
	var height = Math.min(ctx1.canvas.height, ctx2.canvas.height);

	var imageData1 = ctx1.getImageData(0, 0, width, height);
	var imageData2 = ctx2.getImageData(0, 0, width, height);

	/** @type Array */
	var pixels1 = imageData1.data;
	/** @type Array */
	var pixels2 = imageData2.data;

	var r, g, b, oR, oG, oB, alpha1 = 1 - alpha;

	var blendingMode = blendingModes[mode];

	// blend images
	for (var i = 0, il = pixels1.length; i < il; i += 4) {
		oR = pixels1[i];
		oG = pixels1[i + 1];
		oB = pixels1[i + 2];

		// calculate blended color
		r = blendingMode(pixels2[i], oR);
		g = blendingMode(pixels2[i + 1], oG);
		b = blendingMode(pixels2[i + 2], oB);

		// alpha compositing
		pixels1[i] =     r * alpha + oR * alpha1;
		pixels1[i + 1] = g * alpha + oG * alpha1;
		pixels1[i + 2] = b * alpha + oB * alpha1;

	ctx3.putImageData(imageData1, 0, 0);

 * @param {String} name
function humanizeName(name) {
	return name.charAt(0).toUpperCase() + name.substring(1).replace(/[A-Z]/g, function(s) {
		return ' ' + s.toLowerCase();

$(function() {
	// setup page:

	// fill blending mode select box
	var options = [];
	for (var name in blendingModes) if (blendingModes.hasOwnProperty(name)) {
		options.push('' + humanizeName(name) + '');

	$('select[name=blending]').html(options.join('')).change(function() {
		mode = $(this).val();
		if (!totalImages)

	$('input[name=opacity]').bind('change keyup keypress', function() {
		var value = parseInt($(this).val(), 10);
		if ($(this).data('prev-value') != value) {
			$(this).data('prev-value', value);
			alpha = Math.min(1, Math.max(0, value / 100));

			if (!totalImages)
	}).val(Math.floor(alpha * 100));

	// load images
	img1.src = 'image1.jpg';
	img2.src = 'image2.jpg';


body {
			padding: 40px 10px;
			font-family: arial, sans-serif;
			font-size: 12px;

		.blending-demo {
			margin-top: 5em;
			white-space: nowrap;

		section {
			position: relative;
			display: inline-block;

		section:after {
			font-weight: bold;
			font-size: 60px;
			top: 50%;
			margin-left: 0.15em;
			left: 100%;
			margin-top: -0.6em;
			line-height: 1.2;

		.image1, .image2 {
			margin-right: 4em;

		.image1:after {
			content: '+';

		.image2:after {
			content: '=';

		.controls {
			position: absolute;
			bottom: 100%;
			padding-bottom: 1em;

		select[name=blending] {
			margin-bottom: 1em;

		label {
			display: inline-block;
			line-height: 1.5;
			vertical-align: middle;
			margin-right: 1em;
			width: 7em;

		input[name=opacity] {
			vertical-align: middle;

The Result


What is CGI and What can it do?

cgi-perlThe Common Gateway Interface (CGI) is a standard for interfacing external applications with information servers, such as Web servers. A plain HTML document that the Web server retrieves is static-a text file that doesn’t change. Every time you call a CGI program in real time, on the other hand, it executes and outputs dynamic information.

CGI began as a way to interface databases to the Web, but CGI programs provide whatever access you want to program within the limits of the server/browser.

The Web browser communicates with the host server (daemon) using HTTP. When the Web browser requests the Universal Resource Locator (URL), or address, of a CGI program, the server starts the CGI program with the daemon’s standard input attached to the CGI program’s standard output. The CGI program services the request and communicates with the database engine using its application program interface (API), which usually uses some form of interprocess communication, shared memory, or sockets.

The database engine retrieves the requested data and returns it to the CGI program. The CGI program formats a Web page using hypertext markup language (HTML) and returns it to the Web daemon via its standard output. The daemon returns the HTML to the browser on the client machine, which formats the page for display.

All CGI programs use this basic concept. A CGI program outputs more than an HTML page, performs all the processing itself, or accesses any type of server. Figure 11.1 shows that the basic process remains the same.


In this chapter, many of the terms used are the same as the hypertext markup language (HTML) standards. Some terms are unique to CGI and might not match common usage.


Environment variable A named parameter that carries information from the server to the script. It is not necessarily a variable in the operating system’s environment, although that is the most common implementation.
Script The software that is invoked by the server via this interface. It need not be a stand-alone program, but could be a dynamically loaded or shared library or even a subroutine in the server.
Server The application program that invokes the script in order to service requests. Generally, this application runs as an independent process on the host computer. In UNIX terms, this program is referred to as a daemon.


What Are the Benefits of Using CGI?

CGI programs access data, equipment, and other processes and return a myriad of document types.

HTML pages are static. That is, once you create and place them on the server, requests are transmitted in the same format each time they are requested. CGI programs run on the server in real time. With CGI programs, a user can retrieve real-time data and format dynamic pages, and the pages are different with each transmission.

CGI programs return a myriad of document types, not just HTML pages, to the server. They send back an image, a plain-text document, or even an audio clip as well as redirect the user to other documents or CGI programs.

CGI programs can also store and retrieve information about the browser in records called cookies on the client machine. These cookies store information about the user during one session, which the browser transmits when the user next requests your pages. This typically validates a user or allows the user to set up a custom page for their own use on your system. For example, this information is used to store information about what the user has accessed during visits to the site and then is used to customize information (such as advertising) that the user sees on his or her next visit to the site.

Many different compiled languages or scripting languages can be used to write CGI programs. Some of the typical languages include

  • C/C++
  • Perl
  • TCL
  • Any UNIX shell
  • Visual Basic
  • AppleScript

Many people prefer to write CGI in a scripting language such as Perl or a shell rather than a compiled language. This is because scripts don’t require compiling, which results in easier incremental development and debugging. The programs to interpret the scripts and their environments usually take up less room on the server.

Tools for producing CGI programs that do not require knowledge of a particular programming language are coming to the market. Choose a language or tool with which you are familiar or which supports the application programming interface (API) of your database engine.

There are hundreds of modules, sample code, and complete applications available for any of the more common languages, especially Perl and C/C++. There are also libraries of routines for retrieving information stored by the daemon and returning information to the Web daemon. The CD-ROM accompanying this book has several examples and URLs to sites with additional code and information.

Unlike Java and other evolving technologies, CGI is a relatively mature protocol. Most Web servers use it (some with variations). Because of the explosion of the Internet, many people have experience with it on all types of platforms and servers.

What Are the Negatives of Using CGI?

One of the biggest negatives of using CGI for Web programming is a security issue.

Running a CGI program is like inviting the world to run a program on your system; therefore, there are security considerations when using CGI programs. Because of the possibility of this abuse by CGI programs, most HTTP daemons limit the directories in which CGI programs reside. Most HTTP daemons require an ID that limits the program’s access to other parts of the system.

Hackers can take advantage of poorly protected host systems. CGI programs, therefore, should check data before passing it on. Hackers even breach security holes in some mail systems.

Because CGI programs run entirely on the host computer, they can be a drain on host and network resources. If the user receives a form on his browser and enters information, the information, in whatever state, is transmitted to the CGI program through the HTTP host, and the CGI program edits the information. If errors are found, the information returns over the network to the user for correction. Users edit on the host computer, forcing incorrect information to transmit over the network before discovery.

New technologies, such as Java, promise the capability of editing on the client before the data is transmitted to the host. This should minimize the amount of invalid data that is transmitted over the network.

The Protocols

The basics of CGI are relatively straightforward. As seen in Figure 11.1, the server communicates with the CGI program primarily through environment variables and under some conditions through the command line.

Although most CGI implementations use environment variables to transmit information from the server to the CGI program, some implementations may pass information through specific files. An example is MS-DOS where environment space can sometimes be at a premium.

The CGI program communicates with the server through standard output (stdout). In most instances, the programmer writes as if the CGI program communicates directly with the client browser. Most information sent by the CGI program passes unaltered by the server to the browser.

The CGI program activates when the browser receives a request for the program’s Universal Resource Locator (URL). The server places information in environment variables and activates the program by piping its stdoutthe server’s standard input (stdin).

The information passes from the server to the program in a standard format. It is the CGI program’s job to read and decode this information, perform specific processing, and return information to the browser.

There is no connection maintenance between send/receive exchanges in CGI interactions. If an application requires multiple send/receive exchanges to complete its work, the CGI program is responsible for maintaining information about the conversation between exchanges.

The CGI program writes the information to files or databases on the host or passes information through cookies (which are supported by many browsers). The CGI program then stores information on the client system. This book does not include a discussion of this part of the CGI application function because it is not covered by the CGI specification.

Environment Variables

The server must pass information about the request from the browser to the CGI program. In order to do this, it uses a combination of the command line and environment variables. The following variables are passed to the CGI program for every request:


Environment variable Purpose/Comment
GATEWAY_INTERFACE The revision of the CGI specification to which this server complies. The format is CGI/revision.
SERVER_NAME The server’s host name, DNS alias, or IP address as it appears in URLs.
SERVER_SOFTWARE The name and version of the information server software answering the request (and running the gateway). The format is name/version.


The next set of environment variables is specific to the request serviced by the CGI program.


Environment variable Purpose/Comment
SERVER_PROTOCOL The name and revision of the information protocol this request has. The format is protocol/revision.
SERVER_PORT The port number to which the request was sent.
REQUEST_METHOD The method with which the request was made. For HTTP, this is GETHEADPOST, and so on.
PATH_INFO The client gives the extra path information. Scripts can be accessed by their virtual path names followed by extra information at the end of this path. The extra information is sent as PATH_INFO and if it comes from a URL, the server should decode it before passing it to the CGI script.
PATH_TRANSLATED The server provides a translated version of PATH_INFO, which takes the path and does any virtual-to-physical mapping.
SCRIPT_NAME A virtual path to the script being executed, used for self-referencing URLs.
QUERY_STRING The information that follows the ? in the URL referencing this script. This is the query information. Never decode the query string in any way. This variable should always be set when there is query information, regardless of command-line decoding.
REMOTE_HOST The host name making the request. If the server does not have this information, it should set REMOTE_ADDR and leave this unset.
REMOTE_ADDR The IP address of the remote host making the request.
AUTH_TYPE If the server supports user authentication and the script is protected, this is the protocol-specific authentication method used to validate the user.
REMOTE_USER This is the authenticated user name if the server supports user authentication and the script is protected.
REMOTE_IDENT If the HTTP server supports RFC 931 identification, this variable is set to the remote user name retrieved from the server. Usage of this variable should be limited to logging only.
CONTENT_TYPE For queries with attached information, such as HTTP POST and PUT, this is the content type of the data.
CONTENT_LENGTH The length of the content as given by the client.


In addition to these variables, the client supplies any header lines and places them into the environment with the prefix HTTP_ followed by the header name. Any dash characters in the header name then change to underscore characters. The server can exclude any headers that it has already processed, such as Authorization, Content-type, and Content-length. If necessary, the server can choose to exclude any or all of these headers if including them would exceed any system environment limits.

An example of these header lines is the HTTP_ACCEPT variable defined in CGI/1.0. Another example is the header User-Agent.


Environment variable Purpose/Comment
HTTP_ACCEPT The MIME types that the client accepts, as given by HTTP headers. Other protocols might need to obtain this information elsewhere. Separate each item in this list with commas according to the HTTP spec. The format istype/subtype, type/subtype.
HTTP_USER_AGENT The browser the client uses to send the request. The general format is software/version library/version.


Getting Information from the Server

Every time a server receives a request for the URL of a CGI program, it executes the program in real time. Most of the program’s output goes directly to the client. A CGI program does not accept command-line arguments because it uses the command line for other purposes.

CGI uses environment variables to send parameters to the program. The two major environment variables for this purpose are QUERY_STRING and PATH_INFO.

QUERY_STRING is anything that follows the first question mark (?) in the URL. For example, the URL http://www.myhost.com/cgi-bin/myprog.cgi activates the program myprog.cgi in the /cgi-bin directory under the document root on host http://www.myhost.com. To pass additional information to the program, the URL expands to

http://www.myhost.com/cgi-bin/myprog.cgi?mydata is here

Place the information in QUERY_STRING as


This string is encoded in the standard URL format of changing spaces to plus signs (+) and indicating special characters with a percent sign and two-digit number (%xx). The CGI program must decode the string in order to use it.

You can add the QUERY_STRING information using either an ISINDEX document or an HTML form (with the GET action). Another way is to manually embed it into the HTML anchor, which references your gateway. This string usually is an information query-for example, what the user wants to search for in the databases or the encoded results of your feedback GET form.

If the Web daemon is not decoding results from a form, the query string decodes onto the command line. This means that each word of the query string is in a different section of ARGV. The CGI program receives, for example, the query string my data as



No decoding or other processing is necessary in order to use the data.

CGI enables the URL to receive extra embedded information, which transmits extra context-specific information to the scripts. The PATH_INFO information passes at the end of the URL without the server encoding any of the information.

A typical use for PATH_INFO information is to provide directory or file information for processing. Suppose that the CGI program


needs to process information in directory /mydir. This information passes as an addition to the URL:


One use of PATH_INFO is to pass configuration filenames to a CGI program. The same base CGI program can then handle multiple configurations by including the configuration file in the URL for the application.

Myprog.cgi knows the location of the document relative to the DocumentRoot via the PATH_INFO environment variable or the actual path to the document via the PATH_TRANSLATED environment variable, which the server generates. Because the first slash / passes with the PATH_INFO variable, it must be stripped if it is not needed.

Getting Form Data

Use the GET and POST methods to retrieve information from the forms. Each method returns the form information in a different manner.


If the form tag includes the GET method, the CGI program receives the tags in the QUERY_STRING environment variable. This can be a method of maintaining information about a set of request/send transactions between the client and CGI program. For example, the CGI program might store information about the client by indexing a serial number key and encoding this key in the URL specified in the ACTION= option of the form tag. The URL with the additional key information returns to the program with a click of the Submit button. This allows the program to retrieve the stored information and restore its working environment.


If the form tag includes the POST method, the CGI program receives the tags through stdin. Note that the server does not send an indication of end of file (EOF) at the end of data. The program must read theCONTENT_LENGTH environment variable in order to determine the length of the input to read.

Decoding Form Information

Both the GET and POST methods send URL-encoded TAG=data pairs separated by ampersands (&). Plus signs (+) replace spaces, and certain characters are encoded as %xx hexadecimal characters. A NAME tag identifies each FORM variable, and this NAME is placed in the TAG part of the data pair. For example, given the following form:


<INPUT NAME="A" SIZE=5>  (Input "A B C")

<INPUT NAME="B" SIZE=5>  (Input "12345")

<INPUT NAME="C" SIZE=2>  (Input "DE")


The CGI program receives the following:


stdin: A=A+B+C&B=12345&C=DE

Luckily, several library routines are available for various languages to decode URL-encoded data. This makes life easier when creating CGI programs.

Returning Information to the Client

CGI programs return many document types:

  • An image
  • An HTML document
  • A plain-text document
  • An audio clip

Others types are defined by MIME type. CGI programs also can return references to other documents. The client must know what kind of document the program is sending it so it can display it accordingly. For the client to know this, the CGI program must tell the server what type of document it is returning.

To tell the server what kind of document the program is sending back, whether it is a full document or a reference to one, CGI requires the CGI program to place a short header on the output. This header is ASCII text, consisting of lines separated by either line feeds or carriage returns (or both) followed by a single blank line. The output body then follows in its native format.

A Document with MIME Type

For a full document, the CGI program must tell the server what kind of document it is delivering via a MIME type. Examples of common MIME types are text/html for HTML and text/plain for ASCII text.

Here is an example of an HTML document:

Content-type: text/html



<TITLE>Title Goes Here</TITLE>



<H1>Heading Goes Here</H1>

Body of the HTML document.



A Reference to a Document

Instead of sending the document, the CGI program directs the browser to a particular predefined document or has the server automatically send the new one.

An example is an application that sends existing published white papers based on information requests. In this case, the program should know the full URL of the files to reference and send something like the following:

Location: http://www.myserver.com/document_location<lf><lf>

The two line-feed characters form a blank line after the Location: line. The server acts as if the client’s request was for the returned URL instead of the CGI program. It takes care of looking up the file type and sending the appropriate headers.

If you do want to reference a document that is protected by access authentication, the program must have a full URL in the Location: line. This is because the client and the server must retransact to set up access to the referenced document.

If your application needs to send headers such as Content-encoding, your server must be compatible with CGI/1.1. Send the headers and Location or Content-type, and they are sent back to the client.