Fixed a number of issues with SQL query readability and some undefined index-ish errors; consequently the SQL report feature was added
authorDan
Sat, 24 Nov 2007 00:53:23 -0500
changeset 286 b2f985e4cef3
parent 285 7846d45bd250
child 287 f6d144cba8a9
Fixed a number of issues with SQL query readability and some undefined index-ish errors; consequently the SQL report feature was added
includes/common.php
includes/dbal.php
includes/pageprocess.php
includes/paths.php
includes/rijndael.php
includes/sessions.php
includes/tagcloud.php
includes/template.php
index.php
install.php
plugins/SpecialUserFuncs.php
plugins/SpecialUserPrefs.php
plugins/admin/UserManager.php
themes/oxygen/footer.tpl
themes/stpatty/footer.tpl
--- a/includes/common.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/includes/common.php	Sat Nov 24 00:53:23 2007 -0500
@@ -54,16 +54,18 @@
   die(__FILE__.':'.__LINE__.': The debugConsole requires PHP 5.x.x or greater. Please comment out the ENANO_DEBUG constant in your index.php.');
 }
 
+/*
 if(defined('ENANO_DEBUG'))
 {
   require_once(ENANO_ROOT.'/includes/debugger/debugConsole.php');
 } else {
+*/
   function dc_here($m)     { return false; }
   function dc_dump($a, $g) { return false; }
   function dc_watch($n)    { return false; }
   function dc_start_timer($u) { return false; }
   function dc_stop_timer($m) { return false; }
-}
+//}
 
 if ( file_exists( ENANO_ROOT . '/_nightly.php') )
   require(ENANO_ROOT.'/_nightly.php');
--- a/includes/dbal.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/includes/dbal.php	Sat Nov 24 00:53:23 2007 -0500
@@ -27,18 +27,21 @@
     case E_WARNING: case E_USER_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: $errtype = 'Warning'; break;
   }
   $debug = debug_backtrace();
