Database.class.php (6621B)
1 <?php 2 // OpenRat Content Management System 3 // Copyright (C) 2002-2006 Jan Dankert, jandankert@jandankert.de 4 // 5 // This program is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU General Public License 7 // as published by the Free Software Foundation; either version 2 8 // of the License, or (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 namespace database; 20 use cms\base\Configuration as C; 21 use database\driver\PDODriver; 22 use logger\Logger; 23 use util\exception\DatabaseException; 24 25 /** 26 * Darstellung einer Datenbank-Verbindung. 27 * 28 * Fuer die echten DB-Aufrufe werden die entsprechenden 29 * Methoden des passenden Clients aufgerufen. 30 * 31 * Diese Klasse stammt urspruenglich aus dem PHP-Pear-DB-Projekt, wurde hier aber intensiv veraendert. 32 * 33 * @author Jan Dankert 34 * @package openrat.database 35 */ 36 class Database 37 { 38 /** 39 * Datenbank-Id. 40 * 41 * @var String 42 */ 43 public $id; 44 45 /** 46 * Konfiguration der Datenbank-Verbindung 47 * 48 * @var array 49 */ 50 public $conf; 51 52 /** 53 * Client. 54 * 55 * @var PDODriver 56 */ 57 private $client; 58 59 /** 60 * Schalter, ob eine Transaktion begonnen wurde. 61 * @var boolean 62 */ 63 private $transactionInProgress = false; 64 65 66 /** 67 * Default configuration. 68 * @var array 69 */ 70 private static $DEFAULT_CONFIG = [ 71 // we need at least 1 prefix or suffix, because the raw table names are partially keywords in ANSI SQL. 72 'prefix' => 'cms_', 73 'suffix' => '', 74 'enabled' => true, 75 'name' => '', 76 'description' => '', 77 'type' => 'pdo', // we are only supporting PDO 78 'driver' => 'mysql', 79 'dsn' => '', // if no DSN is given, it will be created from user,host,port. 80 'user' => '', 81 'password' => '', 82 'host' => 'localhost', 83 'port' => 0, 84 'database' => '', 85 'base64' => false, // should BLOBs be converted to Base64? 86 'persistent' => true, // persistent connections are faster 87 'charset' => 'UTF-8', // should be UTF-8 88 'connection_sql' => '', // Startup-SQL 89 'cmd' => '', // maybe you want to start a SSH tunnel here 90 'prepare' => true, // using prepared statements is a good idea 91 'transaction' => true, // using transaction is a good idea 92 'update' => 93 [ 94 ], 95 'auto_update' => true, // auto update should always be enabled 96 ]; 97 98 99 /** 100 * Kontruktor. 101 * Erwartet die Datenbank-Konfiguration als Parameter. 102 * 103 * @param array Konfiguration der Verbindung 104 */ 105 public function __construct( $dbconf ) 106 { 107 $this->conf = array_merge( 108 Database::$DEFAULT_CONFIG, // internal defaults 109 C::subset('database-default')->subset('defaults')->getConfig(), // defaults from config 110 $dbconf // per-connection DB configuration 111 ); 112 113 $this->connect(); 114 } 115 116 117 /** 118 * Verbindung zur Datenbank aufbauen. 119 * 120 * @return bool Status 121 */ 122 public function connect() 123 { 124 // Ausfuehren des Systemkommandos vor Verbindungsaufbau 125 if ( $this->conf['cmd'] ) 126 $this->executeSystemCommand( $this->conf['cmd'] ); 127 128 // Client instanziieren 129 $this->client = new PDODriver(); 130 131 // Verbindung aufbauen 132 $this->client->connect( $this->conf ); 133 134 // SQL nach Verbindungsaufbau ausfuehren. 135 if ( ! empty($this->conf['connection_sql']) ) 136 { 137 $cmd = $this->conf['connection_sql']; 138 139 $stmt = $this->sql($cmd); 140 141 $ok = $stmt->execute(); 142 143 if ( ! $ok ) 144 { 145 throw new DatabaseException( "Could not execute connection-query '".$cmd."'"); 146 } 147 } 148 149 // Setting isolation level to "read committed". 150 // if another session is committing data, we want to read that immediatly 151 if ( $this->conf['persistent']) 152 { 153 // $sql = $this->sql('ROLLBACK'); 154 // $sql->execute(); 155 // $sql = $this->sql('SET TRANSACTION ISOLATION LEVEL READ COMMITTED'); 156 // $sql->execute(); 157 } 158 159 160 Logger::debug('Database connection established'); 161 } 162 163 /** 164 * Startet eine Transaktion. 165 */ 166 public function start() 167 { 168 Logger::debug("Starting database transaction!"); 169 $this->transactionInProgress = true; 170 $this->client->start(); 171 } 172 173 174 /** 175 * Beendet und bestaetigt eine Transaktion. 176 * Falls der Schalter 'transaction' nicht gesetzt ist, passiert nichts. 177 */ 178 public function commit() 179 { 180 if ( $this->transactionInProgress ) 181 { 182 Logger::debug("Committing database transaction!"); 183 $this->client->commit(); 184 $this->transactionInProgress = false; 185 } else { 186 Logger::warn("No Transaction in progress, ignoring commit request."); 187 } 188 } 189 190 191 192 /** 193 * Setzt eine Transaktion zurueck. 194 * Falls der Schalter 'transaction' nicht gesetzt ist, passiert nichts. 195 */ 196 public function rollback() 197 { 198 if ( $this->transactionInProgress ) 199 { 200 Logger::debug("Rolling back database transaction!"); 201 $this->client->rollback(); 202 $this->transactionInProgress = false; 203 } else { 204 Logger::warn("No Transaction in progress, ignoring rollback request."); 205 } 206 } 207 208 209 public function disconnect() 210 { 211 $this->client->disconnect(); 212 $this->client = null; // clear references to the client 213 } 214 /** 215 * @param $sql string das SQL 216 * @return Statement 217 */ 218 public function sql($sql ) 219 { 220 return new Statement( $sql,$this->client,$this->conf); 221 } 222 223 224 private function executeSystemCommand( $cmd ) 225 { 226 $ausgabe = array(); 227 $rc = false; 228 229 Logger::debug("Database command executing: " . $cmd ); 230 exec($cmd, $ausgabe, $rc); 231 232 foreach ($ausgabe as $zeile) 233 Logger::debug("Database command output: " . $zeile); 234 235 if ($rc != 0) { 236 throw new DatabaseException('Command failed: ' . implode("", $ausgabe)); 237 } 238 } 239 240 241 /** 242 * database label. 243 * 244 * @return string 245 */ 246 public function getLabel() { 247 return array_values(array_filter( array( 248 @$this->conf['description'], 249 @$this->conf['name' ], 250 $this->id, 251 @$this->conf['host' ], 252 @$this->conf['driver'], 253 @$this->conf['type' ], 254 )))[0]; 255 } 256 }