includes/dbal.php
changeset 1 fe660c52c48f
child 15 ad5986a53197
equal deleted inserted replaced
0:902822492a68 1:fe660c52c48f
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
       
     5  * Version 1.0 (Banshee)
       
     6  * Copyright (C) 2006-2007 Dan Fuhry
       
     7  *
       
     8  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
       
     9  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
       
    12  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
       
    13  */
       
    14  
       
    15 function db_error_handler($errno, $errstr, $errfile = false, $errline = false, $errcontext = Array() )
       
    16 {
       
    17   if ( !defined('ENANO_DEBUG') )
       
    18     return;
       
    19   $e = error_reporting(0);
       
    20   error_reporting($e);
       
    21   if ( $e < $errno )
       
    22     return;
       
    23   $errtype = 'Notice';
       
    24   switch ( $errno )
       
    25   {
       
    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;
       
    28   }
       
    29   $debug = debug_backtrace();
       
    30   $debug = $debug[2]['file'] . ', line ' . $debug[2]['line'];
       
    31   echo "<b>$errtype:</b> $errstr<br />Error source:<pre>$debug</pre>";
       
    32 }
       
    33  
       
    34 class mysql {
       
    35   var $num_queries, $query_backtrace, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values;
       
    36   var $row = array();
       
    37 	var $rowset = array();
       
    38   var $errhandler;
       
    39   
       
    40   function enable_errorhandler()
       
    41   {
       
    42     if ( function_exists('debug_backtrace') )
       
    43     {
       
    44       $this->errhandler = set_error_handler('db_error_handler');
       
    45     }
       
    46   }
       
    47   
       
    48   function disable_errorhandler()
       
    49   {
       
    50     if ( $this->errhandler )
       
    51     {
       
    52       set_error_handler($this->errhandler);
       
    53     }
       
    54     else
       
    55     {
       
    56       restore_error_handler();
       
    57     }
       
    58   }
       
    59   
       
    60   function sql_backtrace() {
       
    61     $qb = explode("\n", $this->query_backtrace);
       
    62     $bt = '';
       
    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   }
       
    69   
       
    70   function ensure_connection()
       
    71   {
       
    72     if(!$this->_conn)
       
    73     {
       
    74       $this->connect();
       
    75     }
       
    76   }
       
    77   
       
    78   function _die($t = '') {
       
    79     if(defined('ENANO_HEADERS_SENT')) {
       
    80       ob_clean();
       
    81     }
       
    82     header('HTTP/1.1 500 Internal Server Error');
       
    83     $bt = $this->sql_backtrace();
       
    84     $e = htmlspecialchars(mysql_error());
       
    85     if($e=='') $e='&lt;none&gt;';
       
    86     if(defined('ENANO_CONFIG_FETCHED')) die_semicritical('Database error', '<h3>An error occurred during a database query.</h3><p>'.$t.'<br />Error returned by MySQL: '.$e.'<br />SQL Backtrace:</p><pre>'.$bt.'</pre>');
       
    87     else                                   grinding_halt('Database error', '<h3>An error occurred during a database query.</h3><p>'.$t.'<br />Error returned by MySQL: '.$e.'<br />SQL Backtrace:</p><pre>'.$bt.'</pre>');
       
    88     exit;
       
    89   }
       
    90   
       
    91   function die_json()
       
    92   {
       
    93     $e = addslashes(htmlspecialchars(mysql_error()));
       
    94     $q = addslashes($this->latest_query);
       
    95     $t = "{'mode':'error','error':'An error occurred during database query.\nQuery was:\n  $q\n\nError returned by MySQL: $e'}";
       
    96     die($t);
       
    97   }
       
    98   
       
    99   function get_error($t = '') {
       
   100     header('HTTP/1.1 500 Internal Server Error');
       
   101     $bt = $this->sql_backtrace();
       
   102     $e = htmlspecialchars(mysql_error());
       
   103     if($e=='') $e='&lt;none&gt;';
       
   104     $text = '<h3>An error occurred during a database query.</h3><p>'.$t.'<br />Error returned by MySQL: '.$e.'<br />SQL Backtrace:</p><pre>'.$bt.'</pre>';
       
   105     return $text;
       
   106   }
       
   107   
       
   108   function connect() {
       
   109     $this->enable_errorhandler();
       
   110     dc_here('dbal: trying to connect....');
       
   111     @include(ENANO_ROOT.'/config.php');
       
   112     if(isset($crypto_key))
       
   113       unset($crypto_key); // Get this sucker out of memory fast
       
   114     if(!defined('ENANO_INSTALLED') && !defined('MIDGET_INSTALLED') && !defined('IN_ENANO_INSTALL') )
       
   115     {
       
   116       dc_here('dbal: oops, looks like Enano isn\'t set up. Constants ENANO_INSTALLED, MIDGET_INSTALLED, and IN_ENANO_INSTALL are all undefined.');
       
   117       header('Location: install.php'); 
       
   118       exit;
       
   119     }
       
   120     $this->_conn = @mysql_connect($dbhost, $dbuser, $dbpasswd);
       
   121     unset($dbuser);
       
   122     unset($dbpasswd); // Security
       
   123     if(!$this->_conn) { dc_here('dbal: uhoh!<br />'.mysql_error()); grinding_halt('Enano is having a problem', '<p>Error: couldn\'t connect to MySQL.<br />'.mysql_error().'</p>'); }
       
   124     $this->query_backtrace = '';
       
   125     $this->num_queries = 0;
       
   126     dc_here('dbal: we\'re in, selecting database...');
       
   127     $q = $this->sql_query('USE '.$dbname.';');
       
   128     if(!$q) $this->_die('The database could not be selected.');
       
   129     dc_here('dbal: connected to MySQL');
       
   130     $this->disable_errorhandler();
       
   131   }
       
   132   
       
   133   function sql_query($q) {
       
   134     $this->enable_errorhandler();
       
   135     $this->num_queries++;
       
   136     $this->query_backtrace .= $q."\n";
       
   137     $this->latest_query = $q;
       
   138     dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
       
   139     if(!$this->_conn) $this->_die('A database connection has not yet been established.');
       
   140     if(!$this->check_query($q))
       
   141     {
       
   142       $this->report_query($q);
       
   143       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>');
       
   144     }
       
   145     $r = mysql_query($q, $this->_conn);
       
   146     $this->latest_result = $r;
       
   147     $this->disable_errorhandler();
       
   148     return $r;
       
   149   }
       
   150   
       
   151   function sql_unbuffered_query($q) {
       
   152     $this->enable_errorhandler();
       
   153     $this->num_queries++;
       
   154     $this->query_backtrace .= '(UNBUFFERED) ' . $q."\n";
       
   155     $this->latest_query = $q;
       
   156     dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
       
   157     if(!$this->_conn) $this->_die('A database connection has not yet been established.');
       
   158     if(!$this->check_query($q))
       
   159     {
       
   160       $this->report_query($q);
       
   161       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>');
       
   162     }
       
   163     $r = mysql_unbuffered_query($q, $this->_conn);
       
   164     $this->latest_result = $r;
       
   165     $this->disable_errorhandler();
       
   166     return $r;
       
   167   }
       
   168   
       
   169   /**
       
   170    * Checks a SQL query for possible signs of injection attempts
       
   171    * @param string $q the query to check
       
   172    * @return bool true if query passed check, otherwise false
       
   173    */
       
   174   
       
   175   function check_query($q, $debug = false)
       
   176   {
       
   177     if($debug) echo "\$db-&gt;check_query(): checking query: ".htmlspecialchars($q).'<br />'."\n";
       
   178     $sz = strlen($q);
       
   179     $quotechar = false;
       
   180     $quotepos  = 0;
       
   181     $prev_is_quote = false;
       
   182     $just_started = false;
       
   183     for($i=0;$i<strlen($q);$i++,$c=substr($q, $i, 1))
       
   184     {
       
   185       $next = substr($q, $i+1, 1);
       
   186       $next2 = substr($q, $i+2, 1);
       
   187       $prev = substr($q, $i-1, 1);
       
   188       $prev2 = substr($q, $i-2, 1);
       
   189       if(isset($c) && in_array($c, Array('"', "'", '`')))
       
   190       {
       
   191         if($quotechar)
       
   192         {
       
   193           if(
       
   194               ( $quotechar == $c && $quotechar != $next && ( $quotechar != $prev || $just_entered ) && $prev != '\\') ||
       
   195               ( $prev2 == '\\' && $prev == $quotechar && $quotechar == $c )
       
   196             )
       
   197           {
       
   198             $quotechar = false;
       
   199             if($debug) echo('$db-&gt;check_query(): just finishing a quote section, quoted string: '.htmlspecialchars(substr($q, $quotepos, $i - $quotepos + 1)) . '<br />');
       
   200             $q = substr($q, 0, $quotepos) . 'SAFE_QUOTE' . substr($q, $i + 1, strlen($q));
       
   201             if($debug) echo('$db-&gt;check_query(): Filtered query: '.$q.'<br />');
       
   202             $i = $quotepos;
       
   203           }
       
   204         }
       
   205         else
       
   206         {
       
   207           $quotechar = $c;
       
   208           $quotepos  = $i;
       
   209           $just_entered = true;
       
   210         }
       
   211         if($debug) echo '$db-&gt;check_query(): found quote char as pos: '.$i.'<br />';
       
   212         continue;
       
   213       }
       
   214       $just_entered = false;
       
   215     }
       
   216     if(substr(trim($q), strlen(trim($q))-1, 1) == ';') $q = substr(trim($q), 0, strlen(trim($q))-1);
       
   217     for($i=0;$i<strlen($q);$i++,$c=substr($q, $i, 1))
       
   218     {
       
   219       if( ( $c == ';' && $i != $sz-1 ) || $c . substr($q, $i+1, 1) == '--') // Don't permit semicolons in mid-query, and never allow comments
       
   220       {
       
   221         // Injection attempt!
       
   222         if($debug)
       
   223         {
       
   224           $e = '';
       
   225           for($j=$i-5;$j<$i+5;$j++)
       
   226           {
       
   227             if($j == $i) $e .= '<span style="color: red; text-decoration: underline;">' . $c . '</span>';
       
   228             else $e .= $c;
       
   229           }
       
   230           echo 'Injection attempt caught at pos: '.$i.'<br />';
       
   231         }
       
   232         return false;
       
   233       }
       
   234     }
       
   235     return true;
       
   236   }
       
   237   
       
   238   /**
       
   239    * Set the internal result pointer to X
       
   240    * @param int $pos The number of the row
       
   241    * @param resource $result The MySQL result resource - if not given, the latest cached query is assumed
       
   242    * @return true on success, false on failure
       
   243    */
       
   244    
       
   245   function sql_data_seek($pos, $result = false)
       
   246   {
       
   247     $this->enable_errorhandler();
       
   248     if(!$result)
       
   249       $result = $this->latest_result;
       
   250     if(!$result)
       
   251     {
       
   252       $this->disable_errorhandler();
       
   253       return false;
       
   254     }
       
   255     if(mysql_data_seek($result, $pos))
       
   256     {
       
   257       $this->disable_errorhandler();
       
   258       return true;
       
   259     }
       
   260     else
       
   261     {
       
   262       $this->disable_errorhandler();
       
   263       return false;
       
   264     }
       
   265   }
       
   266   
       
   267   /**
       
   268    * Reports a bad query to the admin
       
   269    * @param string $query the naughty query
       
   270    * @access private
       
   271    */
       
   272    
       
   273   function report_query($query)
       
   274   {
       
   275     global $session;
       
   276     if(is_object($session) && defined('ENANO_MAINSTREAM'))
       
   277       $username = $session->username;
       
   278     else
       
   279       $username = 'Unavailable';
       
   280     $query = $this->escape($query);
       
   281     $q = $this->sql_query('INSERT INTO '.table_prefix.'logs(log_type,     action,         time_id,    date_string, page_text,      author,            edit_summary)
       
   282                                                      VALUES(\'security\', \'sql_inject\', '.time().', \'\',        \''.$query.'\', \''.$username.'\', \''.$_SERVER['REMOTE_ADDR'].'\');');
       
   283   }
       
   284   
       
   285   function fetchrow($r = false) {
       
   286     $this->enable_errorhandler();
       
   287     if(!$this->_conn) return false;
       
   288     if(!$r) $r = $this->latest_result;
       
   289     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
       
   290     $row = mysql_fetch_assoc($r);
       
   291     $this->disable_errorhandler();
       
   292     return $row;
       
   293   }
       
   294   
       
   295   function fetchrow_num($r = false) {
       
   296     $this->enable_errorhandler();
       
   297     if(!$r) $r = $this->latest_result;
       
   298     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
       
   299     $row = mysql_fetch_row($r);
       
   300     $this->disable_errorhandler();
       
   301     return $row;
       
   302   }
       
   303   
       
   304   function numrows($r = false) {
       
   305     $this->enable_errorhandler();
       
   306     if(!$r) $r = $this->latest_result;
       
   307     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
       
   308     $n = mysql_num_rows($r);
       
   309     $this->disable_errorhandler();
       
   310     return $n;
       
   311   }
       
   312   
       
   313   function escape($str)
       
   314   {
       
   315     $this->enable_errorhandler();
       
   316     $str = mysql_real_escape_string($str);
       
   317     $this->disable_errorhandler();
       
   318     return $str;
       
   319   }
       
   320   
       
   321   function free_result($result = false)
       
   322   {
       
   323     $this->enable_errorhandler();
       
   324     if(!$result)
       
   325       $result = $this->latest_result;
       
   326     if(!$result)
       
   327     {
       
   328       $this->disable_errorhandler();
       
   329       return null;
       
   330     }
       
   331     mysql_free_result($result);
       
   332     $this->disable_errorhandler();
       
   333     return null;
       
   334   }
       
   335   
       
   336   function close() {
       
   337     dc_here('dbal: closing MySQL connection');
       
   338     mysql_close($this->_conn);
       
   339     unset($this->_conn);
       
   340   }
       
   341   
       
   342   // phpBB DBAL compatibility
       
   343   function sql_fetchrow($r = false)
       
   344   {
       
   345     return $this->fetchrow($r);
       
   346   }
       
   347   function sql_freeresult($r = false)
       
   348   {
       
   349     if(!$this->_conn) return false;
       
   350     if(!$r) $r = $this->latest_result;
       
   351     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
       
   352     mysql_free_result($r);
       
   353   }
       
   354   function sql_numrows($r = false)
       
   355   {
       
   356     if(!$this->_conn) return false;
       
   357     if(!$r) $r = $this->latest_result;
       
   358     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
       
   359     return mysql_num_rows($r);
       
   360   }
       
   361   function sql_affectedrows($r = false, $f, $n)
       
   362   {
       
   363     if(!$this->_conn) return false;
       
   364     if(!$r) $r = $this->latest_result;
       
   365     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
       
   366     return mysql_affected_rows();
       
   367   }
       
   368   
       
   369   function sql_type_cast(&$value)
       
   370 	{
       
   371 		if ( is_float($value) )
       
   372 		{
       
   373 			return doubleval($value);
       
   374 		}
       
   375 		if ( is_integer($value) || is_bool($value) )
       
   376 		{
       
   377 			return intval($value);
       
   378 		}
       
   379 		if ( is_string($value) || empty($value) )
       
   380 		{
       
   381 			return '\'' . $this->sql_escape_string($value) . '\'';
       
   382 		}
       
   383 		// uncastable var : let's do a basic protection on it to prevent sql injection attempt
       
   384 		return '\'' . $this->sql_escape_string(htmlspecialchars($value)) . '\'';
       
   385 	}
       
   386 
       
   387 	function sql_statement(&$fields, $fields_inc='')
       
   388 	{
       
   389 		// init result
       
   390 		$this->sql_fields = $this->sql_values = $this->sql_update = '';
       
   391 		if ( empty($fields) && empty($fields_inc) )
       
   392 		{
       
   393 			return;
       
   394 		}
       
   395 
       
   396 		// process
       
   397 		if ( !empty($fields) )
       
   398 		{
       
   399 			$first = true;
       
   400 			foreach ( $fields as $field => $value )
       
   401 			{
       
   402 				// field must contain a field name
       
   403 				if ( !empty($field) && is_string($field) )
       
   404 				{
       
   405 					$value = $this->sql_type_cast($value);
       
   406 					$this->sql_fields .= ( $first ? '' : ', ' ) . $field;
       
   407 					$this->sql_values .= ( $first ? '' : ', ' ) . $value;
       
   408 					$this->sql_update .= ( $first ? '' : ', ' ) . $field . ' = ' . $value;
       
   409 					$first = false;
       
   410 				}
       
   411 			}
       
   412 		}
       
   413 		if ( !empty($fields_inc) )
       
   414 		{
       
   415 			foreach ( $fields_inc as $field => $indent )
       
   416 			{
       
   417 				if ( $indent != 0 )
       
   418 				{
       
   419 					$this->sql_update .= (empty($this->sql_update) ? '' : ', ') . $field . ' = ' . $field . ($indent < 0 ? ' - ' : ' + ') . abs($indent);
       
   420 				}
       
   421 			}
       
   422 		}
       
   423 	}
       
   424 
       
   425 	function sql_stack_reset($id='')
       
   426 	{
       
   427 		if ( empty($id) )
       
   428 		{
       
   429 			$this->sql_stack_fields = array();
       
   430 			$this->sql_stack_values = array();
       
   431 		}
       
   432 		else
       
   433 		{
       
   434 			$this->sql_stack_fields[$id] = array();
       
   435 			$this->sql_stack_values[$id] = array();
       
   436 		}
       
   437 	}
       
   438 
       
   439 	function sql_stack_statement(&$fields, $id='')
       
   440 	{
       
   441 		$this->sql_statement($fields);
       
   442 		if ( empty($id) )
       
   443 		{
       
   444 			$this->sql_stack_fields = $this->sql_fields;
       
   445 			$this->sql_stack_values[] = '(' . $this->sql_values . ')';
       
   446 		}
       
   447 		else
       
   448 		{
       
   449 			$this->sql_stack_fields[$id] = $this->sql_fields;
       
   450 			$this->sql_stack_values[$id][] = '(' . $this->sql_values . ')';
       
   451 		}
       
   452 	}
       
   453 
       
   454 	function sql_stack_insert($table, $transaction=false, $line='', $file='', $break_on_error=true, $id='')
       
   455 	{
       
   456 		if ( (empty($id) && empty($this->sql_stack_values)) || (!empty($id) && empty($this->sql_stack_values[$id])) )
       
   457 		{
       
   458 			return false;
       
   459 		}
       
   460 		switch( SQL_LAYER )
       
   461 		{
       
   462 			case 'mysql':
       
   463 			case 'mysql4':
       
   464 				if ( empty($id) )
       
   465 				{
       
   466 					$sql = 'INSERT INTO ' . $table . '
       
   467 								(' . $this->sql_stack_fields . ') VALUES ' . implode(",\n", $this->sql_stack_values);
       
   468 				}
       
   469 				else
       
   470 				{
       
   471 					$sql = 'INSERT INTO ' . $table . '
       
   472 								(' . $this->sql_stack_fields[$id] . ') VALUES ' . implode(",\n", $this->sql_stack_values[$id]);
       
   473 				}
       
   474 				$this->sql_stack_reset($id);
       
   475 				return $this->sql_query($sql, $transaction, $line, $file, $break_on_error);
       
   476 				break;
       
   477 			default:
       
   478 				$count_sql_stack_values = empty($id) ? count($this->sql_stack_values) : count($this->sql_stack_values[$id]);
       
   479 				$result = !empty($count_sql_stack_values);
       
   480 				for ( $i = 0; $i < $count_sql_stack_values; $i++ )
       
   481 				{
       
   482 					if ( empty($id) )
       
   483 					{
       
   484 						$sql = 'INSERT INTO ' . $table . '
       
   485 									(' . $this->sql_stack_fields . ') VALUES ' . $this->sql_stack_values[$i];
       
   486 					}
       
   487 					else
       
   488 					{
       
   489 						$sql = 'INSERT INTO ' . $table . '
       
   490 									(' . $this->sql_stack_fields[$id] . ') VALUES ' . $this->sql_stack_values[$id][$i];
       
   491 					}
       
   492 					$result &= $this->sql_query($sql, $transaction, $line, $file, $break_on_error);
       
   493 				}
       
   494 				$this->sql_stack_reset($id);
       
   495 				return $result;
       
   496 				break;
       
   497 		}
       
   498 	}
       
   499 
       
   500 	function sql_subquery($field, $sql, $line='', $file='', $break_on_error=true, $type=TYPE_INT)
       
   501 	{
       
   502 		// sub-queries doable
       
   503 		$this->sql_get_version();
       
   504 		if ( !in_array(SQL_LAYER, array('mysql', 'mysql4')) || (($this->sql_version[0] + ($this->sql_version[1] / 100)) >= 4.01) )
       
   505 		{
       
   506 			return $sql;
       
   507 		}
       
   508 
       
   509 		// no sub-queries
       
   510 		$ids = array();
       
   511 		$result = $this->sql_query(trim($sql), false, $line, $file, $break_on_error);
       
   512 		while ( $row = $this->sql_fetchrow($result) )
       
   513 		{
       
   514 			$ids[] = $type == TYPE_INT ? intval($row[$field]) : '\'' . $this->sql_escape_string($row[$field]) . '\'';
       
   515 		}
       
   516 		$this->sql_freeresult($result);
       
   517 		return empty($ids) ? 'NULL' : implode(', ', $ids);
       
   518 	}
       
   519 
       
   520 	function sql_col_id($expr, $alias)
       
   521 	{
       
   522 		$this->sql_get_version();
       
   523 		return in_array(SQL_LAYER, array('mysql', 'mysql4')) && (($this->sql_version[0] + ($this->sql_version[1] / 100)) <= 4.01) ? $alias : $expr;
       
   524 	}
       
   525 
       
   526 	function sql_get_version()
       
   527 	{
       
   528 		if ( empty($this->sql_version) )
       
   529 		{
       
   530 			$this->sql_version = array(0, 0, 0);
       
   531 			switch ( SQL_LAYER )
       
   532 			{
       
   533 				case 'mysql':
       
   534 				case 'mysql4':
       
   535 					if ( function_exists('mysql_get_server_info') )
       
   536 					{
       
   537 						$lo_version = explode('-', mysql_get_server_info());
       
   538 						$this->sql_version = explode('.', $lo_version[0]);
       
   539 						$this->sql_version = array(intval($this->sql_version[0]), intval($this->sql_version[1]), intval($this->sql_version[2]), $lo_version[1]);
       
   540 					}
       
   541 					break;
       
   542 
       
   543 				case 'postgresql':
       
   544 				case 'mssql':
       
   545 				case 'mssql-odbc':
       
   546 				default:
       
   547 					break;
       
   548 			}
       
   549 		}
       
   550 		return $this->sql_version;
       
   551 	}
       
   552 
       
   553 	function sql_error()
       
   554 	{
       
   555 		if ( $this->_conn )
       
   556 		{
       
   557 			return mysql_error();
       
   558 		}
       
   559 		else
       
   560 		{
       
   561 			return array();
       
   562 		}
       
   563 	}
       
   564   function sql_escape_string($t) 
       
   565   {
       
   566     return mysql_real_escape_string($t);
       
   567   }
       
   568   function sql_close()
       
   569   {
       
   570     $this->close();
       
   571   }
       
   572   function sql_fetchrowset($query_id = 0)
       
   573 	{
       
   574 		if( !$query_id )
       
   575 		{
       
   576 			$query_id = $this->query_result;
       
   577 		}
       
   578 
       
   579 		if( $query_id )
       
   580 		{
       
   581 			unset($this->rowset[$query_id]);
       
   582 			unset($this->row[$query_id]);
       
   583 
       
   584 			while($this->rowset[$query_id] = mysql_fetch_array($query_id, MYSQL_ASSOC))
       
   585 			{
       
   586 				$result[] = $this->rowset[$query_id];
       
   587 			}
       
   588 
       
   589 			return $result;
       
   590 		}
       
   591 		else
       
   592 		{
       
   593 			return false;
       
   594 		}
       
   595 	}
       
   596 }
       
   597 
       
   598 ?>