-  $debug = $debug[2]['file'] . ', line ' . $debug[2]['line'];
+  if ( !isset($debug[0]['file']) )
+    return false;
+  $debug = $debug[0]['file'] . ', line ' . $debug[0]['line'];
   echo "<b>$errtype:</b> $errstr<br />Error source:<pre>$debug</pre>";
 }
  
 class mysql {
-  var $num_queries, $query_backtrace, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values;
+  var $num_queries, $query_backtrace, $query_times, $query_sources, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values, $debug;
   var $row = array();
 	var $rowset = array();
   var $errhandler;
   
   function enable_errorhandler()
   {
+    // echo "DBAL: enabling error handler<br />";
     if ( function_exists('debug_backtrace') )
     {
       $this->errhandler = set_error_handler('db_error_handler');
@@ -47,6 +50,7 @@
   
   function disable_errorhandler()
   {
+    // echo "DBAL: disabling error handler<br />";
     if ( $this->errhandler )
     {
       set_error_handler($this->errhandler);
@@ -57,14 +61,9 @@
     }
   }
   
-  function sql_backtrace() {
-    $qb = explode("\n", $this->query_backtrace);
-    $bt = '';
-    //for($i=sizeof($qb)-1;$i>=0;$i--) {
-    for($i=0;$i<sizeof($qb);$i++) {
-      $bt .= $qb[$i]."\n";
-    }
-    return $bt;
+  function sql_backtrace()
+  {
+    return implode("\n-------------------------------------------------------------------\n", $this->query_backtrace);
   }
   
   function ensure_connection()
@@ -170,9 +169,13 @@
     }
     
     // Reset some variables
-    $this->query_backtrace = '';
+    $this->query_backtrace = array();
+    $this->query_times = array();
+    $this->query_sources = array();
     $this->num_queries = 0;
     
+    $this->debug = ( defined('ENANO_DEBUG') );
+    
     dc_here('dbal: we\'re in, selecting database...');
     $q = $this->sql_query('USE `'.$dbname.'`;');
     
@@ -189,8 +192,27 @@
   function sql_query($q)
   {
     $this->enable_errorhandler();
+    
+    if ( $this->debug && function_exists('debug_backtrace') )
+    {
+      $backtrace = @debug_backtrace();
+      if ( is_array($backtrace) )
+      {
+        $bt = $backtrace[0];
+        if ( isset($backtrace[1]['class']) )
+        {
+          if ( $backtrace[1]['class'] == 'sessionManager' )
+          {
+            $bt = $backtrace[1];
+          }
+        }
+        $this->query_sources[$q] = substr($bt['file'], strlen(ENANO_ROOT) + 1) . ', line ' . $bt['line'];
+      }
+      unset($backtrace);
+    }
+    
     $this->num_queries++;
-    $this->query_backtrace .= $q . "\n";
+    $this->query_backtrace[] = $q;
     $this->latest_query = $q;
     dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
     // First make sure we have a connection
@@ -205,7 +227,9 @@
       grinding_halt('SQL Injection attempt', '<p>Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.</p><p>Query was:</p><pre>'.htmlspecialchars($q).'</pre>');
     }
     
+    $time_start = microtime_float();
     $r = mysql_query($q, $this->_conn);
+    $this->query_times[$q] = microtime_float() - $time_start;
     $this->latest_result = $r;
     $this->disable_errorhandler();
     return $r;
@@ -214,8 +238,9 @@
   function sql_unbuffered_query($q)
   {
     $this->enable_errorhandler();
+    
     $this->num_queries++;
-    $this->query_backtrace .= '(UNBUFFERED) ' . $q."\n";
+    $this->query_backtrace[] = '(UNBUFFERED) ' . $q;
     $this->latest_query = $q;
     dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
     // First make sure we have a connection
@@ -230,7 +255,9 @@
       grinding_halt('SQL Injection attempt', '<p>Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.</p><p>Query was:</p><pre>'.htmlspecialchars($q).'</pre>');
     }
     
+    $time_start = microtime_float();
     $r = mysql_unbuffered_query($q, $this->_conn);
+    $this->query_times[$q] = microtime_float() - $time_start;
     $this->latest_result = $r;
     $this->disable_errorhandler();
     return $r;
@@ -681,6 +708,70 @@
 			return false;
 		}
 	}
+  /**
+   * Generates and outputs a report of all the SQL queries made during execution. Should only be called after everything's over with.
+   */
+  
+  function sql_report()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( !$session->get_permissions('mod_misc') )
+    {
+      die_friendly('Access denied', '<p>You are not authorized to generate a SQL backtrace.</p>');
+    }
+    // Create copies of variables that may be changed after header is called
+    $backtrace = $this->query_backtrace;
+    $times = $this->query_times;
+    $template->header();
+    echo '<h3>SQL query log and timetable</h3>';
+    echo '<div class="tblholder">
+            <table border="0" cellspacing="1" cellpadding="4">';
+    $i = 0;
+    foreach ( $backtrace as $query )
+    {
+      $i++;
+      $unbuffered = false;
+      if ( substr($query, 0, 13) == '(UNBUFFERED) ' )
+      {
+        $query = substr($query, 13);
+        $unbuffered = true;
+      }
+      if ( $i == 1 )
+      {
+        echo '<tr>
+                <th colspan="2">SQL backtrace for a normal page load of ' . htmlspecialchars($paths->cpage['urlname']) . '</th>
+              </tr>';
+      }
+      else
+      {
+        echo '<tr>
+                <th class="subhead" colspan="2">&nbsp;</th>
+              </tr>';
+      }
+      echo '<tr>
+              <td class="row2">Query:</td>
+              <td class="row1"><pre>' . htmlspecialchars($query) . '</pre></td>
+            </tr>
+            <tr>
+              <td class="row2">Time:</td>
+              <td class="row1">' . number_format($this->query_times[$query], 6) . ' seconds</td>
+            </tr>
+            <tr>
+              <td class="row2">Unbuffered:</td>
+              <td class="row1">' . ( $unbuffered ? 'Yes' : 'No' ) . '</td>
+            </tr>';
+      if ( isset($this->query_sources[$query]) )
+      {
+        echo '<tr>
+                <td class="row2">Called from:</td>
+                <td class="row1">' . $this->query_sources[$query] . '</td>
+              </tr>';
+      }
+    }
+    echo '  </table>
+          </div>';
+    $template->footer();
+  }
 }
 
 ?>
--- a/includes/pageprocess.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/includes/pageprocess.php	Sat Nov 24 00:53:23 2007 -0500
@@ -166,13 +166,16 @@
         $this->send_headers = false;
         $strict_no_headers = true;
       }
