00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2004-2010 Kasper Skaarhoj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 /** 00028 * Contains the class "t3lib_db" containing functions for building SQL queries 00029 * and mysql wrappers, thus providing a foundational API to all database 00030 * interaction. 00031 * This class is instantiated globally as $TYPO3_DB in TYPO3 scripts. 00032 * 00033 * $Id: class.t3lib_db.php 8197 2010-07-16 13:33:16Z xperseguers $ 00034 * 00035 * @author Kasper Skaarhoj <kasperYYYY@typo3.com> 00036 */ 00037 /** 00038 * [CLASS/FUNCTION INDEX of SCRIPT] 00039 * 00040 * 00041 * 00042 * 138: class t3lib_DB 00043 * 00044 * SECTION: Query execution 00045 * 175: function exec_INSERTquery($table,$fields_values,$no_quote_fields=FALSE) 00046 * 192: function exec_UPDATEquery($table,$where,$fields_values,$no_quote_fields=FALSE) 00047 * 206: function exec_DELETEquery($table,$where) 00048 * 225: function exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='') 00049 * 250: function exec_SELECT_mm_query($select,$local_table,$mm_table,$foreign_table,$whereClause='',$groupBy='',$orderBy='',$limit='') 00050 * 278: function exec_SELECT_queryArray($queryParts) 00051 * 301: function exec_SELECTgetRows($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='',$uidIndexField='') 00052 * 00053 * SECTION: Query building 00054 * 346: function INSERTquery($table,$fields_values,$no_quote_fields=FALSE) 00055 * 381: function UPDATEquery($table,$where,$fields_values,$no_quote_fields=FALSE) 00056 * 422: function DELETEquery($table,$where) 00057 * 451: function SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='') 00058 * 492: function listQuery($field, $value, $table) 00059 * 506: function searchQuery($searchWords,$fields,$table) 00060 * 00061 * SECTION: Various helper functions 00062 * 552: function fullQuoteStr($str, $table) 00063 * 569: function fullQuoteArray($arr, $table, $noQuote=FALSE) 00064 * 596: function quoteStr($str, $table) 00065 * 612: function escapeStrForLike($str, $table) 00066 * 625: function cleanIntArray($arr) 00067 * 641: function cleanIntList($list) 00068 * 655: function stripOrderBy($str) 00069 * 669: function stripGroupBy($str) 00070 * 681: function splitGroupOrderLimit($str) 00071 * 00072 * SECTION: MySQL wrapper functions 00073 * 749: function sql($db,$query) 00074 * 763: function sql_query($query) 00075 * 776: function sql_error() 00076 * 788: function sql_num_rows($res) 00077 * 800: function sql_fetch_assoc($res) 00078 * 813: function sql_fetch_row($res) 00079 * 825: function sql_free_result($res) 00080 * 836: function sql_insert_id() 00081 * 847: function sql_affected_rows() 00082 * 860: function sql_data_seek($res,$seek) 00083 * 873: function sql_field_type($res,$pointer) 00084 * 887: function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password) 00085 * 915: function sql_select_db($TYPO3_db) 00086 * 00087 * SECTION: SQL admin functions 00088 * 947: function admin_get_dbs() 00089 * 965: function admin_get_tables() 00090 * 984: function admin_get_fields($tableName) 00091 * 1002: function admin_get_keys($tableName) 00092 * 1020: function admin_query($query) 00093 * 00094 * SECTION: Connecting service 00095 * 1048: function connectDB() 00096 * 00097 * SECTION: Debugging 00098 * 1086: function debug($func) 00099 * 00100 * TOTAL FUNCTIONS: 42 00101 * (This index is automatically created/updated by the extension "extdeveval") 00102 * 00103 */ 00104 00105 00106 00107 00108 00109 00110 00111 00112 00113 00114 00115 00116 /** 00117 * TYPO3 "database wrapper" class (new in 3.6.0) 00118 * This class contains 00119 * - abstraction functions for executing INSERT/UPDATE/DELETE/SELECT queries ("Query execution"; These are REQUIRED for all future connectivity to the database, thus ensuring DBAL compliance!) 00120 * - functions for building SQL queries (INSERT/UPDATE/DELETE/SELECT) ("Query building"); These are transitional functions for building SQL queries in a more automated way. Use these to build queries instead of doing it manually in your code! 00121 * - mysql() wrapper functions; These are transitional functions. By a simple search/replace you should be able to substitute all mysql*() calls with $GLOBALS['TYPO3_DB']->sql*() and your application will work out of the box. YOU CANNOT (legally) use any mysql functions not found as wrapper functions in this class! 00122 * See the Project Coding Guidelines (doc_core_cgl) for more instructions on best-practise 00123 * 00124 * This class is not in itself a complete database abstraction layer but can be extended to be a DBAL (by extensions, see "dbal" for example) 00125 * ALL connectivity to the database in TYPO3 must be done through this class! 00126 * The points of this class are: 00127 * - To direct all database calls through this class so it becomes possible to implement DBAL with extensions. 00128 * - To keep it very easy to use for developers used to MySQL in PHP - and preserve as much performance as possible when TYPO3 is used with MySQL directly... 00129 * - To create an interface for DBAL implemented by extensions; (Eg. making possible escaping characters, clob/blob handling, reserved words handling) 00130 * - Benchmarking the DB bottleneck queries will become much easier; Will make it easier to find optimization possibilities. 00131 * 00132 * USE: 00133 * In all TYPO3 scripts the global variable $TYPO3_DB is an instance of this class. Use that. 00134 * Eg. $GLOBALS['TYPO3_DB']->sql_fetch_assoc() 00135 * 00136 * @author Kasper Skaarhoj <kasperYYYY@typo3.com> 00137 * @package TYPO3 00138 * @subpackage t3lib 00139 */ 00140 class t3lib_DB { 00141 00142 00143 // Debug: 00144 var $debugOutput = FALSE; // Set "TRUE" if you want database errors outputted. 00145 var $debug_lastBuiltQuery = ''; // Internally: Set to last built query (not necessarily executed...) 00146 var $store_lastBuiltQuery = FALSE; // Set "TRUE" if you want the last built query to be stored in $debug_lastBuiltQuery independent of $this->debugOutput 00147 var $explainOutput = 0; // Set this to 1 to get queries explained (devIPmask must match). Set the value to 2 to the same but disregarding the devIPmask. There is an alternative option to enable explain output in the admin panel under "TypoScript", which will produce much nicer output, but only works in FE. 00148 00149 // Default link identifier: 00150 var $link = FALSE; 00151 00152 // Default character set, applies unless character set or collation are explicitely set 00153 var $default_charset = 'utf8'; 00154 00155 00156 00157 00158 /************************************ 00159 * 00160 * Query execution 00161 * 00162 * These functions are the RECOMMENDED DBAL functions for use in your applications 00163 * Using these functions will allow the DBAL to use alternative ways of accessing data (contrary to if a query is returned!) 00164 * They compile a query AND execute it immediately and then return the result 00165 * This principle heightens our ability to create various forms of DBAL of the functions. 00166 * Generally: We want to return a result pointer/object, never queries. 00167 * Also, having the table name together with the actual query execution allows us to direct the request to other databases. 00168 * 00169 **************************************/ 00170 00171 /** 00172 * Creates and executes an INSERT SQL-statement for $table from the array with field/value pairs $fields_values. 00173 * Using this function specifically allows us to handle BLOB and CLOB fields depending on DB 00174 * Usage count/core: 47 00175 * 00176 * @param string Table name 00177 * @param array Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$insertFields" with 'fieldname'=>'value' and pass it to this function as argument. 00178 * @param string/array See fullQuoteArray() 00179 * @return pointer MySQL result pointer / DBAL object 00180 */ 00181 function exec_INSERTquery($table, $fields_values, $no_quote_fields = FALSE) { 00182 $res = mysql_query($this->INSERTquery($table, $fields_values, $no_quote_fields), $this->link); 00183 if ($this->debugOutput) { 00184 $this->debug('exec_INSERTquery'); 00185 } 00186 return $res; 00187 } 00188 00189 /** 00190 * Creates and executes an INSERT SQL-statement for $table with multiple rows. 00191 * 00192 * @param string Table name 00193 * @param array Field names 00194 * @param array Table rows. Each row should be an array with field values mapping to $fields 00195 * @param string/array See fullQuoteArray() 00196 * @return pointer MySQL result pointer / DBAL object 00197 */ 00198 public function exec_INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) { 00199 $res = mysql_query($this->INSERTmultipleRows($table, $fields, $rows, $no_quote_fields), $this->link); 00200 if ($this->debugOutput) { 00201 $this->debug('exec_INSERTmultipleRows'); 00202 } 00203 return $res; 00204 } 00205 00206 /** 00207 * Creates and executes an UPDATE SQL-statement for $table where $where-clause (typ. 'uid=...') from the array with field/value pairs $fields_values. 00208 * Using this function specifically allow us to handle BLOB and CLOB fields depending on DB 00209 * Usage count/core: 50 00210 * 00211 * @param string Database tablename 00212 * @param string WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself! 00213 * @param array Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$updateFields" with 'fieldname'=>'value' and pass it to this function as argument. 00214 * @param string/array See fullQuoteArray() 00215 * @return pointer MySQL result pointer / DBAL object 00216 */ 00217 function exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields = FALSE) { 00218 $res = mysql_query($this->UPDATEquery($table, $where, $fields_values, $no_quote_fields), $this->link); 00219 if ($this->debugOutput) { 00220 $this->debug('exec_UPDATEquery'); 00221 } 00222 return $res; 00223 } 00224 00225 /** 00226 * Creates and executes a DELETE SQL-statement for $table where $where-clause 00227 * Usage count/core: 40 00228 * 00229 * @param string Database tablename 00230 * @param string WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself! 00231 * @return pointer MySQL result pointer / DBAL object 00232 */ 00233 function exec_DELETEquery($table, $where) { 00234 $res = mysql_query($this->DELETEquery($table, $where), $this->link); 00235 if ($this->debugOutput) { 00236 $this->debug('exec_DELETEquery'); 00237 } 00238 return $res; 00239 } 00240 00241 /** 00242 * Creates and executes a SELECT SQL-statement 00243 * Using this function specifically allow us to handle the LIMIT feature independently of DB. 00244 * Usage count/core: 340 00245 * 00246 * @param string List of fields to select from the table. This is what comes right after "SELECT ...". Required value. 00247 * @param string Table(s) from which to select. This is what comes right after "FROM ...". Required value. 00248 * @param string Optional additional WHERE clauses put in the end of the query. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself! DO NOT PUT IN GROUP BY, ORDER BY or LIMIT! 00249 * @param string Optional GROUP BY field(s), if none, supply blank string. 00250 * @param string Optional ORDER BY field(s), if none, supply blank string. 00251 * @param string Optional LIMIT value ([begin,]max), if none, supply blank string. 00252 * @return pointer MySQL result pointer / DBAL object 00253 */ 00254 function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') { 00255 $query = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit); 00256 $res = mysql_query($query, $this->link); 00257 00258 if ($this->debugOutput) { 00259 $this->debug('exec_SELECTquery'); 00260 } 00261 if ($this->explainOutput) { 00262 $this->explain($query, $from_table, $this->sql_num_rows($res)); 00263 } 00264 00265 return $res; 00266 } 00267 00268 /** 00269 * Creates and executes a SELECT query, selecting fields ($select) from two/three tables joined 00270 * Use $mm_table together with $local_table or $foreign_table to select over two tables. Or use all three tables to select the full MM-relation. 00271 * The JOIN is done with [$local_table].uid <--> [$mm_table].uid_local / [$mm_table].uid_foreign <--> [$foreign_table].uid 00272 * The function is very useful for selecting MM-relations between tables adhering to the MM-format used by TCE (TYPO3 Core Engine). See the section on $TCA in Inside TYPO3 for more details. 00273 * 00274 * Usage: 12 (spec. ext. sys_action, sys_messages, sys_todos) 00275 * 00276 * @param string Field list for SELECT 00277 * @param string Tablename, local table 00278 * @param string Tablename, relation table 00279 * @param string Tablename, foreign table 00280 * @param string Optional additional WHERE clauses put in the end of the query. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself! DO NOT PUT IN GROUP BY, ORDER BY or LIMIT! You have to prepend 'AND ' to this parameter yourself! 00281 * @param string Optional GROUP BY field(s), if none, supply blank string. 00282 * @param string Optional ORDER BY field(s), if none, supply blank string. 00283 * @param string Optional LIMIT value ([begin,]max), if none, supply blank string. 00284 * @return pointer MySQL result pointer / DBAL object 00285 * @see exec_SELECTquery() 00286 */ 00287 function exec_SELECT_mm_query($select, $local_table, $mm_table, $foreign_table, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '') { 00288 if ($foreign_table == $local_table) { 00289 $foreign_table_as = $foreign_table . uniqid('_join'); 00290 } 00291 00292 $mmWhere = $local_table ? $local_table . '.uid=' . $mm_table . '.uid_local' : ''; 00293 $mmWhere .= ($local_table AND $foreign_table) ? ' AND ' : ''; 00294 00295 $tables = ($local_table ? $local_table . ',' : '') . $mm_table; 00296 00297 if ($foreign_table) { 00298 $mmWhere .= ($foreign_table_as ? $foreign_table_as : $foreign_table) . '.uid=' . $mm_table . '.uid_foreign'; 00299 $tables .= ',' . $foreign_table . ($foreign_table_as ? ' AS ' . $foreign_table_as : ''); 00300 } 00301 00302 return $this->exec_SELECTquery( 00303 $select, 00304 $tables, 00305 // whereClauseMightContainGroupOrderBy 00306 $mmWhere . ' ' . $whereClause, 00307 $groupBy, 00308 $orderBy, 00309 $limit 00310 ); 00311 } 00312 00313 /** 00314 * Executes a select based on input query parts array 00315 * 00316 * Usage: 9 00317 * 00318 * @param array Query parts array 00319 * @return pointer MySQL select result pointer / DBAL object 00320 * @see exec_SELECTquery() 00321 */ 00322 function exec_SELECT_queryArray($queryParts) { 00323 return $this->exec_SELECTquery( 00324 $queryParts['SELECT'], 00325 $queryParts['FROM'], 00326 $queryParts['WHERE'], 00327 $queryParts['GROUPBY'], 00328 $queryParts['ORDERBY'], 00329 $queryParts['LIMIT'] 00330 ); 00331 } 00332 00333 /** 00334 * Creates and executes a SELECT SQL-statement AND traverse result set and returns array with records in. 00335 * 00336 * @param string See exec_SELECTquery() 00337 * @param string See exec_SELECTquery() 00338 * @param string See exec_SELECTquery() 00339 * @param string See exec_SELECTquery() 00340 * @param string See exec_SELECTquery() 00341 * @param string See exec_SELECTquery() 00342 * @param string If set, the result array will carry this field names value as index. Requires that field to be selected of course! 00343 * @return array Array of rows. 00344 */ 00345 function exec_SELECTgetRows($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', $uidIndexField = '') { 00346 $res = $this->exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit); 00347 if ($this->debugOutput) { 00348 $this->debug('exec_SELECTquery'); 00349 } 00350 00351 if (!$this->sql_error()) { 00352 $output = array(); 00353 00354 if ($uidIndexField) { 00355 while ($tempRow = $this->sql_fetch_assoc($res)) { 00356 $output[$tempRow[$uidIndexField]] = $tempRow; 00357 } 00358 } else { 00359 while ($output[] = $this->sql_fetch_assoc($res)); 00360 array_pop($output); 00361 } 00362 $this->sql_free_result($res); 00363 } 00364 return $output; 00365 } 00366 00367 /** 00368 * Counts the number of rows in a table. 00369 * 00370 * @param string $field: Name of the field to use in the COUNT() expression (e.g. '*') 00371 * @param string $table: Name of the table to count rows for 00372 * @param string $where: (optional) WHERE statement of the query 00373 * @return mixed Number of rows counter (integer) or false if something went wrong (boolean) 00374 */ 00375 public function exec_SELECTcountRows($field, $table, $where = '') { 00376 $count = false; 00377 $resultSet = $this->exec_SELECTquery('COUNT(' . $field . ')', $table, $where); 00378 if ($resultSet !== false) { 00379 list($count) = $this->sql_fetch_row($resultSet); 00380 $this->sql_free_result($resultSet); 00381 } 00382 return $count; 00383 } 00384 00385 /** 00386 * Truncates a table. 00387 * 00388 * @param string Database tablename 00389 * @return mixed Result from handler 00390 */ 00391 public function exec_TRUNCATEquery($table) { 00392 $res = mysql_query($this->TRUNCATEquery($table), $this->link); 00393 if ($this->debugOutput) { 00394 $this->debug('exec_TRUNCATEquery'); 00395 } 00396 return $res; 00397 } 00398 00399 00400 00401 00402 00403 00404 00405 00406 00407 00408 00409 /************************************** 00410 * 00411 * Query building 00412 * 00413 **************************************/ 00414 00415 /** 00416 * Creates an INSERT SQL-statement for $table from the array with field/value pairs $fields_values. 00417 * Usage count/core: 4 00418 * 00419 * @param string See exec_INSERTquery() 00420 * @param array See exec_INSERTquery() 00421 * @param string/array See fullQuoteArray() 00422 * @return string Full SQL query for INSERT (unless $fields_values does not contain any elements in which case it will be false) 00423 */ 00424 function INSERTquery($table, $fields_values, $no_quote_fields = FALSE) { 00425 00426 // Table and fieldnames should be "SQL-injection-safe" when supplied to this 00427 // function (contrary to values in the arrays which may be insecure). 00428 if (is_array($fields_values) && count($fields_values)) { 00429 00430 // quote and escape values 00431 $fields_values = $this->fullQuoteArray($fields_values, $table, $no_quote_fields); 00432 00433 // Build query: 00434 $query = 'INSERT INTO ' . $table . 00435 '(' . implode(',', array_keys($fields_values)) . ') VALUES ' . 00436 '(' . implode(',', $fields_values) . ')'; 00437 00438 // Return query: 00439 if ($this->debugOutput || $this->store_lastBuiltQuery) { 00440 $this->debug_lastBuiltQuery = $query; 00441 } 00442 return $query; 00443 } 00444 } 00445 00446 /** 00447 * Creates an INSERT SQL-statement for $table with multiple rows. 00448 * 00449 * @param string Table name 00450 * @param array Field names 00451 * @param array Table rows. Each row should be an array with field values mapping to $fields 00452 * @param string/array See fullQuoteArray() 00453 * @return string Full SQL query for INSERT (unless $rows does not contain any elements in which case it will be false) 00454 */ 00455 public function INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) { 00456 // Table and fieldnames should be "SQL-injection-safe" when supplied to this 00457 // function (contrary to values in the arrays which may be insecure). 00458 if (count($rows)) { 00459 // Build query: 00460 $query = 'INSERT INTO ' . $table . 00461 ' (' . implode(', ', $fields) . ') VALUES '; 00462 00463 $rowSQL = array(); 00464 foreach ($rows as $row) { 00465 // quote and escape values 00466 $row = $this->fullQuoteArray($row, $table, $no_quote_fields); 00467 $rowSQL[] = '(' . implode(', ', $row) . ')'; 00468 } 00469 00470 $query .= implode(', ', $rowSQL); 00471 00472 // Return query: 00473 if ($this->debugOutput || $this->store_lastBuiltQuery) { 00474 $this->debug_lastBuiltQuery = $query; 00475 } 00476 00477 return $query; 00478 } 00479 } 00480 00481 /** 00482 * Creates an UPDATE SQL-statement for $table where $where-clause (typ. 'uid=...') from the array with field/value pairs $fields_values. 00483 * Usage count/core: 6 00484 * 00485 * @param string See exec_UPDATEquery() 00486 * @param string See exec_UPDATEquery() 00487 * @param array See exec_UPDATEquery() 00488 * @param array See fullQuoteArray() 00489 * @return string Full SQL query for UPDATE 00490 */ 00491 function UPDATEquery($table, $where, $fields_values, $no_quote_fields = FALSE) { 00492 // Table and fieldnames should be "SQL-injection-safe" when supplied to this 00493 // function (contrary to values in the arrays which may be insecure). 00494 if (is_string($where)) { 00495 $fields = array(); 00496 if (is_array($fields_values) && count($fields_values)) { 00497 00498 // quote and escape values 00499 $nArr = $this->fullQuoteArray($fields_values, $table, $no_quote_fields); 00500 00501 foreach ($nArr as $k => $v) { 00502 $fields[] = $k.'='.$v; 00503 } 00504 } 00505 00506 // Build query: 00507 $query = 'UPDATE ' . $table . ' SET ' . implode(',', $fields) . 00508 (strlen($where) > 0 ? ' WHERE ' . $where : ''); 00509 00510 if ($this->debugOutput || $this->store_lastBuiltQuery) { 00511 $this->debug_lastBuiltQuery = $query; 00512 } 00513 return $query; 00514 } else { 00515 throw new InvalidArgumentException( 00516 'TYPO3 Fatal Error: "Where" clause argument for UPDATE query was not a string in $this->UPDATEquery() !', 00517 1270853880 00518 ); 00519 } 00520 } 00521 00522 /** 00523 * Creates a DELETE SQL-statement for $table where $where-clause 00524 * Usage count/core: 3 00525 * 00526 * @param string See exec_DELETEquery() 00527 * @param string See exec_DELETEquery() 00528 * @return string Full SQL query for DELETE 00529 */ 00530 function DELETEquery($table, $where) { 00531 if (is_string($where)) { 00532 00533 // Table and fieldnames should be "SQL-injection-safe" when supplied to this function 00534 $query = 'DELETE FROM ' . $table . 00535 (strlen($where) > 0 ? ' WHERE ' . $where : ''); 00536 00537 if ($this->debugOutput || $this->store_lastBuiltQuery) { 00538 $this->debug_lastBuiltQuery = $query; 00539 } 00540 return $query; 00541 } else { 00542 throw new InvalidArgumentException( 00543 'TYPO3 Fatal Error: "Where" clause argument for DELETE query was not a string in $this->DELETEquery() !', 00544 1270853881 00545 ); 00546 } 00547 } 00548 00549 /** 00550 * Creates a SELECT SQL-statement 00551 * Usage count/core: 11 00552 * 00553 * @param string See exec_SELECTquery() 00554 * @param string See exec_SELECTquery() 00555 * @param string See exec_SELECTquery() 00556 * @param string See exec_SELECTquery() 00557 * @param string See exec_SELECTquery() 00558 * @param string See exec_SELECTquery() 00559 * @return string Full SQL query for SELECT 00560 */ 00561 function SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') { 00562 00563 // Table and fieldnames should be "SQL-injection-safe" when supplied to this function 00564 // Build basic query: 00565 $query = 'SELECT ' . $select_fields . ' FROM ' . $from_table . 00566 (strlen($where_clause) > 0 ? ' WHERE ' . $where_clause : ''); 00567 00568 // Group by: 00569 $query .= (strlen($groupBy) > 0 ? ' GROUP BY ' . $groupBy : ''); 00570 00571 // Order by: 00572 $query .= (strlen($orderBy) > 0 ? ' ORDER BY ' . $orderBy : ''); 00573 00574 // Group by: 00575 $query .= (strlen($limit) > 0 ? ' LIMIT ' . $limit : ''); 00576 00577 // Return query: 00578 if ($this->debugOutput || $this->store_lastBuiltQuery) { 00579 $this->debug_lastBuiltQuery = $query; 00580 } 00581 return $query; 00582 } 00583 00584 /** 00585 * Creates a SELECT SQL-statement to be used as subquery within another query. 00586 * BEWARE: This method should not be overriden within DBAL to prevent quoting from happening. 00587 * 00588 * @param string $select_fields: List of fields to select from the table. 00589 * @param string $from_table: Table from which to select. 00590 * @param string $where_clause: Conditional WHERE statement 00591 * @return string Full SQL query for SELECT 00592 */ 00593 public function SELECTsubquery($select_fields, $from_table, $where_clause) { 00594 // Table and fieldnames should be "SQL-injection-safe" when supplied to this function 00595 // Build basic query: 00596 $query = 'SELECT ' . $select_fields . ' FROM ' . $from_table . 00597 (strlen($where_clause) > 0 ? ' WHERE ' . $where_clause : ''); 00598 00599 // Return query: 00600 if ($this->debugOutput || $this->store_lastBuiltQuery) { 00601 $this->debug_lastBuiltQuery = $query; 00602 } 00603 00604 return $query; 00605 } 00606 00607 /** 00608 * Creates a TRUNCATE TABLE SQL-statement 00609 * 00610 * @param string See exec_TRUNCATEquery() 00611 * @return string Full SQL query for TRUNCATE TABLE 00612 */ 00613 public function TRUNCATEquery($table) { 00614 // Table should be "SQL-injection-safe" when supplied to this function 00615 // Build basic query: 00616 $query = 'TRUNCATE TABLE ' . $table; 00617 00618 // Return query: 00619 if ($this->debugOutput || $this->store_lastBuiltQuery) { 00620 $this->debug_lastBuiltQuery = $query; 00621 } 00622 00623 return $query; 00624 } 00625 00626 /** 00627 * Returns a WHERE clause that can find a value ($value) in a list field ($field) 00628 * For instance a record in the database might contain a list of numbers, 00629 * "34,234,5" (with no spaces between). This query would be able to select that 00630 * record based on the value "34", "234" or "5" regardless of their position in 00631 * the list (left, middle or right). 00632 * The value must not contain a comma (,) 00633 * Is nice to look up list-relations to records or files in TYPO3 database tables. 00634 * 00635 * @param string Field name 00636 * @param string Value to find in list 00637 * @param string Table in which we are searching (for DBAL detection of quoteStr() method) 00638 * @return string WHERE clause for a query 00639 */ 00640 public function listQuery($field, $value, $table) { 00641 if (strpos(',', $value) !== FALSE) { 00642 throw new InvalidArgumentException('$value must not contain a comma (,) in $this->listQuery() !'); 00643 } 00644 $pattern = $this->quoteStr($value, $table); 00645 $where = 'FIND_IN_SET(\'' . $pattern . '\',' . $field . ')'; 00646 return $where; 00647 } 00648 00649 /** 00650 * Returns a WHERE clause which will make an AND search for the words in the $searchWords array in any of the fields in array $fields. 00651 * 00652 * @param array Array of search words 00653 * @param array Array of fields 00654 * @param string Table in which we are searching (for DBAL detection of quoteStr() method) 00655 * @return string WHERE clause for search 00656 */ 00657 function searchQuery($searchWords, $fields, $table) { 00658 $queryParts = array(); 00659 00660 foreach($searchWords as $sw) { 00661 $like = ' LIKE \'%' . $this->quoteStr($sw, $table) . '%\''; 00662 $queryParts[] = $table . '.' . implode($like . ' OR ' . $table . '.', $fields) . $like; 00663 } 00664 $query = '(' . implode(') AND (', $queryParts) . ')'; 00665 return $query ; 00666 } 00667 00668 00669 00670 00671 00672 00673 00674 00675 00676 00677 00678 00679 00680 00681 00682 00683 /************************************** 00684 * 00685 * Various helper functions 00686 * 00687 * Functions recommended to be used for 00688 * - escaping values, 00689 * - cleaning lists of values, 00690 * - stripping of excess ORDER BY/GROUP BY keywords 00691 * 00692 **************************************/ 00693 00694 /** 00695 * Escaping and quoting values for SQL statements. 00696 * Usage count/core: 100 00697 * 00698 * @param string Input string 00699 * @param string Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!). 00700 * @return string Output string; Wrapped in single quotes and quotes in the string (" / ') and \ will be backslashed (or otherwise based on DBAL handler) 00701 * @see quoteStr() 00702 */ 00703 function fullQuoteStr($str, $table) { 00704 return '\'' . mysql_real_escape_string($str, $this->link) . '\''; 00705 } 00706 00707 /** 00708 * Will fullquote all values in the one-dimensional array so they are ready to "implode" for an sql query. 00709 * 00710 * @param array Array with values (either associative or non-associative array) 00711 * @param string Table name for which to quote 00712 * @param string/array List/array of keys NOT to quote (eg. SQL functions) - ONLY for associative arrays 00713 * @return array The input array with the values quoted 00714 * @see cleanIntArray() 00715 */ 00716 function fullQuoteArray($arr, $table, $noQuote = FALSE) { 00717 if (is_string($noQuote)) { 00718 $noQuote = explode(',', $noQuote); 00719 // sanity check 00720 } elseif (!is_array($noQuote)) { 00721 $noQuote = FALSE; 00722 } 00723 00724 foreach($arr as $k => $v) { 00725 if ($noQuote === FALSE || !in_array($k, $noQuote)) { 00726 $arr[$k] = $this->fullQuoteStr($v, $table); 00727 } 00728 } 00729 return $arr; 00730 } 00731 00732 /** 00733 * Substitution for PHP function "addslashes()" 00734 * Use this function instead of the PHP addslashes() function when you build queries - this will prepare your code for DBAL. 00735 * NOTICE: You must wrap the output of this function in SINGLE QUOTES to be DBAL compatible. Unless you have to apply the single quotes yourself you should rather use ->fullQuoteStr()! 00736 * 00737 * Usage count/core: 20 00738 * 00739 * @param string Input string 00740 * @param string Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!). 00741 * @return string Output string; Quotes (" / ') and \ will be backslashed (or otherwise based on DBAL handler) 00742 * @see quoteStr() 00743 */ 00744 function quoteStr($str, $table) { 00745 return mysql_real_escape_string($str, $this->link); 00746 } 00747 00748 /** 00749 * Escaping values for SQL LIKE statements. 00750 * 00751 * @param string Input string 00752 * @param string Table name for which to escape string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!). 00753 * @return string Output string; % and _ will be escaped with \ (or otherwise based on DBAL handler) 00754 * @see quoteStr() 00755 */ 00756 function escapeStrForLike($str, $table) { 00757 return preg_replace('/[_%]/', '\\\$0', $str); 00758 } 00759 00760 /** 00761 * Will convert all values in the one-dimensional array to integers. 00762 * Useful when you want to make sure an array contains only integers before imploding them in a select-list. 00763 * Usage count/core: 7 00764 * 00765 * @param array Array with values 00766 * @return array The input array with all values passed through intval() 00767 * @see cleanIntList() 00768 */ 00769 function cleanIntArray($arr) { 00770 foreach($arr as $k => $v) { 00771 $arr[$k] = intval($arr[$k]); 00772 } 00773 return $arr; 00774 } 00775 00776 /** 00777 * Will force all entries in the input comma list to integers 00778 * Useful when you want to make sure a commalist of supposed integers really contain only integers; You want to know that when you don't trust content that could go into an SQL statement. 00779 * Usage count/core: 6 00780 * 00781 * @param string List of comma-separated values which should be integers 00782 * @return string The input list but with every value passed through intval() 00783 * @see cleanIntArray() 00784 */ 00785 function cleanIntList($list) { 00786 return implode(',', t3lib_div::intExplode(',', $list)); 00787 } 00788 00789 /** 00790 * Removes the prefix "ORDER BY" from the input string. 00791 * This function is used when you call the exec_SELECTquery() function and want to pass the ORDER BY parameter by can't guarantee that "ORDER BY" is not prefixed. 00792 * Generally; This function provides a work-around to the situation where you cannot pass only the fields by which to order the result. 00793 * Usage count/core: 11 00794 * 00795 * @param string eg. "ORDER BY title, uid" 00796 * @return string eg. "title, uid" 00797 * @see exec_SELECTquery(), stripGroupBy() 00798 */ 00799 function stripOrderBy($str) { 00800 return preg_replace('/^ORDER[[:space:]]+BY[[:space:]]+/i', '', trim($str)); 00801 } 00802 00803 /** 00804 * Removes the prefix "GROUP BY" from the input string. 00805 * This function is used when you call the SELECTquery() function and want to pass the GROUP BY parameter by can't guarantee that "GROUP BY" is not prefixed. 00806 * Generally; This function provides a work-around to the situation where you cannot pass only the fields by which to order the result. 00807 * Usage count/core: 1 00808 * 00809 * @param string eg. "GROUP BY title, uid" 00810 * @return string eg. "title, uid" 00811 * @see exec_SELECTquery(), stripOrderBy() 00812 */ 00813 function stripGroupBy($str) { 00814 return preg_replace('/^GROUP[[:space:]]+BY[[:space:]]+/i', '', trim($str)); 00815 } 00816 00817 /** 00818 * Takes the last part of a query, eg. "... uid=123 GROUP BY title ORDER BY title LIMIT 5,2" and splits each part into a table (WHERE, GROUPBY, ORDERBY, LIMIT) 00819 * Work-around function for use where you know some userdefined end to an SQL clause is supplied and you need to separate these factors. 00820 * Usage count/core: 13 00821 * 00822 * @param string Input string 00823 * @return array 00824 */ 00825 function splitGroupOrderLimit($str) { 00826 // Prepending a space to make sure "[[:space:]]+" will find a space there 00827 // for the first element. 00828 $str = ' ' . $str; 00829 // Init output array: 00830 $wgolParts = array( 00831 'WHERE' => '', 00832 'GROUPBY' => '', 00833 'ORDERBY' => '', 00834 'LIMIT' => '', 00835 ); 00836 00837 // Find LIMIT: 00838 $reg = array(); 00839 if (preg_match('/^(.*)[[:space:]]+LIMIT[[:space:]]+([[:alnum:][:space:],._]+)$/i', $str, $reg)) { 00840 $wgolParts['LIMIT'] = trim($reg[2]); 00841 $str = $reg[1]; 00842 } 00843 00844 // Find ORDER BY: 00845 $reg = array(); 00846 if (preg_match('/^(.*)[[:space:]]+ORDER[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i', $str, $reg)) { 00847 $wgolParts['ORDERBY'] = trim($reg[2]); 00848 $str = $reg[1]; 00849 } 00850 00851 // Find GROUP BY: 00852 $reg = array(); 00853 if (preg_match('/^(.*)[[:space:]]+GROUP[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i', $str, $reg)) { 00854 $wgolParts['GROUPBY'] = trim($reg[2]); 00855 $str = $reg[1]; 00856 } 00857 00858 // Rest is assumed to be "WHERE" clause: 00859 $wgolParts['WHERE'] = $str; 00860 00861 return $wgolParts; 00862 } 00863 00864 00865 00866 00867 00868 00869 00870 00871 00872 00873 00874 00875 00876 00877 00878 /************************************** 00879 * 00880 * MySQL wrapper functions 00881 * (For use in your applications) 00882 * 00883 **************************************/ 00884 00885 /** 00886 * Executes query 00887 * mysql() wrapper function 00888 * Usage count/core: 0 00889 * 00890 * @param string Database name 00891 * @param string Query to execute 00892 * @return pointer Result pointer / DBAL object 00893 * @deprecated since TYPO3 3.6, will be removed in TYPO3 4.5 00894 * @see sql_query() 00895 */ 00896 function sql($db, $query) { 00897 t3lib_div::logDeprecatedFunction(); 00898 00899 $res = mysql_query($query, $this->link); 00900 if ($this->debugOutput) { 00901 $this->debug('sql', $query); 00902 } 00903 return $res; 00904 } 00905 00906 /** 00907 * Executes query 00908 * mysql_query() wrapper function 00909 * Usage count/core: 1 00910 * 00911 * @param string Query to execute 00912 * @return pointer Result pointer / DBAL object 00913 */ 00914 function sql_query($query) { 00915 $res = mysql_query($query, $this->link); 00916 if ($this->debugOutput) { 00917 $this->debug('sql_query', $query); 00918 } 00919 return $res; 00920 } 00921 00922 /** 00923 * Returns the error status on the last sql() execution 00924 * mysql_error() wrapper function 00925 * Usage count/core: 32 00926 * 00927 * @return string MySQL error string. 00928 */ 00929 function sql_error() { 00930 return mysql_error($this->link); 00931 } 00932 00933 /** 00934 * Returns the error number on the last sql() execution 00935 * mysql_errno() wrapper function 00936 * 00937 * @return int MySQL error number. 00938 */ 00939 function sql_errno() { 00940 return mysql_errno($this->link); 00941 } 00942 00943 /** 00944 * Returns the number of selected rows. 00945 * mysql_num_rows() wrapper function 00946 * Usage count/core: 85 00947 * 00948 * @param pointer MySQL result pointer (of SELECT query) / DBAL object 00949 * @return integer Number of resulting rows 00950 */ 00951 function sql_num_rows($res) { 00952 if ($this->debug_check_recordset($res)) { 00953 return mysql_num_rows($res); 00954 } else { 00955 return FALSE; 00956 } 00957 } 00958 00959 /** 00960 * Returns an associative array that corresponds to the fetched row, or FALSE if there are no more rows. 00961 * mysql_fetch_assoc() wrapper function 00962 * Usage count/core: 307 00963 * 00964 * @param pointer MySQL result pointer (of SELECT query) / DBAL object 00965 * @return array Associative array of result row. 00966 */ 00967 function sql_fetch_assoc($res) { 00968 if ($this->debug_check_recordset($res)) { 00969 return mysql_fetch_assoc($res); 00970 } else { 00971 return FALSE; 00972 } 00973 } 00974 00975 /** 00976 * Returns an array that corresponds to the fetched row, or FALSE if there are no more rows. 00977 * The array contains the values in numerical indices. 00978 * mysql_fetch_row() wrapper function 00979 * Usage count/core: 56 00980 * 00981 * @param pointer MySQL result pointer (of SELECT query) / DBAL object 00982 * @return array Array with result rows. 00983 */ 00984 function sql_fetch_row($res) { 00985 if ($this->debug_check_recordset($res)) { 00986 return mysql_fetch_row($res); 00987 } else { 00988 return FALSE; 00989 } 00990 } 00991 00992 /** 00993 * Free result memory 00994 * mysql_free_result() wrapper function 00995 * Usage count/core: 3 00996 * 00997 * @param pointer MySQL result pointer to free / DBAL object 00998 * @return boolean Returns TRUE on success or FALSE on failure. 00999 */ 01000 function sql_free_result($res) { 01001 if ($this->debug_check_recordset($res)) { 01002 return mysql_free_result($res); 01003 } else { 01004 return FALSE; 01005 } 01006 } 01007 01008 /** 01009 * Get the ID generated from the previous INSERT operation 01010 * mysql_insert_id() wrapper function 01011 * Usage count/core: 13 01012 * 01013 * @return integer The uid of the last inserted record. 01014 */ 01015 function sql_insert_id() { 01016 return mysql_insert_id($this->link); 01017 } 01018 01019 /** 01020 * Returns the number of rows affected by the last INSERT, UPDATE or DELETE query 01021 * mysql_affected_rows() wrapper function 01022 * Usage count/core: 1 01023 * 01024 * @return integer Number of rows affected by last query 01025 */ 01026 function sql_affected_rows() { 01027 return mysql_affected_rows($this->link); 01028 } 01029 01030 /** 01031 * Move internal result pointer 01032 * mysql_data_seek() wrapper function 01033 * Usage count/core: 3 01034 * 01035 * @param pointer MySQL result pointer (of SELECT query) / DBAL object 01036 * @param integer Seek result number. 01037 * @return boolean Returns TRUE on success or FALSE on failure. 01038 */ 01039 function sql_data_seek($res, $seek) { 01040 if ($this->debug_check_recordset($res)) { 01041 return mysql_data_seek($res, $seek); 01042 } else { 01043 return FALSE; 01044 } 01045 } 01046 01047 /** 01048 * Get the type of the specified field in a result 01049 * mysql_field_type() wrapper function 01050 * Usage count/core: 2 01051 * 01052 * @param pointer MySQL result pointer (of SELECT query) / DBAL object 01053 * @param integer Field index. 01054 * @return string Returns the name of the specified field index 01055 */ 01056 function sql_field_type($res, $pointer) { 01057 if ($this->debug_check_recordset($res)) { 01058 return mysql_field_type($res, $pointer); 01059 } else { 01060 return FALSE; 01061 } 01062 } 01063 01064 /** 01065 * Open a (persistent) connection to a MySQL server 01066 * mysql_pconnect() wrapper function 01067 * Usage count/core: 12 01068 * 01069 * @param string Database host IP/domain 01070 * @param string Username to connect with. 01071 * @param string Password to connect with. 01072 * @return pointer Returns a positive MySQL persistent link identifier on success, or FALSE on error. 01073 */ 01074 function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password) { 01075 // mysql_error() is tied to an established connection 01076 // if the connection fails we need a different method to get the error message 01077 @ini_set('track_errors', 1); 01078 @ini_set('html_errors', 0); 01079 01080 // check if MySQL extension is loaded 01081 if (!extension_loaded('mysql')) { 01082 $message = 'Database Error: It seems that MySQL support for PHP is not installed!'; 01083 throw new RuntimeException($message, 1271492606); 01084 } 01085 01086 // Check for client compression 01087 $isLocalhost = ($TYPO3_db_host == 'localhost' || $TYPO3_db_host == '127.0.0.1'); 01088 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) { 01089 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['dbClientCompress'] && !$isLocalhost) { 01090 // We use PHP's default value for 4th parameter (new_link), which is false. 01091 // See PHP sources, for example: file php-5.2.5/ext/mysql/php_mysql.c, 01092 // function php_mysql_do_connect(), near line 525 01093 $this->link = @mysql_connect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password, false, MYSQL_CLIENT_COMPRESS); 01094 } else { 01095 $this->link = @mysql_connect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password); 01096 } 01097 } else { 01098 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['dbClientCompress'] && !$isLocalhost) { 01099 // See comment about 4th parameter in block above 01100 $this->link = @mysql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password, false, MYSQL_CLIENT_COMPRESS); 01101 } else { 01102 $this->link = @mysql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password); 01103 } 01104 } 01105 01106 $error_msg = $php_errormsg; 01107 @ini_restore('track_errors'); 01108 @ini_restore('html_errors'); 01109 01110 if (!$this->link) { 01111 t3lib_div::sysLog('Could not connect to MySQL server ' . $TYPO3_db_host . 01112 ' with user ' . $TYPO3_db_username . ': ' . $error_msg, 01113 'Core', 01114 4 01115 ); 01116 } else { 01117 $setDBinit = t3lib_div::trimExplode(LF, str_replace("' . LF . '", LF, $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']), TRUE); 01118 foreach ($setDBinit as $v) { 01119 if (mysql_query($v, $this->link) === FALSE) { 01120 t3lib_div::sysLog('Could not initialize DB connection with query "' . $v . 01121 '": ' . mysql_error($this->link), 01122 'Core', 01123 3 01124 ); 01125 } 01126 } 01127 } 01128 01129 return $this->link; 01130 } 01131 01132 /** 01133 * Select a MySQL database 01134 * mysql_select_db() wrapper function 01135 * Usage count/core: 8 01136 * 01137 * @param string Database to connect to. 01138 * @return boolean Returns TRUE on success or FALSE on failure. 01139 */ 01140 function sql_select_db($TYPO3_db) { 01141 $ret = @mysql_select_db($TYPO3_db, $this->link); 01142 if (!$ret) { 01143 t3lib_div::sysLog('Could not select MySQL database ' . $TYPO3_db . ': ' . 01144 mysql_error(), 01145 'Core', 01146 4 01147 ); 01148 } 01149 return $ret; 01150 } 01151 01152 01153 01154 01155 01156 01157 01158 01159 01160 01161 /************************************** 01162 * 01163 * SQL admin functions 01164 * (For use in the Install Tool and Extension Manager) 01165 * 01166 **************************************/ 01167 01168 /** 01169 * Listing databases from current MySQL connection. NOTICE: It WILL try to select those databases and thus break selection of current database. 01170 * This is only used as a service function in the (1-2-3 process) of the Install Tool. 01171 * In any case a lookup should be done in the _DEFAULT handler DBMS then. 01172 * Use in Install Tool only! 01173 * Usage count/core: 1 01174 * 01175 * @return array Each entry represents a database name 01176 */ 01177 function admin_get_dbs() { 01178 $dbArr = array(); 01179 $db_list = mysql_list_dbs($this->link); 01180 while ($row = mysql_fetch_object($db_list)) { 01181 if ($this->sql_select_db($row->Database)) { 01182 $dbArr[] = $row->Database; 01183 } 01184 } 01185 return $dbArr; 01186 } 01187 01188 /** 01189 * Returns the list of tables from the default database, TYPO3_db (quering the DBMS) 01190 * In a DBAL this method should 1) look up all tables from the DBMS of 01191 * the _DEFAULT handler and then 2) add all tables *configured* to be managed by other handlers 01192 * Usage count/core: 2 01193 * 01194 * @return array Array with tablenames as key and arrays with status information as value 01195 */ 01196 function admin_get_tables() { 01197 $whichTables = array(); 01198 01199 $tables_result = mysql_query('SHOW TABLE STATUS FROM `' . TYPO3_db . '`', $this->link); 01200 if (!mysql_error()) { 01201 while ($theTable = mysql_fetch_assoc($tables_result)) { 01202 $whichTables[$theTable['Name']] = $theTable; 01203 } 01204 01205 $this->sql_free_result($tables_result); 01206 } 01207 01208 return $whichTables; 01209 } 01210 01211 /** 01212 * Returns information about each field in the $table (quering the DBMS) 01213 * In a DBAL this should look up the right handler for the table and return compatible information 01214 * This function is important not only for the Install Tool but probably for 01215 * DBALs as well since they might need to look up table specific information 01216 * in order to construct correct queries. In such cases this information should 01217 * probably be cached for quick delivery. 01218 * 01219 * @param string Table name 01220 * @return array Field information in an associative array with fieldname => field row 01221 */ 01222 function admin_get_fields($tableName) { 01223 $output = array(); 01224 01225 $columns_res = mysql_query('SHOW COLUMNS FROM `' . $tableName . '`', $this->link); 01226 while ($fieldRow = mysql_fetch_assoc($columns_res)) { 01227 $output[$fieldRow['Field']] = $fieldRow; 01228 } 01229 01230 $this->sql_free_result($columns_res); 01231 01232 return $output; 01233 } 01234 01235 /** 01236 * Returns information about each index key in the $table (quering the DBMS) 01237 * In a DBAL this should look up the right handler for the table and return compatible information 01238 * 01239 * @param string Table name 01240 * @return array Key information in a numeric array 01241 */ 01242 function admin_get_keys($tableName) { 01243 $output = array(); 01244 01245 $keyRes = mysql_query('SHOW KEYS FROM `' . $tableName . '`', $this->link); 01246 while ($keyRow = mysql_fetch_assoc($keyRes)) { 01247 $output[] = $keyRow; 01248 } 01249 01250 $this->sql_free_result($keyRes); 01251 01252 return $output; 01253 } 01254 01255 /** 01256 * Returns information about the character sets supported by the current DBM 01257 * This function is important not only for the Install Tool but probably for 01258 * DBALs as well since they might need to look up table specific information 01259 * in order to construct correct queries. In such cases this information should 01260 * probably be cached for quick delivery. 01261 * 01262 * This is used by the Install Tool to convert tables tables with non-UTF8 charsets 01263 * Use in Install Tool only! 01264 * 01265 * @return array Array with Charset as key and an array of "Charset", "Description", "Default collation", "Maxlen" as values 01266 */ 01267 function admin_get_charsets() { 01268 $output = array(); 01269 01270 $columns_res = mysql_query('SHOW CHARACTER SET', $this->link); 01271 if ($columns_res) { 01272 while (($row = mysql_fetch_assoc($columns_res))) { 01273 $output[$row['Charset']] = $row; 01274 } 01275 01276 $this->sql_free_result($columns_res); 01277 } 01278 01279 return $output; 01280 } 01281 01282 /** 01283 * mysql() wrapper function, used by the Install Tool and EM for all queries regarding management of the database! 01284 * Usage count/core: 10 01285 * 01286 * @param string Query to execute 01287 * @return pointer Result pointer 01288 */ 01289 function admin_query($query) { 01290 $res = mysql_query($query, $this->link); 01291 if ($this->debugOutput) { 01292 $this->debug('admin_query', $query); 01293 } 01294 return $res; 01295 } 01296 01297 01298 01299 01300 01301 01302 01303 01304 01305 01306 01307 01308 /****************************** 01309 * 01310 * Connecting service 01311 * 01312 ******************************/ 01313 01314 /** 01315 * Connects to database for TYPO3 sites: 01316 * 01317 * @param string $host 01318 * @param string $user 01319 * @param string $password 01320 * @param string $db 01321 * @return void 01322 */ 01323 function connectDB($host = TYPO3_db_host, $user = TYPO3_db_username, $password = TYPO3_db_password, $db = TYPO3_db) { 01324 if ($this->sql_pconnect($host, $user, $password)) { 01325 if (!$db) { 01326 throw new RuntimeException( 01327 'TYPO3 Fatal Error: No database selected!', 01328 1270853882 01329 ); 01330 } elseif (!$this->sql_select_db($db)) { 01331 throw new RuntimeException( 01332 'TYPO3 Fatal Error: Cannot connect to the current database, "' . $db . '"!', 01333 1270853883 01334 ); 01335 } 01336 } else { 01337 throw new RuntimeException( 01338 'TYPO3 Fatal Error: The current username, password or host was not accepted when the connection to the database was attempted to be established!', 01339 1270853884 01340 ); 01341 } 01342 } 01343 01344 /** 01345 * Checks if database is connected 01346 * 01347 * @return boolean 01348 */ 01349 public function isConnected() { 01350 return is_resource($this->link); 01351 } 01352 01353 01354 01355 /****************************** 01356 * 01357 * Debugging 01358 * 01359 ******************************/ 01360 01361 /** 01362 * Debug function: Outputs error if any 01363 * 01364 * @param string Function calling debug() 01365 * @param string Last query if not last built query 01366 * @return void 01367 */ 01368 function debug($func, $query='') { 01369 01370 $error = $this->sql_error(); 01371 if ($error) { 01372 debug( 01373 array( 01374 'caller' => 't3lib_DB::' . $func, 01375 'ERROR' => $error, 01376 'lastBuiltQuery' => ($query ? $query : $this->debug_lastBuiltQuery), 01377 'debug_backtrace' => t3lib_div::debug_trail(), 01378 ), 01379 $func, 01380 is_object($GLOBALS['error']) && @is_callable(array($GLOBALS['error'], 'debug')) ? '' : 'DB Error' 01381 ); 01382 } 01383 } 01384 01385 /** 01386 * Checks if recordset is valid and writes debugging inormation into devLog if not. 01387 * 01388 * @param resource $res Recordset 01389 * @return boolean <code>false</code> if recordset is not valid 01390 */ 01391 function debug_check_recordset($res) { 01392 if (!$res) { 01393 $trace = FALSE; 01394 $msg = 'Invalid database result resource detected'; 01395 $trace = debug_backtrace(); 01396 array_shift($trace); 01397 $cnt = count($trace); 01398 for ($i = 0; $i < $cnt; $i++) { 01399 // complete objects are too large for the log 01400 if (isset($trace['object'])) { 01401 unset($trace['object']); 01402 } 01403 } 01404 $msg .= ': function t3lib_DB->' . $trace[0]['function'] . ' called from file ' . 01405 substr($trace[0]['file'], strlen(PATH_site) + 2) . ' in line ' . 01406 $trace[0]['line']; 01407 t3lib_div::sysLog($msg.'. Use a devLog extension to get more details.', 'Core/t3lib_db', 3); 01408 // Send to devLog if enabled 01409 if (TYPO3_DLOG) { 01410 $debugLogData = array( 01411 'SQL Error' => $this->sql_error(), 01412 'Backtrace' => $trace, 01413 ); 01414 if ($this->debug_lastBuiltQuery) { 01415 $debugLogData = array('SQL Query' => $this->debug_lastBuiltQuery) + $debugLogData; 01416 } 01417 t3lib_div::devLog($msg . '.', 'Core/t3lib_db', 3, $debugLogData); 01418 } 01419 01420 return FALSE; 01421 } 01422 return TRUE; 01423 } 01424 01425 /** 01426 * Explain select queries 01427 * If $this->explainOutput is set, SELECT queries will be explained here. Only queries with more than one possible result row will be displayed. 01428 * The output is either printed as raw HTML output or embedded into the TS admin panel (checkbox must be enabled!) 01429 * 01430 * TODO: Feature is not DBAL-compliant 01431 * 01432 * @param string SQL query 01433 * @param string Table(s) from which to select. This is what comes right after "FROM ...". Required value. 01434 * @param integer Number of resulting rows 01435 * @return boolean True if explain was run, false otherwise 01436 */ 01437 protected function explain($query, $from_table, $row_count) { 01438 01439 if ((int)$this->explainOutput == 1 || ((int)$this->explainOutput == 2 && 01440 t3lib_div::cmpIP(t3lib_div::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'])) 01441 ) { 01442 // raw HTML output 01443 $explainMode = 1; 01444 } elseif ((int)$this->explainOutput == 3 && is_object($GLOBALS['TT'])) { 01445 // embed the output into the TS admin panel 01446 $explainMode = 2; 01447 } else { 01448 return false; 01449 } 01450 01451 $error = $this->sql_error(); 01452 $trail = t3lib_div::debug_trail(); 01453 01454 $explain_tables = array(); 01455 $explain_output = array(); 01456 $res = $this->sql_query('EXPLAIN ' . $query, $this->link); 01457 if (is_resource($res)) { 01458 while ($tempRow = $this->sql_fetch_assoc($res)) { 01459 $explain_output[] = $tempRow; 01460 $explain_tables[] = $tempRow['table']; 01461 } 01462 $this->sql_free_result($res); 01463 } 01464 01465 $indices_output = array(); 01466 // Notice: Rows are skipped if there is only one result, or if no conditions are set 01467 if ($explain_output[0]['rows'] > 1 || t3lib_div::inList('ALL', $explain_output[0]['type'])) { 01468 // only enable output if it's really useful 01469 $debug = true; 01470 01471 foreach ($explain_tables as $table) { 01472 $tableRes = $this->sql_query('SHOW TABLE STATUS LIKE \'' . $table . '\''); 01473 $isTable = $this->sql_num_rows($tableRes); 01474 if ($isTable) { 01475 $res = $this->sql_query('SHOW INDEX FROM ' . $table, $this->link); 01476 if (is_resource($res)) { 01477 while ($tempRow = $this->sql_fetch_assoc($res)) { 01478 $indices_output[] = $tempRow; 01479 } 01480 $this->sql_free_result($res); 01481 } 01482 } 01483 $this->sql_free_result($tableRes); 01484 } 01485 } else { 01486 $debug = false; 01487 } 01488 01489 if ($debug) { 01490 if ($explainMode) { 01491 $data = array(); 01492 $data['query'] = $query; 01493 $data['trail'] = $trail; 01494 $data['row_count'] = $row_count; 01495 01496 if ($error) { 01497 $data['error'] = $error; 01498 } 01499 if (count($explain_output)) { 01500 $data['explain'] = $explain_output; 01501 } 01502 if (count($indices_output)) { 01503 $data['indices'] = $indices_output; 01504 } 01505 01506 if ($explainMode == 1) { 01507 t3lib_div::debug($data, 'Tables: ' . $from_table, 'DB SQL EXPLAIN'); 01508 } elseif ($explainMode == 2) { 01509 $GLOBALS['TT']->setTSselectQuery($data); 01510 } 01511 } 01512 return true; 01513 } 01514 01515 return false; 01516 } 01517 01518 } 01519 01520 01521 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_db.php']) { 01522 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_db.php']); 01523 } 01524 01525 ?>
1.4.7