|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // $Id$ 00004 // 00005 // Definition of eZDB class 00006 // 00007 // Created on: <12-Feb-2002 15:41:03 bf> 00008 // 00009 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00010 // SOFTWARE NAME: eZ Publish 00011 // SOFTWARE RELEASE: 4.0.x 00012 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS 00013 // SOFTWARE LICENSE: GNU General Public License v2.0 00014 // NOTICE: > 00015 // This program is free software; you can redistribute it and/or 00016 // modify it under the terms of version 2.0 of the GNU General 00017 // Public License as published by the Free Software Foundation. 00018 // 00019 // This program is distributed in the hope that it will be useful, 00020 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00022 // GNU General Public License for more details. 00023 // 00024 // You should have received a copy of version 2.0 of the GNU General 00025 // Public License along with this program; if not, write to the Free 00026 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00027 // MA 02110-1301, USA. 00028 // 00029 // 00030 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00031 // 00032 00033 /*! \file ezdb.php 00034 Database abstraction layer. 00035 */ 00036 00037 /*! \defgroup eZDB Database abstraction layer */ 00038 00039 /*! 00040 \class eZDB ezdb.php 00041 \ingroup eZDB 00042 \brief The eZDB class provides database wrapper functions 00043 The eZ db library procides a database independent framework for 00044 SQL databases. The current supported databases are: PostgreSQL and 00045 MySQL. 00046 00047 eZ db is designed to be used with the following type subset of SQL: 00048 int, float, varchar and text. 00049 00050 To store date and time values int's are used. eZ locale is used to 00051 present the date and times on a localized format. That way we don't have 00052 to worry about the different date and time formats used in the different 00053 databases. 00054 00055 Auto incrementing numbers, sequences, are used to generate unique id's 00056 for a table row. This functionality is abstracted as it works different 00057 in the different databases. 00058 00059 Limit and offset functionality is also abstracted by the eZ db library. 00060 00061 eZ db is designed to use lowercase in all table/column names. This is 00062 done to prevent errors as the different databases handles this differently. 00063 Especially when returning the data as an associative array. 00064 00065 \code 00066 // include the library 00067 //include_once( 'lib/ezdb/classes/ezdb.php' ); 00068 00069 // Get the current database instance 00070 // will create a new database object and connect to the database backend 00071 // if there is already created an instance for this session the existing 00072 // object will be returned. 00073 // the settings for the database connections are set in site.ini 00074 $db = eZDB::instance(); 00075 00076 // Run a simple query 00077 $db->query( 'DELETE FROM sql_test' ); 00078 00079 // insert some data 00080 $str = $db->escapeString( "Testing escaping'\"" ); 00081 $db->query( "INSERT INTO sql_test ( name, description ) VALUES ( 'New test', '$str' )" ); 00082 00083 // Get the last serial value for the sql_test table 00084 $rowID = $db->lastSerialID( 'sql_test', 'id' ); 00085 00086 // fetch some data into an array of associative arrays 00087 $rows = $db->arrayQuery( 'SELECT * FROM sql_test' ); 00088 00089 foreach ( $rows as $row ) 00090 { 00091 print( $row['name'] ); 00092 } 00093 00094 // fetch some data with a limit 00095 // will return the 10 first rows in the result 00096 $ret = $db->arrayQuery( 'SELECT id, name, description, rownum FROM sql_test', 00097 array( 'offset' => 0, 'limit' => 10 ) ); 00098 00099 // check which implementation we're running 00100 print( $db->databaseName() ); 00101 00102 \endcode 00103 00104 \sa eZLocale eZINI 00105 */ 00106 00107 require_once( 'lib/ezutils/classes/ezdebug.php' ); 00108 00109 class eZDB 00110 { 00111 /*! 00112 Constructor. 00113 NOTE: Should not be used. 00114 */ 00115 private function __construct() 00116 { 00117 eZDebug::writeError( 'This class should not be instantiated', 'eZDB::eZDB' ); 00118 } 00119 00120 /*! 00121 \static 00122 Returns an instance of the database object. 00123 */ 00124 static function hasInstance() 00125 { 00126 return isset( $GLOBALS['eZDBGlobalInstance'] ) && $GLOBALS['eZDBGlobalInstance'] instanceof eZDBInterface; 00127 } 00128 00129 /*! 00130 \static 00131 Sets the global database instance to \a $instance. 00132 */ 00133 static function setInstance( $instance ) 00134 { 00135 $GLOBALS['eZDBGlobalInstance'] = $instance; 00136 } 00137 00138 /*! 00139 \static 00140 Returns an instance of the database object. 00141 If you want to change the current database values you should set \a $forceNewInstance to \c true to force a new instance. 00142 */ 00143 static function instance( $databaseImplementation = false, $databaseParameters = false, $forceNewInstance = false ) 00144 { 00145 $impl =& $GLOBALS['eZDBGlobalInstance']; 00146 00147 $fetchInstance = false; 00148 if ( !( $impl instanceof eZDBInterface ) ) 00149 $fetchInstance = true; 00150 00151 if ( $forceNewInstance ) 00152 { 00153 unset($impl); 00154 $impl = false; 00155 $fetchInstance = true; 00156 } 00157 00158 $useDefaults = true; 00159 if ( is_array( $databaseParameters ) and isset( $databaseParameters['use_defaults'] ) ) 00160 $useDefaults = $databaseParameters['use_defaults']; 00161 00162 if ( $fetchInstance ) 00163 { 00164 //include_once( 'lib/ezutils/classes/ezini.php' ); 00165 $ini = eZINI::instance(); 00166 if ( $databaseImplementation === false and $useDefaults ) 00167 $databaseImplementation = $ini->variable( 'DatabaseSettings', 'DatabaseImplementation' ); 00168 00169 $server = $user = $pwd = $db = $usePersistentConnection = $port = false; 00170 if ( $useDefaults ) 00171 list( $server, $port, $user, $pwd, $db, $usePersistentConnection ) = 00172 $ini->variableMulti( 'DatabaseSettings', array( 'Server', 'Port', 'User', 'Password', 'Database', 'UsePersistentConnection', ) ); 00173 00174 $socketPath = false; 00175 if ( $useDefaults ) 00176 { 00177 $socket = $ini->variable( 'DatabaseSettings', 'Socket' ); 00178 if ( trim( $socket != "" ) and $socket != "disabled" ) 00179 { 00180 $socketPath = $socket; 00181 } 00182 } 00183 00184 // Check slave servers 00185 $slaveServer = null; 00186 $slaveServerPort = null; 00187 $slaveServerUser = null; 00188 $slaveServerPassword = null; 00189 $slaveServerDatabase = null; 00190 $useSlave = $ini->variable( 'DatabaseSettings', 'UseSlaveServer' ); 00191 if ( $useSlave == "enabled" ) 00192 { 00193 $slaveServers = $ini->variable( 'DatabaseSettings', 'SlaveServerArray' ); 00194 $slaveServerPorts = $ini->variable( 'DatabaseSettings', 'SlaveServerPort' ); 00195 $slaveServerUsers = $ini->variable( 'DatabaseSettings', 'SlaverServerUser' ); 00196 $slaveServerPasswords = $ini->variable( 'DatabaseSettings', 'SlaverServerPassword' ); 00197 $slaveServerDatabases = $ini->variable( 'DatabaseSettings', 'SlaverServerDatabase' ); 00198 $numberServers = count( $slaveServers ); 00199 if ( $numberServers > 1 ) 00200 { 00201 $index = rand( 1, $numberServers ) - 1; 00202 } 00203 else 00204 $index = 0; 00205 $slaveServer = $slaveServers[$index]; 00206 $slaveServerPort = $slaveServerPorts[$index]; 00207 $slaveServerUser = $slaveServerUsers[$index]; 00208 $slaveServerPassword = $slaveServerPasswords[$index]; 00209 $slaveServerDatabase = $slaveServerDatabases[$index]; 00210 } 00211 00212 list( $charset, $retries ) = 00213 $ini->variableMulti( 'DatabaseSettings', array( 'Charset', 'ConnectRetries' ) ); 00214 00215 $isInternalCharset = false; 00216 if ( trim( $charset ) == '' ) 00217 { 00218 $charset = eZTextCodec::internalCharset(); 00219 $isInternalCharset = true; 00220 } 00221 $builtinEncoding = ( $ini->variable( 'DatabaseSettings', 'UseBuiltinEncoding' ) == 'true' ); 00222 00223 $extraPluginPathArray = $ini->variableArray( 'DatabaseSettings', 'DatabasePluginPath' ); 00224 $pluginPathArray = array_merge( array( 'lib/ezdb/classes/' ), 00225 $extraPluginPathArray ); 00226 $impl = null; 00227 00228 $useSlaveServer = false; 00229 if ( $useSlave == "enabled" ) 00230 $useSlaveServer = true; 00231 $defaultDatabaseParameters = array( 'server' => $server, 00232 'port' => $port, 00233 'user' => $user, 00234 'password' => $pwd, 00235 'database' => $db, 00236 'use_slave_server' => $useSlaveServer, 00237 'slave_server' => $slaveServer, 00238 'slave_port' => $slaveServerPort, 00239 'slave_user' => $slaveServerUser, 00240 'slave_password' => $slaveServerPassword, 00241 'slave_database' => $slaveServerDatabase, 00242 'charset' => $charset, 00243 'is_internal_charset' => $isInternalCharset, 00244 'socket' => $socketPath, 00245 'builtin_encoding' => $builtinEncoding, 00246 'connect_retries' => $retries, 00247 'use_persistent_connection' => $usePersistentConnection, 00248 'show_errors' => true ); 00249 /* This looks funny, but is needed to fix a crash in PHP */ 00250 $b = $databaseParameters; 00251 $databaseParameters = $defaultDatabaseParameters; 00252 if ( isset( $b['server'] ) ) 00253 $databaseParameters['server'] = $b['server']; 00254 if ( isset( $b['port'] ) ) 00255 $databaseParameters['port'] = $b['port']; 00256 if ( isset( $b['user'] ) ) 00257 $databaseParameters['user'] = $b['user']; 00258 if ( isset( $b['password'] ) ) 00259 $databaseParameters['password'] = $b['password']; 00260 if ( isset( $b['database'] ) ) 00261 $databaseParameters['database'] = $b['database']; 00262 if ( isset( $b['use_slave_server'] ) ) 00263 $databaseParameters['use_slave_server'] = $b['use_slave_server']; 00264 if ( isset( $b['slave_server'] ) ) 00265 $databaseParameters['slave_server'] = $b['slave_server']; 00266 if ( isset( $b['slave_port'] ) ) 00267 $databaseParameters['slave_port'] = $b['slave_port']; 00268 if ( isset( $b['slave_user'] ) ) 00269 $databaseParameters['slave_user'] = $b['slave_user']; 00270 if ( isset( $b['slave_password'] ) ) 00271 $databaseParameters['slave_password'] = $b['slave_password']; 00272 if ( isset( $b['slave_database'] ) ) 00273 $databaseParameters['slave_database'] = $b['slave_database']; 00274 if ( isset( $b['charset'] ) ) 00275 { 00276 $databaseParameters['charset'] = $b['charset']; 00277 $databaseParameters['is_internal_charset'] = false; 00278 } 00279 if ( isset( $b['socket'] ) ) 00280 $databaseParameters['socket'] = $b['socket']; 00281 if ( isset( $b['builtin_encoding'] ) ) 00282 $databaseParameters['builtin_encoding'] = $b['builtin_encoding']; 00283 if ( isset( $b['connect_retries'] ) ) 00284 $databaseParameters['connect_retries'] = $b['connect_retries']; 00285 if ( isset( $b['use_persistent_connection'] ) ) 00286 $databaseParameters['use_persistent_connection'] = $b['use_persistent_connection']; 00287 if ( isset( $b['show_errors'] ) ) 00288 $databaseParameters['show_errors'] = $b['show_errors']; 00289 00290 // Search for the db interface implementations in active extensions directories. 00291 //include_once( 'lib/ezutils/classes/ezextension.php' ); 00292 $baseDirectory = eZExtension::baseDirectory(); 00293 $extensionDirectories = eZExtension::activeExtensions(); 00294 $extensionDirectories = array_unique( $extensionDirectories ); 00295 $repositoryDirectories = array(); 00296 foreach ( $extensionDirectories as $extDir ) 00297 { 00298 $newRepositoryDir = "$baseDirectory/$extDir/ezdb/dbms-drivers/"; 00299 if ( file_exists( $newRepositoryDir ) ) 00300 $repositoryDirectories[] = $newRepositoryDir; 00301 } 00302 $repositoryDirectories = array_merge( $repositoryDirectories, $pluginPathArray ); 00303 00304 foreach( $repositoryDirectories as $repositoryDir ) 00305 { 00306 // If we have an alias get the real name 00307 $aliasList = $ini->variable( 'DatabaseSettings', 'ImplementationAlias' ); 00308 if ( isset( $aliasList[$databaseImplementation] ) ) 00309 { 00310 $databaseImplementation = $aliasList[$databaseImplementation]; 00311 } 00312 00313 $dbFile = $repositoryDir . $databaseImplementation . 'db.php'; 00314 if ( file_exists( $dbFile ) ) 00315 { 00316 include_once( $dbFile ); 00317 $className = $databaseImplementation . 'db'; 00318 $impl = new $className( $databaseParameters ); 00319 break; 00320 } 00321 } 00322 if ( $impl === null ) 00323 { 00324 //include_once( 'lib/ezdb/classes/eznulldb.php' ); 00325 $impl = new eZNullDB( $databaseParameters ); 00326 $impl->ErrorMessage = "No database handler was found for '$databaseImplementation'"; 00327 $impl->ErrorNumber = -1; 00328 if ( $databaseParameters['show_errors'] ) 00329 { 00330 eZDebug::writeError( 'Database implementation not supported: ' . $databaseImplementation, 'eZDB::instance' ); 00331 } 00332 } 00333 00334 } 00335 return $impl; 00336 } 00337 00338 /*! 00339 Checks transaction counter 00340 If the current transaction counter is 1 or higher 00341 means 1 or more transactions are running and a negative value 00342 means something is wrong. 00343 Prints the error. 00344 */ 00345 static function checkTransactionCounter() 00346 { 00347 $result = true; 00348 //include_once( 'lib/ezutils/classes/ezini.php' ); 00349 $ini = eZINI::instance(); 00350 $checkValidity = ( $ini->variable( "SiteAccessSettings", "CheckValidity" ) == "true" ); 00351 if ( $checkValidity ) 00352 return $result; 00353 00354 $db = eZDB::instance(); 00355 00356 if ( $db->transactionCounter() > 0 ) 00357 { 00358 $result = array(); 00359 $result['error'] = "Internal transaction counter mismatch : " . $db->transactionCounter() . ". Should be zero."; 00360 eZDebug::writeError( $result['error'] ); 00361 $stack = $db->generateFailedTransactionStack(); 00362 if ( $stack !== false ) 00363 { 00364 eZDebug::writeError( $stack, 'Transaction stack' ); 00365 } 00366 //include_once( 'lib/ezutils/classes/ezini.php' ); 00367 $ini = eZINI::instance(); 00368 // In debug mode the transaction will be invalidated causing the top-level commit 00369 // to issue an error. 00370 if ( $ini->variable( "DatabaseSettings", "DebugTransactions" ) == "enabled" ) 00371 { 00372 $db->invalidateTransaction(); 00373 $db->reportError(); 00374 } 00375 else 00376 { 00377 while ( $db->transactionCounter() > 0 ) 00378 { 00379 $db->commit(); 00380 } 00381 } 00382 } 00383 00384 return $result; 00385 } 00386 00387 } 00388 00389 ?>