-      if ( $paths->pages[$pathskey]['password'] != '' && $paths->pages[$pathskey]['password'] != sha1('') )
+      if ( isset($paths->pages[$pathskey]['password']) )
       {
-        $password =& $paths->pages[$pathskey]['password'];
-        if ( $this->password != $password )
+        if ( $paths->pages[$pathskey]['password'] != '' && $paths->pages[$pathskey]['password'] != sha1('') )
         {
-          $this->err_wrong_password();
-          return false;
+          $password =& $paths->pages[$pathskey]['password'];
+          if ( $this->password != $password )
+          {
+            $this->err_wrong_password();
+            return false;
+          }
         }
       }
     }
--- a/includes/paths.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/includes/paths.php	Sat Nov 24 00:53:23 2007 -0500
@@ -118,7 +118,8 @@
       eval($cmd);
     }
     
-    $e = $db->sql_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;');
+    $e = $db->sql_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,' . "\n"
+                        . '  delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;');
     if( !$e )
     {
       $db->_die('The error seems to have occured while selecting the page information. File: includes/paths.php; line: '.__LINE__);
--- a/includes/rijndael.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/includes/rijndael.php	Sat Nov 24 00:53:23 2007 -0500
@@ -16,10 +16,13 @@
 define ('ENC_BASE64', 202);
 define ('ENC_BINARY', 203);
 
+$_aes_objcache = array();
+
 class AESCrypt {
   
   var $debug = false;
   var $mcrypt = false;
+  var $decrypt_cache = array();
 
   // Rijndael parameters --  Valid values are 128, 192, or 256
   
@@ -128,6 +131,18 @@
     $this->debug = $debug;
   }
   
+  function singleton($key_size, $block_size)
+  {
+    global $_aes_objcache;
+    if ( isset($_aes_objcache["$key_size,$block_size"]) )
+    {
+      return $_aes_objcache["$key_size,$block_size"];
+    }
+    
+    $_aes_objcache["$key_size,$block_size"] = new AESCrypt($key_size, $block_size);
+    return $_aes_objcache["$key_size,$block_size"];
+  }
+  
   // Error handler
   
   function trigger_error($text, $level = E_USER_NOTICE)
@@ -804,6 +819,14 @@
   {
     if ( $text == '' )
       return '';
+    $text_orig = $text;
+    if ( isset($this->decrypt_cache[$key]) && is_array($this->decrypt_cache[$key]) )
+    {
+      if ( isset($this->decrypt_cache[$key][$text]) )
+      {
+        return $this->decrypt_cache[$key][$text];
+      }
+    }
     switch($input_encoding)
     {
       case ENC_BINARY:
@@ -838,6 +861,11 @@
       }
       $dypt = $this->byteArrayToString($dypt);
     }
+    if ( !isset($this->decrypt_cache[$key]) )
+      $this->decrypt_cache[$key] = array();
+    
+    $this->decrypt_cache[$key][$text_orig] = $dypt;
+    
     return $dypt;
   }
   
--- a/includes/sessions.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/includes/sessions.php	Sat Nov 24 00:53:23 2007 -0500
@@ -150,7 +150,6 @@
    * @var string
    */
    
