5 # A Simple SQL Database Abstraction Object 7 # Copyright 1999-2002 Axis Data 8 # This code is free software that can be used or redistributed under the 9 # terms of Version 2 of the GNU General Public License, as published by the 10 # Free Software Foundation (http://www.fsf.org). 12 # Author: Edward Almasy (almasy@axisdata.com) 14 # Part of the AxisPHP library v1.2.5 15 # For more information see http://www.axisdata.com/AxisPHP/ 25 # ---- PUBLIC INTERFACE -------------------------------------------------- 44 $UserName = NULL, $Password = NULL, $DatabaseName = NULL, $HostName = NULL)
46 # save DB access parameter values 47 $this->
DBUserName = $UserName ? $UserName : self::$GlobalDBUserName;
48 $this->DBPassword = $Password ? $Password : self::$GlobalDBPassword;
50 (isset(self::$GlobalDBHostName) ? self::$GlobalDBHostName
52 $this->
DBName = $DatabaseName ? $DatabaseName : self::$GlobalDBName;
54 # set memory threshold for cache clearing 55 if (!isset(self::$CacheMemoryThreshold))
57 self::$CacheMemoryThreshold = self::GetPhpMemoryLimit() / 4;
60 # if we don't already have a connection or DB access parameters were supplied 62 if (!array_key_exists($HandleIndex, self::$ConnectionHandles)
63 || $UserName || $Password || $DatabaseName || $HostName)
65 # open connection to DB server and select database 66 $this->Handle = self::ConnectAndSelectDB($this->
DBHostName,
68 self::$ConnectionHandles[$HandleIndex] = $this->Handle;
72 # set local connection handle 73 $this->Handle = self::$ConnectionHandles[$HandleIndex];
83 return array(
"DBUserName",
"DBPassword",
"DBHostName",
"DBName");
92 # if we don't already have a database server connection 94 if (!array_key_exists($HandleIndex, self::$ConnectionHandles))
96 # open connection to DB server and select database 99 $this->Handle = self::ConnectAndSelectDB($this->
DBHostName,
102 catch (Exception $Exception)
104 if (isset(self::$GlobalDBUserName)
105 && isset(self::$GlobalDBPassword)
106 && isset(self::$GlobalDBName))
109 $this->DBPassword = self::$GlobalDBPassword;
110 $this->
DBName = self::$GlobalDBName;
111 $this->
DBHostName = isset(self::$GlobalDBHostName)
112 ? self::$GlobalDBHostName :
"localhost";
113 $this->Handle = self::ConnectAndSelectDB($this->
DBHostName,
121 self::$ConnectionHandles[$HandleIndex] = $this->Handle;
125 # set local connection handle 126 $this->Handle = self::$ConnectionHandles[$HandleIndex];
139 $UserName, $Password, $HostName =
"localhost")
141 # save default DB access parameters 142 self::$GlobalDBUserName = $UserName;
143 self::$GlobalDBPassword = $Password;
144 self::$GlobalDBHostName = $HostName;
146 # clear any existing DB connection handles 147 self::$ConnectionHandles = array();
156 # save new default DB name 157 self::$GlobalDBName = $DatabaseName;
159 # clear any existing DB connection handles 160 self::$ConnectionHandles = array();
169 # choose config variable to use based on server version number 171 ?
"storage_engine" :
"default_storage_engine";
173 # set storage engine in database 174 $this->
Query(
"SET ".$ConfigVar.
" = ".$Engine);
185 # retrieve version string 186 $Version = $this->
Query(
"SELECT VERSION() AS ServerVer",
"ServerVer");
190 # strip off any build/config suffix 191 $Pieces = explode(
"-", $Version);
192 $Version = array_shift($Pieces);
195 # return version number to caller 209 return mysqli_get_client_info();
219 return mysqli_get_host_info($this->Handle);
259 public static function Caching($NewSetting = NULL)
261 # if cache setting has changed 262 if (($NewSetting !== NULL) && ($NewSetting != self::$CachingFlag))
265 self::$CachingFlag = $NewSetting;
267 # clear any existing cached results 268 self::$QueryResultCache = array();
271 # return current setting to caller 272 return self::$CachingFlag;
287 if ($NewSetting !== NULL)
289 self::$AdvancedCachingFlag = $NewSetting;
291 return self::$AdvancedCachingFlag;
315 if ($NormalizeWhitespace && ($ErrorsToIgnore !== NULL))
317 $RevisedErrorsToIgnore = array();
318 foreach ($ErrorsToIgnore as $SqlPattern => $ErrMsgPattern)
320 $SqlPattern = preg_replace(
"/\\s+/",
"\\s+", $SqlPattern);
321 $RevisedErrorsToIgnore[$SqlPattern] = $ErrMsgPattern;
323 $ErrorsToIgnore = $RevisedErrorsToIgnore;
325 $this->ErrorsToIgnore = $ErrorsToIgnore;
335 return $this->ErrorIgnored;
351 public function Query($QueryString, $FieldName =
"")
353 # clear flag that indicates whether query error was ignored 354 $this->ErrorIgnored = FALSE;
356 # if caching is enabled 357 if (self::$CachingFlag)
359 # if SQL statement is read-only 360 if ($this->IsReadOnlyStatement($QueryString))
362 # if we have statement in cache 363 if (isset(self::$QueryResultCache[$QueryString][
"NumRows"]))
365 if (self::$QueryDebugOutputFlag)
366 { print(
"DB-C: $QueryString<br>\n"); }
368 # make sure query result looks okay 369 $this->QueryHandle = TRUE;
371 # increment cache hit counter 372 self::$CachedQueryCounter++;
374 # make local copy of results 375 $this->QueryResults = self::$QueryResultCache[$QueryString];
376 $this->NumRows = self::$QueryResultCache[$QueryString][
"NumRows"];
378 # set flag to indicate that results should be retrieved from cache 379 $this->GetResultsFromCache = TRUE;
383 # execute SQL statement 384 $this->QueryHandle = $this->RunQuery($QueryString);
385 if (!$this->QueryHandle instanceof mysqli_result) {
return FALSE; }
387 # save number of rows in result 388 $this->NumRows = mysqli_num_rows($this->QueryHandle);
390 # if too many rows to cache 391 if ($this->NumRows >= self::$CacheRowsThreshold)
393 # set flag to indicate that query results should not 394 # be retrieved from cache 395 $this->GetResultsFromCache = FALSE;
399 # if we are low on memory 400 if (self::GetFreeMemory() < self::$CacheMemoryThreshold)
402 # clear out all but last few rows from cache 403 self::$QueryResultCache = array_slice(
404 self::$QueryResultCache,
405 (0 - self::$CacheRowsToLeave));
408 # if advanced caching is enabled 409 if (self::$AdvancedCachingFlag)
411 # save tables accessed by query 412 self::$QueryResultCache[$QueryString][
"TablesAccessed"] =
413 $this->TablesAccessed($QueryString);
417 if ($this->NumRows > 0)
420 for ($Row = 0; $Row < $this->NumRows; $Row++)
422 $this->QueryResults[$Row] =
423 mysqli_fetch_assoc($this->QueryHandle);
426 # cache query results 427 self::$QueryResultCache[$QueryString] = $this->QueryResults;
431 # clear local query results 432 unset($this->QueryResults);
435 # cache number of rows 436 self::$QueryResultCache[$QueryString][
"NumRows"] = $this->NumRows;
438 # set flag to indicate that query results should be 439 # retrieved from cache 440 $this->GetResultsFromCache = TRUE;
446 # if advanced caching is enabled 447 if (self::$AdvancedCachingFlag)
449 # if table modified by statement is known 450 $TableModified = $this->TableModified($QueryString);
453 # for each cached query 454 foreach (self::$QueryResultCache
455 as $CachedQueryString => $CachedQueryResult)
457 # if we know what tables were accessed 458 if ($CachedQueryResult[
"TablesAccessed"])
460 # if tables accessed include the one we may modify 461 if (in_array($TableModified,
462 $CachedQueryResult[
"TablesAccessed"]))
464 # clear cached query results 465 unset(self::$QueryResultCache[$CachedQueryString]);
470 # clear cached query results 471 unset(self::$QueryResultCache[$CachedQueryString]);
477 # clear entire query result cache 478 self::$QueryResultCache = array();
483 # clear entire query result cache 484 self::$QueryResultCache = array();
487 # execute SQL statement 488 $this->QueryHandle = $this->RunQuery($QueryString);
489 if ($this->QueryHandle === FALSE) {
return FALSE; }
491 # set flag to indicate that query results should not be 492 # retrieved from cache 493 $this->GetResultsFromCache = FALSE;
497 $this->RowCounter = 0;
499 # increment query counter 500 self::$QueryCounter++;
504 # execute SQL statement 505 $this->QueryHandle = $this->RunQuery($QueryString);
506 if ($this->QueryHandle === FALSE) {
return FALSE; }
509 if (($FieldName !=
"") && ($this->QueryHandle !== FALSE))
515 return $this->QueryHandle;
534 $FHandle = fopen($FileName,
"r");
536 # if file open succeeded 537 if ($FHandle !== FALSE)
539 # while lines left in file 542 while (!feof($FHandle))
544 # read in line from file 545 $Line = fgets($FHandle, 32767);
547 # trim whitespace from line 550 # if line is not empty and not a comment 551 if (!preg_match(
"/^#/", $Line)
552 && !preg_match(
"/^--/", $Line)
555 # add line to current query 558 # if line completes a query 559 if (preg_match(
"/;$/", $Line))
563 $Result = $this->
Query($Query);
566 # if query resulted in an error that is not ignorable 567 if ($Result === FALSE)
569 # stop processing queries and set error code 581 # return number of executed queries to caller 592 return $this->ErrMsg;
613 if ($NewValue !== NULL) { self::$DisplayErrors = $NewValue; }
614 return self::$DisplayErrors;
623 # if caching is enabled and query was cached 624 if (self::$CachingFlag && $this->GetResultsFromCache)
626 # return cached number of rows to caller 627 return $this->NumRows;
631 # call to this method after an unsuccessful query 632 if (!$this->QueryHandle instanceof mysqli_result)
637 # retrieve number of rows and return to caller 638 return mysqli_num_rows($this->QueryHandle);
649 # call to this method after an unsuccessful query 650 if ($this->QueryHandle === FALSE)
655 # retrieve number of rows and return to caller 656 return mysqli_affected_rows($this->Handle);
666 # if caching is enabled and query was cached 667 if (self::$CachingFlag && $this->GetResultsFromCache)
669 # if rows left to return 670 if ($this->RowCounter < $this->NumRows)
672 # retrieve row from cache 673 $Result = $this->QueryResults[$this->RowCounter];
675 # increment row counter 686 # call to this method after successful query 687 if ($this->QueryHandle instanceof mysqli_result)
689 $Result = mysqli_fetch_assoc($this->QueryHandle);
690 if ($Result === NULL) { $Result = FALSE; }
693 # call to this method after unsuccessful query 700 # return row to caller 712 # assume no rows will be returned 715 # for each available row 717 while ((($RowsFetched < $NumberOfRows) || ($NumberOfRows == NULL))
725 # return array of rows to caller 750 if ($IndexFieldName != NULL)
752 $Array[$Record[$IndexFieldName]] = $Record[$FieldName];
756 $Array[] = $Record[$FieldName];
773 return isset($Record[$FieldName]) ? $Record[$FieldName] : NULL;
784 return (
int)$this->
Query(
785 "SELECT LAST_INSERT_ID() AS InsertId",
804 $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
806 # expand condition if supplied 807 if ($Condition != NULL) { $Condition =
" WHERE ".$Condition; }
809 # read cached record from database if not already loaded 810 if (!isset($CachedRecord))
812 $this->
Query(
"SELECT * FROM `".$TableName.
"` ".$Condition);
816 # if new value supplied 819 # update value in database 820 $this->
Query(
"UPDATE `".$TableName.
"` SET `".$FieldName.
"` = " 821 .(($NewValue === NULL) ?
"NULL" :
"'" 822 .mysqli_real_escape_string($this->Handle, $NewValue).
"'")
825 # update value in cached record 826 $CachedRecord[$FieldName] = $NewValue;
829 # return value from cached record to caller 830 return isset($CachedRecord[$FieldName])
831 ? $CachedRecord[$FieldName] : NULL;
851 $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
855 $Condition, $CachedRecord);
875 $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
879 $Condition, $CachedRecord);
893 public function CopyValues($TableName, $IdColumn, $SrcId, $DstId,
894 $ColumnsToExclude = array())
896 # retrieve names of all columns in table 899 # remove columns to be excluded from copy 900 $ColumnsToExclude[] = $IdColumn;
901 $ColumnsToCopy = array_diff($AllColumns, $ColumnsToExclude);
903 # normalize destination IDs 904 $DstIds = is_array($DstId) ? $DstId : array($DstId);
905 $DstIds = array_diff($DstIds, array($SrcId));
907 # if there are columns to copy and we have destinations 908 if (count($ColumnsToCopy) && count($DstIds))
910 # construct and execute query to perform copy 911 $Query =
"UPDATE `".$TableName.
"` AS Target" 912 .
" LEFT JOIN `".$TableName.
"` AS Source" 913 .
" ON Source.`".$IdColumn.
"` = '".addslashes($SrcId).
"'";
914 $QuerySets = array();
915 foreach ($ColumnsToCopy as $ColumnName)
917 $QuerySets[] =
"Target.`".$ColumnName.
"` = Source.`".$ColumnName.
"`";
919 $Query .=
" SET ".implode(
", ", $QuerySets);
920 $QueryConditions = array();
921 foreach ($DstIds as $Id)
923 $QueryConditions[] =
"Target.`".$IdColumn.
"` = '".addslashes($DstId).
"'";
925 $Query .=
" WHERE ".implode(
" OR ", $QueryConditions);
926 $this->
Query($Query);
944 $KeyField = NULL, $AvgDataLength = 20)
946 # pick some ballpark values 947 $ChunkSizeAssumedSafe = 100;
948 $QueryLengthAssumedSafe = 10486576; # (1 MB)
950 # exit without doing anything
if there are no values
951 $ValueCount = count($Values);
952 if ($ValueCount == 0)
957 # determine size of array chunk per INSERT statement 958 $NonValueCharCount = 100;
959 if ($ValueCount > $ChunkSizeAssumedSafe)
962 $ValueSegmentLen = $AvgDataLength + 6;
963 if ($KeyField !== NULL)
965 $ValueSegmentLen = $ValueSegmentLen * 2;
967 $ValueChunkSize = $MaxQueryLen / $ValueSegmentLen;
971 $ValueChunkSize = $ChunkSizeAssumedSafe;
974 # for each chunk of values 975 foreach (array_chunk($Values, $ValueChunkSize, TRUE) as $ValueChunk)
977 # begin building query 978 $Query =
"INSERT INTO `".$Table.
"` (`".$ValueField.
"`";
980 # if key field was specified 981 if ($KeyField !== NULL)
983 # add key field to query 984 $Query .=
", `".$KeyField.
"`";
986 # assemble value segment with keys 987 $ValueSegFunc =
function($Carry, $Key) use ($ValueChunk)
989 $Carry .=
"('".addslashes($ValueChunk[$Key]).
"','" 990 .addslashes($Key).
"'),";
993 $ValueSegment = array_reduce(array_keys($ValueChunk), $ValueSegFunc);
997 # assemble value segment 998 $ValueSegFunc =
function($Carry, $Value)
1000 $Carry .=
"('".addslashes($Value).
"'),";
1003 $ValueSegment = array_reduce($ValueChunk, $ValueSegFunc);
1006 # trim extraneous comma off of value segment 1007 $ValueSegment = substr($ValueSegment, 0, -1);
1009 # add value segment to query 1010 $Query .=
") VALUES ".$ValueSegment;
1012 # double check to make sure query isn't too long 1013 $QueryLen = strlen($Query);
1014 if ($QueryLen > $QueryLengthAssumedSafe)
1016 if (!isset($MaxQueryLen))
1020 if ($QueryLen > $MaxQueryLen)
1022 throw new Exception(
"Maximum query length (" 1023 .$MaxQueryLen.
") exceeded (".$QueryLen.
").");
1028 $this->
Query($Query);
1045 return mysqli_real_escape_string($this->Handle, $String);
1056 $this->
Query(
"-- ".$String);
1066 $this->
Query(
"SHOW TABLES LIKE '".addslashes($TableName).
"'");
1078 $this->
Query(
"DESC ".$TableName);
1079 while ($CurrentFieldName = $this->
FetchField(
"Field"))
1081 if ($CurrentFieldName == $FieldName) {
return TRUE; }
1094 $this->
Query(
"DESC ".$TableName);
1096 return $AllTypes[$FieldName];
1106 $this->
Query(
"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS" 1107 .
" WHERE TABLE_SCHEMA = '".addslashes($this->
DBName)
1108 .
"' AND TABLE_NAME = '".addslashes($TableName).
"'");
1118 return $this->
Query(
"SHOW VARIABLES LIKE 'max_allowed_packet'",
1129 self::$QueryDebugOutputFlag = $NewSetting;
1139 return self::$QueryCounter;
1150 return self::$CachedQueryCounter;
1160 if (self::$QueryCounter)
1162 return (self::$CachedQueryCounter / self::$QueryCounter) * 100;
1172 # ---- PRIVATE INTERFACE ------------------------------------------------- 1180 private $QueryHandle;
1181 private $QueryResults;
1182 private $RowCounter;
1184 private $GetResultsFromCache;
1185 private $ErrorIgnored = FALSE;
1186 private $ErrorsToIgnore = NULL;
1187 private $ErrMsg = NULL;
1188 private $ErrNo = NULL;
1190 private static $DisplayErrors = FALSE;
1192 private static $GlobalDBUserName;
1193 private static $GlobalDBPassword;
1194 private static $GlobalDBHostName;
1195 private static $GlobalDBName;
1198 private static $QueryDebugOutputFlag = FALSE;
1199 # flag for whether caching is turned on 1200 private static $CachingFlag = TRUE;
1201 # query result advanced caching flag 1202 private static $AdvancedCachingFlag = FALSE;
1203 # global cache for query results 1204 private static $QueryResultCache = array();
1206 private static $QueryCounter = 0;
1207 private static $CachedQueryCounter = 0;
1208 # database connection link handles 1209 private static $ConnectionHandles = array();
1210 # do not cache queries that return more than this number of rows 1211 private static $CacheRowsThreshold = 250;
1212 # prune the query cache if there is less than this amount of memory free 1213 private static $CacheMemoryThreshold;
1214 # number of rows to leave in cache when pruning 1215 private static $CacheRowsToLeave = 10;
1216 # number of retry attempts to make to connect to database 1217 private static $ConnectRetryAttempts = 3;
1218 # number of seconds to wait between connection retry attempts 1219 private static $ConnectRetryInterval = 5;
1221 # server connection error codes 1223 # through socket '%s
' (%d) 1224 const CR_CONN_HOST_ERROR = 2003; # Can't connect to MySQL server on
'%s' (%d)
1228 # connection error codes that may be recoverable 1229 private static $RecoverableConnectionErrors = array(
1230 self::CR_CONNECTION_ERROR,
1243 private static function ConnectAndSelectDB(
1246 $ConnectAttemptsLeft = self::$ConnectRetryAttempts + 1;
1249 # if this is not our first connection attempt 1252 # wait for the retry interval 1253 sleep(self::$ConnectRetryInterval);
1256 # attempt to connect to server 1258 $ConnectAttemptsLeft--;
1260 # repeat if we do not have a connection and there are retry attempts 1261 # left and the connection error code indicates a retry may succeed 1264 while (!$Handle && $ConnectAttemptsLeft
1265 && in_array(mysqli_connect_errno(),
1266 self::$RecoverableConnectionErrors));
1269 # throw exception if connection attempts failed 1272 throw new Exception(
"Could not connect to database: " 1273 .mysqli_connect_error().
" (errno: ".mysqli_connect_errno().
")");
1277 $Result = mysqli_select_db($Handle,
$DBName);
1278 if ($Result !== TRUE)
1280 throw new Exception(
"Could not select database: " 1281 .mysqli_error($Handle).
" (errno: ".mysqli_errno($Handle).
")");
1284 # return new connection to caller 1293 private function IsReadOnlyStatement($QueryString)
1295 return preg_match(
"/^[ ]*SELECT /i", $QueryString) ? TRUE : FALSE;
1304 private function TableModified($QueryString)
1306 # assume we're not going to be able to determine table 1309 # split query into pieces 1310 $QueryString = trim($QueryString);
1311 $Words = preg_split(
"/\s+/", $QueryString);
1313 # if INSERT statement 1315 if (strtoupper($Words[0]) ==
"INSERT")
1317 # skip over modifying keywords 1318 while ((strtoupper($Words[$WordIndex]) ==
"LOW_PRIORITY")
1319 || (strtoupper($Words[$WordIndex]) ==
"DELAYED")
1320 || (strtoupper($Words[$WordIndex]) ==
"IGNORE")
1321 || (strtoupper($Words[$WordIndex]) ==
"INTO"))
1326 # next word is table name 1327 $TableName = $Words[$WordIndex];
1329 # else if UPDATE statement 1330 elseif (strtoupper($Words[0]) ==
"UPDATE")
1332 # skip over modifying keywords 1333 while ((strtoupper($Words[$WordIndex]) ==
"LOW_PRIORITY")
1334 || (strtoupper($Words[$WordIndex]) ==
"IGNORE"))
1339 # if word following next word is SET 1340 if (strtoupper($Words[$WordIndex + 1]) ==
"SET")
1342 # next word is table name 1343 $TableName = $Words[$WordIndex];
1346 # else if DELETE statement 1347 elseif (strtoupper($Words[0]) ==
"DELETE")
1349 # skip over modifying keywords 1350 while ((strtoupper($Words[$WordIndex]) ==
"LOW_PRIORITY")
1351 || (strtoupper($Words[$WordIndex]) ==
"IGNORE")
1352 || (strtoupper($Words[$WordIndex]) ==
"QUICK"))
1357 # if next term is FROM 1358 if (strtoupper($Words[$WordIndex]) ==
"FROM")
1360 # next word is table name 1362 $TableName = $Words[$WordIndex];
1366 # discard table name if it looks at all suspicious 1369 if (!preg_match(
"/[a-zA-Z0-9]+/", $TableName))
1375 # return table name (or lack thereof) to caller 1385 private function TablesAccessed($QueryString)
1387 # assume we're not going to be able to determine tables 1388 $TableNames = FALSE;
1390 # split query into pieces 1391 $QueryString = trim($QueryString);
1392 $Words = preg_split(
"/\s+/", $QueryString);
1393 $UQueryString = strtoupper($QueryString);
1394 $UWords = preg_split(
"/\s+/", $UQueryString);
1396 # if SELECT statement 1397 if ($UWords[0] ==
"SELECT")
1399 # keep going until we hit FROM or last word 1401 while (($UWords[$WordIndex] !=
"FROM")
1402 && strlen($UWords[$WordIndex]))
1408 if ($UWords[$WordIndex] ==
"FROM")
1410 # for each word after FROM 1412 while (strlen($UWords[$WordIndex]))
1414 # if current word ends with comma 1415 if (preg_match(
"/,$/", $Words[$WordIndex]))
1417 # strip off comma and add word to table name list 1418 $TableNames[] = substr($Words[$WordIndex], 0, -1);
1422 # add word to table name list 1423 $TableNames[] = $Words[$WordIndex];
1425 # if next word is not comma 1427 if ($Words[$WordIndex] !=
",")
1429 # if word begins with comma 1430 if (preg_match(
"/^,/", $Words[$WordIndex]))
1432 # strip off comma (NOTE: modifies $Words array!) 1433 $Words[$WordIndex] = substr($Words[$WordIndex], 1);
1435 # decrement index so we start with this word next pass 1440 # stop scanning words (non-basic JOINs not yet handled) 1452 # discard table names if they look at all suspicious 1455 foreach ($TableNames as $Name)
1457 if (!preg_match(
"/^[a-zA-Z0-9]+$/", $Name))
1459 $TableNames = FALSE;
1465 # return table name (or lack thereof) to caller 1475 private function RunQuery($QueryString)
1477 # log query start time if debugging output is enabled 1478 if (self::$QueryDebugOutputFlag) { $QueryStartTime = microtime(TRUE); }
1480 # run query against database 1481 $this->QueryHandle = mysqli_query($this->Handle, $QueryString) ;
1483 # print query and execution time if debugging output is enabled 1484 if (self::$QueryDebugOutputFlag)
1486 print
"DB: ".$QueryString.
" [" 1487 .sprintf(
"%.2f", microtime(TRUE) - $QueryStartTime)
1491 # if query failed and there are errors that we can ignore 1492 if (($this->QueryHandle === FALSE) && $this->ErrorsToIgnore)
1494 # for each pattern for an error that we can ignore 1495 foreach ($this->ErrorsToIgnore as $SqlPattern => $ErrMsgPattern)
1497 # if error matches pattern 1498 $ErrorMsg = mysqli_error($this->Handle);
1499 if (preg_match($SqlPattern, $QueryString)
1500 && preg_match($ErrMsgPattern, $ErrorMsg))
1502 # set return value to indicate error was ignored 1503 $this->QueryHandle = TRUE;
1505 # set internal flag to indicate that an error was ignored 1506 $this->ErrorIgnored = $ErrorMsg;
1508 # stop looking at patterns 1515 if ($this->QueryHandle === FALSE)
1517 # clear stored value for number of rows retrieved 1520 # retrieve error info 1521 $this->ErrMsg = mysqli_error($this->Handle);
1522 $this->ErrNo = mysqli_errno($this->Handle);
1524 # if we are supposed to be displaying errors 1525 if (self::$DisplayErrors)
1528 print(
"<b>SQL Error:</b> <i>".$this->ErrMsg
1529 .
"</i> (".$this->ErrNo.
")<br/>\n");
1530 print(
"<b>SQL Statement:</b> <i>" 1531 .htmlspecialchars($QueryString).
"</i><br/>\n");
1533 # retrieve execution trace that got us to this point 1534 $Trace = debug_backtrace();
1536 # remove current context from trace 1537 array_shift($Trace);
1539 # make sure file name and line number are available 1540 foreach ($Trace as $Index => $Loc)
1542 if (!array_key_exists(
"file", $Loc))
1544 $Trace[$Index][
"file"] =
"UNKNOWN";
1546 if (!array_key_exists(
"line", $Loc))
1548 $Trace[$Index][
"line"] =
"??";
1552 # determine length of leading path common to all file names in trace 1554 $OurFile = __FILE__;
1556 foreach ($Trace as $Loc)
1558 if ($Loc[
"file"] !=
"UNKNOWN")
1561 $FNameLength = strlen($Loc[
"file"]);
1562 while ($Index < $FNameLength &&
1563 $Loc[
"file"][$Index] == $OurFile[$Index])
1565 $PrefixLen = min($PrefixLen, $Index);
1569 foreach ($Trace as $Loc)
1573 foreach ($Loc[
"args"] as $Arg)
1576 switch (gettype($Arg))
1579 $ArgString .= $Arg ?
"TRUE" :
"FALSE";
1588 $ArgString .=
'"<i>'.htmlspecialchars(substr($Arg, 0, 40))
1589 .((strlen($Arg) > 40) ?
"..." :
"").
'</i>"';
1595 $ArgString .= strtoupper(gettype($Arg));
1599 $ArgString .= get_class($Arg);
1602 case "unknown type":
1603 $ArgString .=
"UNKNOWN";
1608 $Loc[
"file"] = substr($Loc[
"file"], $PrefixLen);
1609 $LocString .=
" ";
1610 if (array_key_exists(
"class", $Loc))
1611 { $LocString .= $Loc[
"class"].
"::"; }
1612 $LocString .= $Loc[
"function"].
"(".$ArgString.
")" 1613 .
" - ".$Loc[
"file"].
":".$Loc[
"line"]
1616 print(
"<b>Trace:</b><br>\n".$LocString);
1619 return $this->QueryHandle;
1626 static private function GetPhpMemoryLimit()
1628 $Str = strtoupper(ini_get(
"memory_limit"));
1629 if (substr($Str, -1) ==
"B") { $Str = substr($Str, 0, strlen($Str) - 1); }
1630 switch (substr($Str, -1))
1633 $MemoryLimit = (int)$Str * 1024;
1637 $MemoryLimit = (int)$Str * 1048576;
1641 $MemoryLimit = (int)$Str * 1073741824;
1645 $MemoryLimit = (int)$Str;
1648 return $MemoryLimit;
1655 static private function GetFreeMemory()
1657 return self::GetPhpMemoryLimit() - memory_get_usage();
1661 # define return values (numerical values correspond to MySQL error codes) 1663 define(
"DB_OKAY", 0);
1664 define(
"DB_ERROR", 1);
1665 define(
"DB_ACCESSDENIED", 2);
1666 define(
"DB_UNKNOWNDB", 3);
1667 define(
"DB_UNKNOWNTABLE", 4);
1668 define(
"DB_SYNTAXERROR", 5);
1669 define(
"DB_DBALREADYEXISTS", 6);
1670 define(
"DB_DBDOESNOTEXIST", 7);
1671 define(
"DB_DISKFULL", 8);
1674 # define value to designate omitted arguments (so DB values can be set to NULL) 1675 define(
"DB_NOVALUE",
"!-_-_-DB_NOVALUE-_-_-!");
1677 # MySQL error code mapping 1688 # date() format for SQL dates 1689 define(
"DATE_SQL",
"Y-m-d H:i:s");
QueryErrMsg()
Get most recent error message text set by Query().
static Caching($NewSetting=NULL)
Get or set whether query result caching is currently enabled.
GetServerVersion($FullVersion=FALSE)
Get database server version number.
static SetGlobalDatabaseName($DatabaseName)
Set default database name.
const CR_CONNECTION_ERROR
SetDefaultStorageEngine($Engine)
Set default database storage engine.
ExecuteQueriesFromFile($FileName)
Execute queries from specified file.
UpdateIntValue($TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
A convenience function to get or set an integer value in the database.
SQL database abstraction object with smart query caching.
SetQueryErrorsToIgnore($ErrorsToIgnore, $NormalizeWhitespace=TRUE)
Set query errors to ignore.
const CR_SERVER_GONE_ERROR
DBUserName()
Get name used to connect with database server.
EscapeString($String)
Escape a string that may contain null bytes.
FetchRow()
Get next database row retrieved by most recent query.
LastInsertId()
Get ID of row added by the last SQL "INSERT" statement.
__construct($UserName=NULL, $Password=NULL, $DatabaseName=NULL, $HostName=NULL)
Object constructor.
TableExists($TableName)
Get whether specified table exists.
static SetGlobalServerInfo($UserName, $Password, $HostName="localhost")
Set default login and host info for database server.
GetClientVersion()
Get version number of the client libraries being used to connect to the database server (Currently th...
GetFieldType($TableName, $FieldName)
Get field (column) type.
NumRowsSelected()
Get number of rows returned by last SELECT or SHOW query.
FetchRows($NumberOfRows=NULL)
Get specified number of database rows retrieved by most recent query.
static QueryDebugOutput($NewSetting)
Enable or disable debugging output for queries.
Query($QueryString, $FieldName="")
Query database (with caching if enabled).
GetColumns($TableName)
Get column (database field) names.
FetchField($FieldName)
Pull next row from last DB query and get a specific value from that row.
FieldExists($TableName, $FieldName)
Get whether specified field exists in specified table.
static NumCacheHits()
Get the number of queries that have resulted in cache hits since program execution began...
FetchColumn($FieldName, $IndexFieldName=NULL)
Get all available values for specified database field retrieved by most recent query.
DBHostName()
Get host name of system on which database server resides.
NumRowsAffected()
Get number of rows affected by last INSERT, UPDATE, REPLACE, or DELETE query.
UpdateFloatValue($TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
A convenience function to get or set a float value in the database.
InsertArray($Table, $ValueField, $Values, $KeyField=NULL, $AvgDataLength=20)
Insert an array of values with a minimum number of INSERT statements.
QueryErrNo()
Get most recent error code set by Query().
GetHostInfo()
Get database connection type and hostname.
UpdateValue($TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
A convenience function to get or set a value in the database.
static AdvancedCaching($NewSetting=NULL)
Get or set whether advanced query result cachine is currently enabled.
static DisplayQueryErrors($NewValue=NULL)
Get/set whether Query() errors will be displayed.
static CacheHitRate()
Get the ratio of query cache hits to queries as a percentage.
GetMaxQueryLength()
Get maximum size for query string.
IgnoredError()
Check whether an error was ignored by the most recent query.
DBName()
Get current database name.
CopyValues($TableName, $IdColumn, $SrcId, $DstId, $ColumnsToExclude=array())
A convenience function to copy values from one row to another.
LogComment($String)
Peform query that consists of SQL comment statement.
__wakeup()
Restore database connection when unserialized.
static NumQueries()
Get the number of queries that have been run since program execution began.