includes/dbal.php
changeset 304 e2cb5f1432c8
parent 279 8acd77a6c19d
parent 293 3f98d4ba1e33
child 313 854eecfada20
equal deleted inserted replaced
280:dc08c70ca550 304:e2cb5f1432c8
    25   {
    25   {
    26     case E_ERROR: case E_USER_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: $errtype = 'Error'; break;
    26     case E_ERROR: case E_USER_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: $errtype = 'Error'; break;
    27     case E_WARNING: case E_USER_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: $errtype = 'Warning'; break;
    27     case E_WARNING: case E_USER_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: $errtype = 'Warning'; break;
    28   }
    28   }
    29   $debug = debug_backtrace();
    29   $debug = debug_backtrace();
    30   $debug = $debug[2]['file'] . ', line ' . $debug[2]['line'];
    30   if ( !isset($debug[0]['file']) )
       
    31     return false;
       
    32   $debug = $debug[0]['file'] . ', line ' . $debug[0]['line'];
    31   echo "<b>$errtype:</b> $errstr<br />Error source:<pre>$debug</pre>";
    33   echo "<b>$errtype:</b> $errstr<br />Error source:<pre>$debug</pre>";
    32 }
    34 }
    33  
    35  
    34 class mysql {
    36 class mysql {
    35   var $num_queries, $query_backtrace, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values;
    37   var $num_queries, $query_backtrace, $query_times, $query_sources, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values, $debug;
    36   var $row = array();
    38   var $row = array();
    37 	var $rowset = array();
    39 	var $rowset = array();
    38   var $errhandler;
    40   var $errhandler;
    39   
    41   
    40   function enable_errorhandler()
    42   function enable_errorhandler()
    41   {
    43   {
       
    44     // echo "DBAL: enabling error handler<br />";
    42     if ( function_exists('debug_backtrace') )
    45     if ( function_exists('debug_backtrace') )
    43     {
    46     {
    44       $this->errhandler = set_error_handler('db_error_handler');
    47       $this->errhandler = set_error_handler('db_error_handler');
    45     }
    48     }
    46   }
    49   }
    47   
    50   
    48   function disable_errorhandler()
    51   function disable_errorhandler()
    49   {
    52   {
       
    53     // echo "DBAL: disabling error handler<br />";
    50     if ( $this->errhandler )
    54     if ( $this->errhandler )
    51     {
    55     {
    52       set_error_handler($this->errhandler);
    56       set_error_handler($this->errhandler);
    53     }
    57     }
    54     else
    58     else
    55     {
    59     {
    56       restore_error_handler();
    60       restore_error_handler();
    57     }
    61     }
    58   }
    62   }
    59   
    63   
    60   function sql_backtrace() {
    64   function sql_backtrace()
    61     $qb = explode("\n", $this->query_backtrace);
    65   {
    62     $bt = '';
    66     return implode("\n-------------------------------------------------------------------\n", $this->query_backtrace);
    63     //for($i=sizeof($qb)-1;$i>=0;$i--) {
       
    64     for($i=0;$i<sizeof($qb);$i++) {
       
    65       $bt .= $qb[$i]."\n";
       
    66     }
       
    67     return $bt;
       
    68   }
    67   }
    69   
    68   
    70   function ensure_connection()
    69   function ensure_connection()
    71   {
    70   {
    72     if(!$this->_conn)
    71     if(!$this->_conn)
   125   {
   124   {
   126     $this->enable_errorhandler();
   125     $this->enable_errorhandler();
   127     
   126     
   128     dc_here('dbal: trying to connect....');
   127     dc_here('dbal: trying to connect....');
   129     
   128     
   130     if ( defined('IN_ENANO_INSTALL') )
   129     if ( defined('IN_ENANO_INSTALL') && !defined('IN_ENANO_UPGRADE') )
   131     {
   130     {
   132       @include(ENANO_ROOT.'/config.new.php');
   131       @include(ENANO_ROOT.'/config.new.php');
   133     }
   132     }
   134     else
   133     else
   135     {
   134     {
   146       if ( !defined('scriptPath') )
   145       if ( !defined('scriptPath') )
   147       {
   146       {
   148         if ( isset($_SERVER['PATH_INFO']) && !preg_match('/index\.php$/', $_SERVER['PATH_INFO']) )
   147         if ( isset($_SERVER['PATH_INFO']) && !preg_match('/index\.php$/', $_SERVER['PATH_INFO']) )
   149         {
   148         {
   150           $_SERVER['REQUEST_URI'] = preg_replace(';' . preg_quote($_SERVER['PATH_INFO']) . '$;', '', $_SERVER['REQUEST_URI']);
   149           $_SERVER['REQUEST_URI'] = preg_replace(';' . preg_quote($_SERVER['PATH_INFO']) . '$;', '', $_SERVER['REQUEST_URI']);
       
   150         }
       
   151         if ( !preg_match('/\.php$/', $_SERVER['REQUEST_URI']) )
       
   152         {
       
   153           // user requested http://foo/enano as opposed to http://foo/enano/index.php
       
   154           $_SERVER['REQUEST_URI'] .= '/index.php';
   151         }
   155         }
   152         $sp = dirname($_SERVER['REQUEST_URI']);
   156         $sp = dirname($_SERVER['REQUEST_URI']);
   153         if($sp == '/' || $sp == '\\') $sp = '';
   157         if($sp == '/' || $sp == '\\') $sp = '';
   154         define('scriptPath', $sp);
   158         define('scriptPath', $sp);
   155         define('contentPath', "$sp/index.php?title=");
   159         define('contentPath', "$sp/index.php?title=");
   168       dc_here('dbal: uhoh!<br />'.mysql_error());
   172       dc_here('dbal: uhoh!<br />'.mysql_error());
   169       grinding_halt('Enano is having a problem', '<p>Error: couldn\'t connect to MySQL.<br />'.mysql_error().'</p>');
   173       grinding_halt('Enano is having a problem', '<p>Error: couldn\'t connect to MySQL.<br />'.mysql_error().'</p>');
   170     }
   174     }
   171     
   175     
   172     // Reset some variables
   176     // Reset some variables
   173     $this->query_backtrace = '';
   177     $this->query_backtrace = array();
       
   178     $this->query_times = array();
       
   179     $this->query_sources = array();
   174     $this->num_queries = 0;
   180     $this->num_queries = 0;
       
   181     
       
   182     $this->debug = ( defined('ENANO_DEBUG') );
   175     
   183     
   176     dc_here('dbal: we\'re in, selecting database...');
   184     dc_here('dbal: we\'re in, selecting database...');
   177     $q = $this->sql_query('USE `'.$dbname.'`;');
   185     $q = $this->sql_query('USE `'.$dbname.'`;');
   178     
   186     
   179     if ( !$q )
   187     if ( !$q )
   187   }
   195   }
   188   
   196   
   189   function sql_query($q)
   197   function sql_query($q)
   190   {
   198   {
   191     $this->enable_errorhandler();
   199     $this->enable_errorhandler();
       
   200     
       
   201     if ( $this->debug && function_exists('debug_backtrace') )
       
   202     {
       
   203       $backtrace = @debug_backtrace();
       
   204       if ( is_array($backtrace) )
       
   205       {
       
   206         $bt = $backtrace[0];
       
   207         if ( isset($backtrace[1]['class']) )
       
   208         {
       
   209           if ( $backtrace[1]['class'] == 'sessionManager' )
       
   210           {
       
   211             $bt = $backtrace[1];
       
   212           }
       
   213         }
       
   214         $this->query_sources[$q] = substr($bt['file'], strlen(ENANO_ROOT) + 1) . ', line ' . $bt['line'];
       
   215       }
       
   216       unset($backtrace);
       
   217     }
       
   218     
   192     $this->num_queries++;
   219     $this->num_queries++;
   193     $this->query_backtrace .= $q . "\n";
   220     $this->query_backtrace[] = $q;
   194     $this->latest_query = $q;
   221     $this->latest_query = $q;
   195     dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
   222     dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
   196     // First make sure we have a connection
   223     // First make sure we have a connection
   197     if ( !$this->_conn )
   224     if ( !$this->_conn )
   198     {
   225     {
   203     {
   230     {
   204       $this->report_query($q);
   231       $this->report_query($q);
   205       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>');
   232       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>');
   206     }
   233     }
   207     
   234     
       
   235     $time_start = microtime_float();
   208     $r = mysql_query($q, $this->_conn);
   236     $r = mysql_query($q, $this->_conn);
       
   237     $this->query_times[$q] = microtime_float() - $time_start;
   209     $this->latest_result = $r;
   238     $this->latest_result = $r;
   210     $this->disable_errorhandler();
   239     $this->disable_errorhandler();
   211     return $r;
   240     return $r;
   212   }
   241   }
   213   
   242   
   214   function sql_unbuffered_query($q)
   243   function sql_unbuffered_query($q)
   215   {
   244   {
   216     $this->enable_errorhandler();
   245     $this->enable_errorhandler();
       
   246     
   217     $this->num_queries++;
   247     $this->num_queries++;
   218     $this->query_backtrace .= '(UNBUFFERED) ' . $q."\n";
   248     $this->query_backtrace[] = '(UNBUFFERED) ' . $q;
   219     $this->latest_query = $q;
   249     $this->latest_query = $q;
   220     dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
   250     dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
   221     // First make sure we have a connection
   251     // First make sure we have a connection
   222     if ( !$this->_conn )
   252     if ( !$this->_conn )
   223     {
   253     {
   228     {
   258     {
   229       $this->report_query($q);
   259       $this->report_query($q);
   230       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>');
   260       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>');
   231     }
   261     }
   232     
   262     
       
   263     $time_start = microtime_float();
   233     $r = mysql_unbuffered_query($q, $this->_conn);
   264     $r = mysql_unbuffered_query($q, $this->_conn);
       
   265     $this->query_times[$q] = microtime_float() - $time_start;
   234     $this->latest_result = $r;
   266     $this->latest_result = $r;
   235     $this->disable_errorhandler();
   267     $this->disable_errorhandler();
   236     return $r;
   268     return $r;
   237   }
   269   }
   238   
   270   
   679 		else
   711 		else
   680 		{
   712 		{
   681 			return false;
   713 			return false;
   682 		}
   714 		}
   683 	}
   715 	}
       
   716   /**
       
   717    * Generates and outputs a report of all the SQL queries made during execution. Should only be called after everything's over with.
       
   718    */
       
   719   
       
   720   function sql_report()
       
   721   {
       
   722     global $db, $session, $paths, $template, $plugins; // Common objects
       
   723     if ( !$session->get_permissions('mod_misc') )
       
   724     {
       
   725       die_friendly('Access denied', '<p>You are not authorized to generate a SQL backtrace.</p>');
       
   726     }
       
   727     // Create copies of variables that may be changed after header is called
       
   728     $backtrace = $this->query_backtrace;
       
   729     $times = $this->query_times;
       
   730     $template->header();
       
   731     echo '<h3>SQL query log and timetable</h3>';
       
   732     echo '<div class="tblholder">
       
   733             <table border="0" cellspacing="1" cellpadding="4">';
       
   734     $i = 0;
       
   735     foreach ( $backtrace as $query )
       
   736     {
       
   737       $i++;
       
   738       $unbuffered = false;
       
   739       if ( substr($query, 0, 13) == '(UNBUFFERED) ' )
       
   740       {
       
   741         $query = substr($query, 13);
       
   742         $unbuffered = true;
       
   743       }
       
   744       if ( $i == 1 )
       
   745       {
       
   746         echo '<tr>
       
   747                 <th colspan="2">SQL backtrace for a normal page load of ' . htmlspecialchars($paths->cpage['urlname']) . '</th>
       
   748               </tr>';
       
   749       }
       
   750       else
       
   751       {
       
   752         echo '<tr>
       
   753                 <th class="subhead" colspan="2">&nbsp;</th>
       
   754               </tr>';
       
   755       }
       
   756       echo '<tr>
       
   757               <td class="row2">Query:</td>
       
   758               <td class="row1"><pre>' . htmlspecialchars($query) . '</pre></td>
       
   759             </tr>
       
   760             <tr>
       
   761               <td class="row2">Time:</td>
       
   762               <td class="row1">' . number_format($this->query_times[$query], 6) . ' seconds</td>
       
   763             </tr>
       
   764             <tr>
       
   765               <td class="row2">Unbuffered:</td>
       
   766               <td class="row1">' . ( $unbuffered ? 'Yes' : 'No' ) . '</td>
       
   767             </tr>';
       
   768       if ( isset($this->query_sources[$query]) )
       
   769       {
       
   770         echo '<tr>
       
   771                 <td class="row2">Called from:</td>
       
   772                 <td class="row1">' . $this->query_sources[$query] . '</td>
       
   773               </tr>';
       
   774       }
       
   775     }
       
   776     if ( function_exists('array_sum') )
       
   777     {
       
   778       $query_time_total = array_sum($this->query_times);
       
   779       echo '<tr>
       
   780               <th class="subhead" colspan="2">
       
   781                 Total time taken for SQL queries: ' . round( $query_time_total, 6 ) . ' seconds
       
   782               </th>
       
   783             </tr>';
       
   784     }
       
   785     echo '  </table>
       
   786           </div>';
       
   787     $template->footer();
       
   788   }
   684 }
   789 }
   685 
   790 
   686 ?>
   791 ?>