-  //var $valid_username = '([A-Za-z0-9 \!\@\(\)-]+)';
   var $valid_username = '([^<>&\?\'"%\n\r\t\a\/]+)';
    
   /**
@@ -282,7 +281,7 @@
       {
         // Generate and stash a private key
         // This should only happen during an automated silent gradual migration to the new encryption platform.
-        $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+        $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
         $this->private_key = $aes->gen_readymade_key();
         
         $config = file_get_contents(ENANO_ROOT.'/config.php');
@@ -500,7 +499,10 @@
           else
           {
             $key = strrev($_REQUEST['auth']);
-            $super = $this->validate_session($key);
+            if ( !empty($key) && ( strlen($key) / 2 ) % 4 == 0 )
+            {
+              $super = $this->validate_session($key);
+            }
           }
           if(is_array($super))
           {
@@ -518,13 +520,13 @@
     if(!$this->compat)
     {
       // init groups
-      $q = $this->sql('SELECT g.group_name,g.group_id,m.is_mod FROM '.table_prefix.'groups AS g
-          LEFT JOIN '.table_prefix.'group_members AS m
-            ON g.group_id=m.group_id
-          WHERE ( m.user_id='.$this->user_id.' 
-            OR g.group_name=\'Everyone\')
-            ' . ( enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '
-          ORDER BY group_id ASC;'); // Make sure "Everyone" comes first so the permissions can be overridden
+      $q = $this->sql('SELECT g.group_name,g.group_id,m.is_mod FROM '.table_prefix.'groups AS g' . "\n"
+        . '  LEFT JOIN '.table_prefix.'group_members AS m' . "\n"
+        . '    ON g.group_id=m.group_id' . "\n"
+        . '  WHERE ( m.user_id='.$this->user_id.'' . "\n" 
+        . '    OR g.group_name=\'Everyone\')' . "\n"
+        . '    ' . ( enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '' . "\n"
+        . '  ORDER BY group_id ASC;'); // Make sure "Everyone" comes first so the permissions can be overridden
       if($row = $db->fetchrow())
       {
         do {
@@ -566,7 +568,7 @@
     $privcache = $this->private_key;
     
     // Instanciate the Rijndael encryption object
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     
     // Fetch our decryption key
     
@@ -714,7 +716,7 @@
     }
     
     // Instanciate the Rijndael encryption object
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     
     // Initialize our success switch
     $success = false;
@@ -862,7 +864,7 @@
     $session_key = "u=$username;p=$passha1;s=$salt";
     
     // Encrypt the key
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     $session_key = $aes->encrypt($session_key, $this->private_key, ENC_HEX);
     
     // If we're registering an elevated-privilege key, it needs to be on GET
@@ -968,7 +970,8 @@
     
     if ( !$decrypted_key )
     {
-      die_semicritical('AES encryption error', '<p>Something went wrong during the AES decryption process.</p><pre>'.print_r($decrypted_key, true).'</pre>');
+      // die_semicritical('AES encryption error', '<p>Something went wrong during the AES decryption process.</p><pre>'.print_r($decrypted_key, true).'</pre>');
+      return false;
     }
     
     $n = preg_match('/^u='.$this->valid_username.';p=([A-Fa-f0-9]+?);s=([A-Fa-f0-9]+?)$/', $decrypted_key, $keydata);
@@ -979,16 +982,19 @@
     }
     $keyhash = md5($key);
     $salt = $db->escape($keydata[3]);
-    $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,x.* FROM '.table_prefix.'session_keys AS k
-                               LEFT JOIN '.table_prefix.'users AS u
-                                 ON ( u.user_id=k.user_id )
-                               LEFT JOIN '.table_prefix.'users_extra AS x
-                                 ON ( u.user_id=x.user_id OR x.user_id IS NULL )
-                               LEFT JOIN '.table_prefix.'privmsgs AS p
-                                 ON ( p.message_to=u.username AND p.message_read=0 )
-                               WHERE k.session_key=\''.$keyhash.'\'
-                                 AND k.salt=\''.$salt.'\'
-                               GROUP BY u.user_id;');
+    // using a normal call to $db->sql_query to avoid failing on errors here
+    $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,' . "\n"
+                             . '    u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,' . "\n"
+                             . '    x.* FROM '.table_prefix.'session_keys AS k' . "\n"
+                             . '  LEFT JOIN '.table_prefix.'users AS u' . "\n"
+                             . '    ON ( u.user_id=k.user_id )' . "\n"
+                             . '  LEFT JOIN '.table_prefix.'users_extra AS x' . "\n"
+                             . '    ON ( u.user_id=x.user_id OR x.user_id IS NULL )' . "\n"
+                             . '  LEFT JOIN '.table_prefix.'privmsgs AS p' . "\n"
+                             . '    ON ( p.message_to=u.username AND p.message_read=0 )' . "\n"
+                             . '  WHERE k.session_key=\''.$keyhash.'\'' . "\n"
+                             . '    AND k.salt=\''.$salt.'\'' . "\n"
+                             . '  GROUP BY u.user_id;');
     if ( !$query )
     {
       $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms FROM '.table_prefix.'session_keys AS k
@@ -1133,7 +1139,7 @@
     $oid = $this->user_id;
     if($level > USER_LEVEL_CHPREF)
     {
-      $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+      $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
       if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD) return 'success';
       // Destroy elevated privileges
       $keyhash = md5(strrev($this->sid_super));
@@ -1209,7 +1215,7 @@
    
   function rijndael_genkey()
   {
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     $key = $aes->gen_readymade_key();
     $keys = getConfig('login_key_cache');
     if(is_string($keys))
@@ -1227,7 +1233,7 @@
    
   function dss_rand()
   {
-    $aes = new AESCrypt();
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     $random = $aes->randkey(128);
     unset($aes);
     return md5(microtime() . $random);
@@ -1344,7 +1350,7 @@
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
     $col_reason = ( $this->compat ) ? '"No reason entered (session manager is in compatibility mode)" AS reason' : 'reason';
-    $is_banned = false;
+    $banned = false;
     if ( $this->user_logged_in )
     {
       // check by IP, email, and username
@@ -1439,7 +1445,7 @@
     global $db, $session, $paths, $template, $plugins; // Common objects
     
     // Initialize AES
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     
     if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.';
     $username = str_replace('_', ' ', $username);
@@ -1795,7 +1801,7 @@
    
   function register_temp_password($user_id, $password)
   {
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     $temp_pass = $aes->encrypt($password, $this->private_key, ENC_HEX);
     $this->sql('UPDATE '.table_prefix.'users SET temp_password=\'' . $temp_pass . '\',temp_password_time='.time().' WHERE user_id='.intval($user_id).';');
   }
@@ -1906,7 +1912,7 @@
     if(intval($user_id) < 1) $errors[] = 'SQL injection attempt';
     
     // Instanciate the AES encryption class
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     
     // If all of our input vars are false, then we've effectively done our job so get out of here
     if($username === false && $password === false && $email === false && $realname === false && $signature === false && $user_level === false)
@@ -2200,7 +2206,9 @@
     $this->acl_defaults_used = $this->perms;
     
     // Fetch sitewide defaults from the permissions table
-    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE page_id IS NULL AND namespace IS NULL AND ( ';
+    $bs = 'SELECT rules, target_type, target_id FROM '.table_prefix.'acl' . "\n"
+             . '  WHERE page_id IS NULL AND namespace IS NULL AND' . "\n"
+             . '  ( ';
     
     $q = Array();
     $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
@@ -2211,7 +2219,7 @@
         $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
       }
     }
-    $bs .= implode(' OR ', $q) . ' ) ORDER BY target_type ASC, target_id ASC;';
+    $bs .= implode(" OR \n    ", $q) . " ) \n  ORDER BY target_type ASC, target_id ASC;";
     $q = $this->sql($bs);
     if ( $row = $db->fetchrow() )
     {
@@ -2255,7 +2263,7 @@
     }
     // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
     // permissions to override group permissions.
-    $bs .= implode(' OR ', $q) . ' ) AND (' . $pg_info . ' ( page_id=\''.$db->escape($paths->cpage['urlname_nons']).'\' AND namespace=\''.$db->escape($paths->namespace).'\' ) )     
+    $bs .= implode(" OR\n    ", $q) . " )\n  AND (" . $pg_info . ' ( page_id=\''.$db->escape($paths->cpage['urlname_nons']).'\' AND namespace=\''.$db->escape($paths->namespace).'\' ) )     
       ORDER BY target_type ASC, page_id ASC, namespace ASC;';
     $q = $this->sql($bs);
     if ( $row = $db->fetchrow() )
@@ -2697,7 +2705,8 @@
     }
     
     // Build a query to grab ACL info
-    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE ( ';
+    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE ' . "\n"
+          . '  ( ';
     $q = Array();
     $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$session->user_id.' )';
     if(count($session->groups) > 0)
@@ -2709,7 +2718,7 @@
     }
     // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
     // permissions to override group permissions.
-    $bs .= implode(' OR ', $q) . ' ) AND (' . $pg_info . ' page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\' )     
+    $bs .= implode(" OR\n    ", $q) . ' ) AND (' . $pg_info . ' page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\' )     
       ORDER BY target_type ASC, page_id ASC, namespace ASC;';
     $q = $session->sql($bs);
     if ( $row = $db->fetchrow() )
--- a/includes/tagcloud.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/includes/tagcloud.php	Sat Nov 24 00:53:23 2007 -0500
@@ -35,7 +35,7 @@
    * @param array Optional. An initial list of words, just a plain old array.
    */
   
