Watcher: PHP Session Variables Tracker

<?php
  ////////////////////////////////////////////////////////////////////////////
  // watcher.php
  //
  // utility to display current session vars for PHP troubleshooting, with
  //   output a bit more organized than print_r(); to use, open new tab in
  //   the same browser running the application which is generating/using
  //   the session vars of interest; default behavior is to display all
  //   active session vars; a session variable prefix may be provided as a
  //   GET parm to display only those vars; for example,
  //
  //       http://mywebsite.com/watcher.php?prefix=test_
  //
  //   will retrieve and display only those vars at the topmost level which
  //     begin with "test_"
  //
  // output is Web page showing all matching session vars and their values; 
  //   arrays are nested, color-coded, and recursively expanded; because the 
  //   arrays are walked recursively, there is no practical limit on the 
  //   levels to which the arrays may be nested (although the display may get 
  //   funky if nested too deep); the output page is not particularly pretty, 
  //   but this is intended only as a development tool, not a polished Web page
  //
  // note the display order is the same as the creation order; the PHP
  //   function ksort() could be used to make locating a specific item
  //   by key name easier
  //
  // Written 11/27/2010, L.Pritchett, Cliffson Solutions, LLC
  // Revised 2/21/2015, L.Pritchett, Cliffson Solutions, LLC
  ////////////////////////////////////////////////////////////////////////////

  session_start();

  //==========================================================================
  // global constants
  //==========================================================================

  // colors are used in sequence, wrapping back to the first color if nesting
  //   exceeds the number of defined colors; colors may be added, deleted, or 
  //   modified freely with no change in the code below; if color coding of
  //   each level is not desired, remove all colors but one

  $aCOLORS = array ("blue", "green", "crimson", "magenta", "brown", "orange",
    "black");

  // indent in pixels for each array level in displayed page

  define("iINDENT_DISPLAY", 20);

  // indent for HTML code itself (makes for easier troubleshooting)

  define("iINDENT_HTML", 2);

  //==========================================================================
  //  functions
  //==========================================================================

  function fnDisplay_Var($sname, $sval, $ilevel)
  {
    // display given var/val pair; indent HTML code appropriately

    // handle special cases: turn NULLs and Booleans into something printable, 
    //   add quotes to strings

    if (is_null($sval))
      $sval = "NULL";
    else if (is_bool($sval))
      $sval = $sval ? "true" : "false";
    else if (is_string($sval))
      $sval = sprintf("\"%s\"", $sval);

    printf("%s%s =&gt; %s\n", str_repeat(" ", $ilevel * iINDENT_HTML), 
      htmlspecialchars($sname), htmlspecialchars($sval));
    printf("%s<br />\n", str_repeat(" ", $ilevel * iINDENT_HTML));
  }


  function fnWalk_Array($sname, $oval, $ilevel)
  {
    // recursive function to walk all elements of array and display
    //   each member, indenting each new level and changing the display
    //   color for easier tracking

    global $aCOLORS;

    if (is_array($oval))
    {
      // write array name at current indent level

      printf("%s%s =>\n", str_repeat(" ", $ilevel * iINDENT_HTML), 
        htmlspecialchars($sname));

      // create new indented div with new text color

      $ilevel++;
      printf("%s<div style=\"margin-left:%dpx;color:%s;\">\n",
        str_repeat(" ", $ilevel * iINDENT_HTML), iINDENT_DISPLAY, 
        $aCOLORS[$ilevel % count($aCOLORS)]);

      // walk through all elements of array, calling this function
      //   recursively if any of those are also arrays

      foreach ($oval as $schild_name => $ochild_val)
        fnWalk_Array($schild_name, $ochild_val, $ilevel);
      printf("%s</div>\n", str_repeat(" ", $ilevel * iINDENT_HTML));
    }
    else
    {
      // if not array, write var/val pair and end recursion

      fnDisplay_Var($sname, $oval, $ilevel);
    }
    return;
  }

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

  <title>PHP Session Reporter</title>
</head>

<body>
<center>
  <h3>Current Session Variables</h3>

<?php
  // create refresh button; could be eliminated, as a browser refresh works
  //   just as well

  printf("  <button onclick=\"document.location='%s%s'\">\n",
    $_SERVER['SCRIPT_NAME'], (!empty($_SERVER['QUERY_STRING']) &&
    ($_SERVER['QUERY_STRING'] != "clear=true")) ?
    "?" . $_SERVER['QUERY_STRING'] : "");
  printf("    Refresh\n");
  printf("  </button>\n");

  printf("  <button onclick=\"document.location='%s%s?clear=true'\">\n",
    $_SERVER['SCRIPT_NAME'], (!empty($_SERVER['QUERY_STRING']) &&
    ($_SERVER['QUERY_STRING'] != "clear=true")) ?
    "&" . $_SERVER['QUERY_STRING'] : "");
  printf("    Clear\n");
  printf("  </button>\n");
?>

  <hr />
</center>
<br />
<br />

<?php
  //==========================================================================
  // start inline code
  //==========================================================================

  // if clear option selected, do that first

  if (!empty($_GET['clear']))
    foreach ($_SESSION as $sVar => $sVal)
      unset($_SESSION[$sVar]);

  if (empty($_SESSION))
    printf("  No session variables are currently defined\n");
  else
  {
    // start primary block in 1st color

    printf("<div style=\"color:%s;\">\n", $aCOLORS[0]);
    foreach($_SESSION as $sName => $oVal)
    {
      // if prefix specified, only display variables that match; note this
      //   screening is only done on 1st layer variable names, not on
      //   array members or their descendents

      if (empty($_GET['prefix']) || (strpos($sName, $_GET['prefix']) === 0))
      {
        if (is_array($oVal))
          fnWalk_Array($sName, $oVal, 0);
        else
          fnDisplay_Var($sName, $oVal, 0);
      }
    }
    printf("</div>\n");
  }
?>

</body>
</html>