-  function __construct($words)
+  function __construct($words = array())
   {
     if ( count($words) > 0 )
     {
--- a/includes/template.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/includes/template.php	Sat Nov 24 00:53:23 2007 -0500
@@ -748,7 +748,8 @@
       'STYLE_ID'=>$this->style,
       'JS_DYNAMIC_VARS'=>$js_dynamic,
       'UNREAD_PMS'=>$session->unread_pms,
-      'URL_ABOUT_ENANO' => makeUrlNS('Special', 'About_Enano', '', true)
+      'URL_ABOUT_ENANO' => makeUrlNS('Special', 'About_Enano', '', true),
+      'REPORT_URI' => makeUrl($paths->page, 'do=sql_report', true)
       );
     
     foreach ( $paths->nslist as $ns_id => $ns_prefix )
@@ -1047,7 +1048,7 @@
           continue;
         
         $tag_complete = <<<TPLCODE
-        ';
+';
         /* START OF CONDITION: $type ($test) */
         if ( $cond )
         {
@@ -1605,7 +1606,8 @@
     if ( !$this->fetch_block('Links') )
       $this->initLinksWidget();
     
-    $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;');
+    $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar' . "\n"
+                           . '  WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;');
     if(!$q) $db->_die('The sidebar text data could not be selected.');
     
     $vars = $this->extract_vars('elements.tpl');
@@ -1794,7 +1796,8 @@
  * "critical error" messages. ** REQUIRES ** the Oxygen theme.
  */
 
-class template_nodb {
+class template_nodb
+{
   var $fading_button, $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list;
   function __construct() {
     
--- a/index.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/index.php	Sat Nov 24 00:53:23 2007 -0500
@@ -429,6 +429,17 @@
       $data = ( isset($_POST['data']) ) ? $_POST['data'] : Array('mode' => 'listgroups');
       PageUtils::aclmanager($data);
       break;
+    case 'sql_report':
+      $rev_id = ( (isset($_GET['oldid'])) ? intval($_GET['oldid']) : 0 );
+      $page = new PageProcessor( $paths->cpage['urlname_nons'], $paths->namespace, $rev_id );
+      $page->send_headers = true;
+      $pagepass = ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '';
+      $page->password = $pagepass;
+      $page->send(true);
+      ob_end_clean();
+      ob_start();
+      $db->sql_report();
+      break;
   }
   
   //
@@ -438,7 +449,7 @@
   {
     // Load up the HTML
     $html = ob_get_contents();
-    ob_end_clean();
+    @ob_end_clean();
     
     $html = aggressive_optimize_html($html);
     
--- a/install.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/install.php	Sat Nov 24 00:53:23 2007 -0500
@@ -329,7 +329,7 @@
   if ( $act_get )
     return $decrypted_pass;
   
-  $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+  $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
   
   if ( !empty($_POST['crypt_data']) )
   {
@@ -359,7 +359,7 @@
   if ( $act_get )
     return $key;
   
-  $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+  $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
   $key = $aes->gen_readymade_key();
   return true;
 }
@@ -372,7 +372,7 @@
   
   $admin_pass = stg_decrypt_admin_pass(true);
   $key = stg_generate_aes_key(true);
-  $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+  $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
   $key = $aes->hextostring($key);
   $admin_pass = $aes->encrypt($admin_pass, $key, ENC_HEX);
   
@@ -452,7 +452,7 @@
   {
     $admin_pass = stg_decrypt_admin_pass(true);
     $key = stg_generate_aes_key(true);
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     $key = $aes->hextostring($key);
     $admin_pass = $aes->encrypt($admin_pass, $key, ENC_HEX);
     $admin_user = mysql_real_escape_string($_POST['admin_user']);
@@ -1334,7 +1334,7 @@
     }
     unset($_POST['_cont']);
     require('config.new.php');
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     if ( isset($crypto_key) )
     {
       $cryptkey = $crypto_key;
--- a/plugins/SpecialUserFuncs.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/plugins/SpecialUserFuncs.php	Sat Nov 24 00:53:23 2007 -0500
@@ -376,7 +376,7 @@
         
         if ( $_POST['use_crypt'] == 'yes' )
         {
-          $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+          $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
           $crypt_key = $session->fetch_public_key($_POST['crypt_key']);
           if ( !$crypt_key )
           {
@@ -1067,7 +1067,7 @@
     
     if ( isset($_POST['do_stage2']) )
     {
-      $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+      $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
       if($_POST['use_crypt'] == 'yes')
       {
         $crypt_key = $session->fetch_public_key($_POST['crypt_key']);
--- a/plugins/SpecialUserPrefs.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/plugins/SpecialUserPrefs.php	Sat Nov 24 00:53:23 2007 -0500
@@ -25,7 +25,7 @@
 function userprefs_menu_add($section, $text, $link)
 {
   global $userprefs_menu;
-  if ( is_array($userprefs_menu[$section]) )
+  if ( isset($userprefs_menu[$section]) && is_array($userprefs_menu[$section]) )
   {
     $userprefs_menu[$section][] = Array(
       'text' => $text,
@@ -133,7 +133,7 @@
   $uid = intval($session->user_id);
   
   // Instanciate the AES encryptor
-  $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+  $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
   
   // Basic user info
   $q = $db->sql_query('SELECT username, password, email, real_name, signature, theme, style FROM '.table_prefix.'users WHERE user_id='.$uid.';');
--- a/plugins/admin/UserManager.php	Fri Nov 23 17:59:24 2007 -0500
+++ b/plugins/admin/UserManager.php	Sat Nov 24 00:53:23 2007 -0500
@@ -68,7 +68,7 @@
         $password = false;
         if ( $_POST['changing_pw'] == 'yes' )
         {
-          $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+          $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
           $key_hex_md5 = $_POST['crypt_key'];
           $key_hex = $session->fetch_public_key($key_hex_md5);
           if ( $key_hex )
@@ -348,7 +348,7 @@
     else
     {
       // Get the current session information so the user doesn't get logged out
-      $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+      $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
       $sk = md5(strrev($session->sid_super));
       $qb = $db->sql_query('SELECT session_key,salt,auth_level,source_ip,time FROM '.table_prefix.'session_keys WHERE session_key=\''.$sk.'\' AND user_id='.$session->user_id.' AND auth_level='.USER_LEVEL_ADMIN);
       if ( !$qb )
@@ -544,21 +544,12 @@
    * Constructor.
    */
   
-  function __construct()
+  function Admin_UserManager_SmartForm()
   {
     $this->uuid = md5( mt_rand() . microtime() );
   }
   
   /**
-   * PHP4 constructor.
-   */
-  
-  function Admin_UserManager_SmartForm()
-  {
-    $this->__construct();
-  }
-  
-  /**
    * Renders and returns the finished form.
    * @return string
    */
--- a/themes/oxygen/footer.tpl	Fri Nov 23 17:59:24 2007 -0500
+++ b/themes/oxygen/footer.tpl	Sat Nov 24 00:53:23 2007 -0500
@@ -12,7 +12,7 @@
                  -->
             <div id="credits">
               <b>{COPYRIGHT}</b><br />
-              Website engine powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>&nbsp;&nbsp;|&nbsp;&nbsp;Generated in [[GenTime]]sec
+              Website engine powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>&nbsp;&nbsp;|&nbsp;&nbsp;Generated in [[GenTime]]sec<!-- BEGIN auth_admin -->&nbsp;&nbsp;|&nbsp;&nbsp;<a href="{REPORT_URI}">[[NumQueries]] SQL</a><!-- END auth_admin -->
               <!-- Do not remove this line or scheduled tasks will not run. -->
               <img alt=" " src="{SCRIPTPATH}/cron.php" width="1" height="1" />
             </div>
--- a/themes/stpatty/footer.tpl	Fri Nov 23 17:59:24 2007 -0500
+++ b/themes/stpatty/footer.tpl	Sat Nov 24 00:53:23 2007 -0500
@@ -10,7 +10,7 @@
                  -Dan
                  -->
           <b>{COPYRIGHT}</b><br />
-          Powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a>  |  <a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>  |  <a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>  |  [[Stats]]
+          Powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>&nbsp;&nbsp;|&nbsp;&nbsp;Time: [[GenTime]]s<!-- BEGIN auth_admin -->&nbsp;&nbsp;|&nbsp;&nbsp;<a href="{REPORT_URI}">[[NumQueries]] SQL</a><!-- END auth_admin -->
           <!-- Do not remove this line or scheduled tasks will not run. -->
           <img alt=" " src="{SCRIPTPATH}/cron.php" width="1" height="1" />
         </div>