openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 853f8211ad64ffc75a189266dedf23a89b067719
parent 0b8f700c5400321393293856c86ef21658a98e25
Author: Jan Dankert <devnull@localhost>
Date:   Sun,  3 Dec 2017 03:11:38 +0100

Refactoring: Datenbank-Funktionen in ein eigenes "Modul" ausgelagert.

Diffstat:
db/Database.class.php | 209-------------------------------------------------------------------------------
db/DbVersion.class.php | 316-------------------------------------------------------------------------------
db/Sql.class.php | 116-------------------------------------------------------------------------------
db/Statement.class.php | 327-------------------------------------------------------------------------------
db/driver/pdo.class.php | 222-------------------------------------------------------------------------------
db/include.inc.php | 5-----
dispatcher.php | 2+-
modules/database/Database.class.php | 209+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
modules/database/DbVersion.class.php | 316+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
modules/database/Sql.class.php | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
modules/database/Statement.class.php | 327+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
modules/database/driver/pdo.class.php | 222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
modules/database/require.php | 11+++++++++++
13 files changed, 1202 insertions(+), 1196 deletions(-)

diff --git a/db/Database.class.php b/db/Database.class.php @@ -1,208 +0,0 @@ -<?php -// OpenRat Content Management System -// Copyright (C) 2002-2006 Jan Dankert, jandankert@jandankert.de -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -/** - * Darstellung einer Datenbank-Verbindung. - * - * Fuer die echten DB-Aufrufe werden die entsprechenden - * Methoden des passenden Clients aufgerufen. - * - * Diese Klasse stammt urspruenglich aus dem PHP-Pear-DB-Projekt, wurde hier aber intensiv veraendert. - * - * @author Jan Dankert - * @package openrat.database - */ -class DB -{ - /** - * Datenbank-Id. - * - * @var String - */ - var $id; - - /** - * Konfiguration der Datenbank-Verbindung - * - * @var Array - */ - var $conf; - - /** - * Kennzeichen, ob die Datenbank verf�gbar ist. - * - * @var Boolean - */ - var $available; - - /** - * Enth�lt eine Fehlermeldung (sofern verf�gbar). - * - * @var String - */ - var $error; - - /** - * Client. - * Enth�lt ein Objekt der Klasse db_<type>. - * - * @var Object - */ - var $client; - - /** - * Schalter, ob eine Transaktion begonnen wurde. - * @var boolean - */ - var $transactionInProgress = false; - - - /** - * Kontruktor. - * Erwartet die Datenbank-Konfiguration als Parameter. - * - * @param Array Konfiguration der Verbindung - * @param boolean admin Wenn es eine Admin-DB-Verbindung werden soll, die auch DDL ausfuehren darf - */ - public function DB( $dbconf,$admin=false ) - { - global $conf; - - $this->conf = $dbconf + $conf['database-default']['defaults']; // linksstehender Operator hat Priorität! - - if ( $admin ) - { - // Bevorzugung der Unter-Konfiguration 'update' - if ( isset($this->conf['update']) ) - $this->conf = $this->conf['update'] + $this->conf; // linksstehender Operator hat Priorität! - } - - $this->connect(); - } - - - /** - * Verbindung zur Datenbank aufbauen. - * - * @return Status - */ - public function connect() - { - // Ausfuehren des Systemkommandos vor Verbindungsaufbau - if ( !empty($this->conf['cmd'])) - { - $ausgabe = array(); - $rc = false; - - Logger::debug("Database command executing: ".$this->conf['cmd']); - exec( $this->conf['cmd'],$ausgabe,$rc ); - - foreach( $ausgabe as $zeile ) - Logger::debug("Database command output: ".$zeile); - - if ( $rc != 0 ) - { - throw new OpenRatException( 'ERROR_DATABASE_CONNECTION','Command failed: '.implode("",$ausgabe) ); - } - } - - $type = $this->conf['type']; - $classname = 'db_'.$type; - - if ( ! class_exists($classname) ) - { - $this->available = false; - throw new OpenRatException( 'ERROR_DATABASE_CONNECTION','Database type "'.$type.'" is not available'); - } - - // Client instanziieren - $this->client = new $classname; - - - $this->client->connect( $this->conf ); - - // SQL nach Verbindungsaufbau ausfuehren. - if ( ! empty($this->conf['connection_sql']) ) - { - $cmd = $this->conf['connection_sql']; - - $sql = $this->sql($cmd); - - $ok = $sql->execute(); - - if ( ! $ok ) - { - throw new OpenRatException( 'ERROR_DATABASE_CONNECTION',"Could not execute connection-query '".$cmd."'"); - } - } - - Logger::debug('database connection established'); - - $this->available = true; - return true; - } - - /** - * Startet eine Transaktion. - * Falls der Schalter 'transaction' nicht gesetzt ist, passiert nichts. - */ - public function start() - { - $this->transactionInProgress = true; - $this->client->start(); - } - - - /** - * Beendet und bestaetigt eine Transaktion. - * Falls der Schalter 'transaction' nicht gesetzt ist, passiert nichts. - */ - public function commit() - { - if ( $this->transactionInProgress ) - { - $this->client->commit(); - $this->transactionInProgress = false; - } - } - - - - /** - * Setzt eine Transaktion zurueck. - * Falls der Schalter 'transaction' nicht gesetzt ist, passiert nichts. - */ - public function rollback() - { - if ( $this->transactionInProgress ) - { - $this->client->rollback(); - $this->transactionInProgress = false; - } - } - - public function sql( $sql ) - { - return new Statement( $sql,$this->client,$this->conf); - } - -} - - -?>- \ No newline at end of file diff --git a/db/DbVersion.class.php b/db/DbVersion.class.php @@ -1,315 +0,0 @@ -<?php - -define('OR_DB_INDEX_PREFIX' ,'IX'); -define('OR_DB_CONSTRAINT_PREFIX','FK'); - -abstract class DbVersion -{ - private $db; - private $tablePrefix; - private $tableSuffix; - private $dbmsType; - - function DbVersion( $db ) - { - $this->db = $db; - - switch( $db->conf['type'] ) - { - case 'mysql': - case 'mysqli': - $this->dbmsType = 'mysql'; - break; - case 'postgresql': - $this->dbmsType = 'postgresql'; - break; - case 'sqlite': - case 'sqlite3': - $this->dbmsType = 'sqlite'; - break; - case 'pdo': - $dsnParts = explode(':',$db->conf['dsn']); - switch( $dsnParts[0] ) - { - case 'mysql': - $this->dbmsType = 'mysql'; - break; - case 'pgsql': - $this->dbmsType = 'postgresql'; - break; - case 'sqlite': - $this->dbmsType = 'sqlite'; - break; - default: - Http::serverError('Datebase Configuration Error','Unknown DBMS in PDO-DSN: '.$dsnParts[0]); - } - break; - default: - Http::serverError('Datebase Configuration Error','Unknown DBMS type: '.$db->conf['type'] ); - } - - $this->tablePrefix = $db->conf['prefix']; - $this->tableSuffix = $db->conf['suffix']; - } - - // Muss überschrieben werden! - abstract function update(); - - - - - - - - - protected function getTableName( $name ) - { - return $this->tablePrefix.$name.$this->tableSuffix; - } - - - /** - * Erzeugt eine neue Tabelle. - * Die neue Tabelle enthält bereits eine Spalte "id" (da eine leere Tabelle i.d.R. nicht zulässig ist). - */ - function addTable( $tableName ) - { - $tableName = $this->getTableName($tableName); - - $table_opts = $this->dbmsType=='mysql'?' ENGINE=InnoDB CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci':''; - - $ddl = $this->db->sql('CREATE TABLE '.$tableName.'(id INTEGER)'.$table_opts.';'); - // The syntax 'TYPE = InnoDB' was deprecated in MySQL 5.0 and was removed in MySQL 5.1 and later versions. - - $ddl->query(); - } - - - # Creating a new column - # param 1: column name - # param 2: type (available are: INT,VARCHAR,TEXT,BLOB) - # param 3: size (number value) - # param 4: default (number value) - # param 5: nullable (available are: J,N) - function addColumn($tableName,$columnName,$type,$size,$default,$nullable) - { - $table = $this->getTableName($tableName); - - $type = strtoupper($type); - switch( $type ) - { - case 'INT': - switch( $this->dbmsType ) - { - case 'mysql': - if ( $size == 1 ) - $dbmsInternalType = 'TINYINT'; - else - $dbmsInternalType = 'INT'; - break; - - case 'oracle': - $dbmsInternalType = 'NUMBER'; - break; - - default: - $dbmsInternalType = 'INTEGER'; - - } - break; - - case 'VARCHAR': - switch( $this->dbmsType ) - { - default: - $dbmsInternalType = 'VARCHAR'; - - } - break; - - case 'TEXT': - switch( $this->dbmsType ) - { - case 'mysql': - $dbmsInternalType = 'MEDIUMTEXT'; - break; - - case 'oracle': - $dbmsInternalType = 'CLOB'; - break; - - default: - $dbmsInternalType = 'TEXT'; - - } - break; - - case 'BLOB': - switch( $this->dbmsType ) - { - case 'mysql': - $dbmsInternalType = 'MEDIUMBLOB'; - break; - - case 'oracle': - $dbmsInternalType = 'CLOB'; - break; - - case 'postgresql': - $dbmsInternalType = 'TEXT'; - break; - - case 'sqlite': - $dbmsInternalType = 'TEXT'; - break; - - default: - $dbmsInternalType = 'BLOB'; - - } - break; - default: - Http::serverError('Datebase Configuration Error','Unknown Column type: '.$type ); - } - - if ( $this->dbmsType == 'oracle') - { - // TEXT-columns should be nullable in Oracle, because empty strings are treated as NULL - if ( $type=='VARCHAR' || $type=='TEXT') - $nullable = true; - - } - - $ddl = $this->db->sql('ALTER TABLE '.$table. - ' ADD COLUMN '.$columnName.' '.$dbmsInternalType.($size!=null?'('.$size.')':''). - ($default!==null?' DEFAULT '.(is_string($default)?"'":'').$default.(is_string($default)?"'":''):''). - ' '.($nullable?'NULL':'NOT NULL').';' - ); - $ddl->query(); - - } - - - - function addPrimaryKey( $tableName,$columnNames) - { - $table = $this->getTableName($tableName); - - if ( !is_array($columnNames) ) - $columnNames = explode(',',$columnNames); - - $ddl = $this->db->sql('ALTER TABLE '.$table.' ADD PRIMARY KEY ('.implode(',',$columnNames).');'); - $ddl->query(); - - } - - - - # Creating a unique key - # param 1: name of index column. Seperate multiple columns with ',' - function addIndex($tableName,$columnNames,$unique=false) - { - $table = $this->getTableName($tableName); - - if ( !is_array($columnNames) ) - $columnNames = explode(',',$columnNames); - - $indexName = $this->tablePrefix.OR_DB_INDEX_PREFIX.'_'.$tableName.'_'.implode('_',$columnNames).$this->tableSuffix; - -// if [ "$type" == "oracle" ]; then -// cnt=$(($cnt+1)) -// echo "CREATE UNIQUE INDEX ${prefix}uidx_${cnt}" >> $outfile -// else - - $ddl = $this->db->sql('CREATE '.($unique?'UNIQUE ':'').'INDEX '.$indexName.' ON '.$table.' ('.implode(',',$columnNames).');'); - $ddl->query(); - - } - - - /** - * Creating a unique key. - * param 1: name of index column. Seperate multiple columns with ',' - * - */ - function addUniqueIndex($tableName,$columnNames) - { - $this->addIndex( $tableName,$columnNames,true ); - } - - - # Creating a foreign key - # param 1: column name - # param 2: target table name - # param 3: target column name - function addConstraint($tableName,$columnName,$targetTableName,$targetColumnName) - { - $table = $this->getTableName($tableName); - $targetTable = $this->getTableName($targetTableName); - - $constraintName = $this->tablePrefix.OR_DB_CONSTRAINT_PREFIX.'_'.$tableName.$this->tableSuffix.'_'.$columnName; - - // Oracle doesn't support "ON DELETE RESTRICT"-Statements, but its the default. - - $ddl = $this->db->sql('ALTER TABLE '.$table.' ADD CONSTRAINT '.$constraintName.' FOREIGN KEY ('.$columnName.') REFERENCES '.$targetTable.' ('.$targetColumnName.') ON DELETE RESTRICT ON UPDATE RESTRICT;'); - $ddl->query(); - } - - - - function dropTable( $tableName) - { - $table = $this->getTableName($tableName); - - $ddl = $this->db->sql('DROP TABLE '.$table.';' ); - $ddl->query(); - } - - function dropColumn( $tableName,$columnName ) - { - $table = $this->getTableName($tableName); - - $ddl = $this->db->sql('ALTER TABLE '.$table.' DROP COLUMN '.$columnName.';'); - $ddl->query(); - - - } - - function dropIndex( $indexName,$unique=false) - { - $ddl = $this->db->sql('DROP'.($unique?' UNIQUE':'').' INDEX '.$indexName.';' ); - $ddl->query(); - } - - function dropUniqueIndex( $indexName) - { - $this->dropIndex( $indexName,true ); - } - - function dropPrimaryKey( $tableName,$columnNames ) - { - $table = $this->getTableName($tableName); - - if ( !is_array($columnNames) ) - $columnNames = explode(',',$columnNames); - - $ddl = $this->db->sql('ALTER TABLE '.$table.' DROP PRIMARY KEY('.implode(',',$columnNames).')'); - $ddl->query(); - } - - - function dropConstraint( $constraintName) - { - $ddl = $this->db->sql('DROP CONSTRAINT '.$constraintName.';' ); - $ddl->query(); - } - - - function getDb() - { - return $this->db; - } - -} - -?>- \ No newline at end of file diff --git a/db/Sql.class.php b/db/Sql.class.php @@ -1,115 +0,0 @@ -<?php -// OpenRat Content Management System -// Copyright (C) 2002-2006 Jan Dankert, jandankert@jandankert.de -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - - -/** - * SQL-Anweisung.<br> - * <br> - * Darstellen eines SQL-Statements incl. Methoden zum Fuellen von - * Platzhaltern im SQL-Befehl.<br> - * <br> - * Beispiel<br> - * <pre> - * // Neues Objekt erzeugen mit SQL-Anweisung - * $sql = $db->sql('SELECT * FROM xy WHERE id={uid} AND name={name}'); - * - * // Parameter f�llen - * $sql->setInt ('uid' ,1 ); - * $sql->setString('name','peter'); - * - * // Fertige SQL-Anweisung verwenden - * $xy->execute( $sql->query ); - * </pre> - * <br> - * Ziele dieser Klasse sind:<br> - * - Schreiben einfacher SQL-Anweisungen ohne Stringverarbeitung<br> - * - Verhindern von SQL-Injection.<br> - * <br> - * - * @author Jan Dankert, $Author$ - * @version $Revision$ - * @package openrat.services - */ - -class Sql -{ - /** - * SQL-Anweisung. - */ - var $query; - - /** - * Ein 1-dimensionales Array mit den Positionen der Parameter.<br> - * <br> - * Beispiel:<br> - * <pre> - * - * Array - * ( - * [lid] => 16 - * [oid] => 24 - * ) - * </pre> - */ - var $param = array(); - - - /** - * Erzeugt ein SQL-Objekt und analysiert die SQL-Anfrage. - */ - function Sql( $query = '' ) - { - $this->parseSourceQuery( $query ); - } - - - /** - * Die SQL-Anfrage wird auf Parameter untersucht. - */ - function parseSourceQuery( $query ) - { - Logger::debug( 'SQL-query: '.$query); - - while( true ) // Schleife wird solange durchlaufen, solange Parameter gefunden werden. - { - $posKlLinks = strpos($query,'{'); - $posKlRechts = strpos($query,'}'); - - if ( $posKlLinks === false || $posKlRechts === false ) - break; // Schleife abbrechen, wenn kein Parameter mehr gefunden wird. - - $nameParam = substr($query,$posKlLinks+1,$posKlRechts-$posKlLinks-1); // Name Parameter - - if ( isset($this->param[$nameParam ])) - throw new RuntimeException( 'Parameter '.$nameParam.' in Query mehrfach vorhanden.' ); - - $this->param[$nameParam] = $posKlLinks; - - $query = substr($query,0,$posKlLinks).substr($query,$posKlRechts+1); - } - - $this->query = $query; - - } - - -} - - -?>- \ No newline at end of file diff --git a/db/Statement.class.php b/db/Statement.class.php @@ -1,326 +0,0 @@ -<?php -// OpenRat Content Management System -// Copyright (C) 2002-2006 Jan Dankert, jandankert@jandankert.de -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -/** - * Darstellung einer Datenbank-Abfrage. - * - * @author Jan Dankert - * @package openrat.database - */ -class Statement -{ - - /** - * SQL-Objekt. - * - * @var SQL - */ - var $sql; - - /** - * Client. - * Enth�lt ein Objekt der Klasse db_<type>. - * - * @var Object - */ - var $client; - - - /** - * Datenbank-Konfiguration - * @var Array - */ - var $conf; - - /** - * Kontruktor. - * Erwartet die Datenbank-Konfiguration als Parameter. - * - * @param Array Konfiguration der Verbindung - * @return Status 'true' wenn Verbindung erfolgreich aufgebaut. - */ - public function Statement( $sql, $client,$conf ) - { - // Tabellen-Praefixe ergaenzen. - $this->conf = $conf; - $this->client = $client; - - $sql = str_replace('{{',$conf['prefix'],$sql); - $sql = str_replace('}}',$conf['suffix'],$sql); - - $this->sql = new Sql( $sql ); - - // Vorbereitete Datenbankabfrage ("Prepared Statement") - $this->client->clear(); - - // Statement an die Datenbank schicken - $this->client->prepare( $this->sql->query,$this->sql->param ); - } - - - - /** - * Ausfuehren einer Datenbankanfrage. - * - * @param SQL-Objekt - * @return Object (Result) - */ - public function query( ) - { - return $this->execute(); - } - - - /** - * Ausfuehren einer Datenbankanfrage. - * - * @param SQL-Objekt - * @return Object (Result) - */ - public function execute( ) - { - // Ausfuehren... - $result = $this->client->query($this->sql); - - if ( $result === FALSE ) - { - throw new RuntimeException( 'Database error: '.$this->client->error); - } - - return $result; - } - - - /** - * Ermittelt genau 1 Datenbankergebnis aus einer SQL-Anfrage. - * Falls es mehrere Treffer gibt, wird die 1. Spalte aus der 1. Zeile genommen. - * - * @param String $this->query - * @return String - */ - public function &getOne() - { - $none = ''; - $result = $this->query(); - - $row = $this->client->fetchRow( $result,0 ); - $this->client->freeResult($result); - - if ( ! is_array($row) ) - return $none; - - $keys = array_keys($row); - - return $row[ $keys[0] ]; - } - - - /** - * Ermittelt eine Zeile aus der Datenbank. - * - * @param String $this->query - * @return Array - */ - public function &getRow() - { - $result = $this->query(); - - $row = $this->client->fetchRow( $result,0 ); - $this->client->freeResult($result); - - if ( ! is_array($row) ) - $row = array(); - - return $row; - } - - - /** - * Ermittelt eine (die 1.) Spalte aus dem Datenbankergebnis. - * - * @param String $this->query - * @return Array - */ - public function &getCol() - { - $result = $this->query(); - - $i = 0; - $col = array(); - while( $row = $this->client->fetchRow( $result,$i++ ) ) - { - if ( empty($row) ) - break; - - $keys = array_keys($row); - $col[] = $row[ $keys[0] ]; - } - - $this->client->freeResult($result); - - return $col; - } - - - /** - * Ermittelt ein assoziatives Array aus der Datenbank. - * - * @param String $this->query - * @param Boolean $force_array - * @return Array - */ - public function &getAssoc() - { - $force_array = false; - - $results = array(); - $result = $this->query(); - - $i = 0; - - while( $row = $this->client->fetchRow( $result,$i++ ) ) - { - if ( empty($row) ) - break; - - $keys = array_keys($row); - $key1 = $keys[0]; - $id = $row[$key1]; - - if ( count($row) > 2 || $force_array ) - { - unset( $row[$key1] ); - $results[ $id ] = $row; - } - else - { - $key2 = $keys[1]; - - $results[ $id ] = $row[$key2]; - } - } - - $this->client->freeResult( $result ); - - return $results; - } - - - /** - * Ermittelt alle Datenbankergebniszeilen. - * - * @param String $this->query - * @return Array - */ - public function &getAll() - { - $result = $this->query(); - - $results = array(); - $i = 0; - - while( $row = $this->client->fetchRow( $result,$i++ ) ) - { - $results[] = $row; - } - - $this->client->freeResult( $result ); - - return $results; - } - - - /** - * Führt eine Query aus und gibt nur zurück, ob diese funktioniert. - * - * @param unknown_type $this->query - * @return boolean - */ - public function testQuery() - { - try - { - $result = $this->query(); - return $result; - } - catch( Exception $e ) - { - return false; - } - } - - - /** - * Setzt eine Ganzzahl als Parameter.<br> - * - * @param name Name des Parameters - * @param value Inhalt - */ - function setInt( $name,$value ) - { - $this->client->bind( $name, (int)$value ); - } - - - - /** - * Setzt eine Zeichenkette als Parameter.<br> - * - * @param name Name des Parameters - * @param value Inhalt - */ - function setString( $name,$value ) - { - $this->client->bind( $name, (string)$value ); - } - - - - /** - * Setzt einen bool'schen Wert als Parameter.<br> - * Ist der Parameterwert wahr, dann wird eine 1 gesetzt. Sonst 0.<br> - * - * @param name Name des Parameters - * @param value Inhalt - */ - function setBoolean( $name,$value ) - { - if ( $value ) - $this->setInt( $name,1 ); - else - $this->setInt( $name,0 ); - } - - - - /** - * Setzt einen Parameter auf den Wert <code>null</code>.<br> - * - * @param name Name des Parameters - */ - function setNull( $name ) - { - $this->client->bind( $name, null ); - } - - -} - - -?>- \ No newline at end of file diff --git a/db/driver/pdo.class.php b/db/driver/pdo.class.php @@ -1,221 +0,0 @@ -<?php - -// -// +----------------------------------------------------------------------+ -// | PHP version 4.0 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1997-2001 The PHP Group | -// +----------------------------------------------------------------------+ -// | This source file is subject to version 2.02 of the PHP license, | -// | that is bundled with this package in the file LICENSE, and is | -// | available at through the world-wide-web at | -// | http://www.php.net/license/2_02.txt. | -// | If you did not receive a copy of the PHP license and are unable to | -// | obtain it through the world-wide-web, please send a note to | -// | license@php.net so we can mail you a copy immediately. | -// +----------------------------------------------------------------------+ -// | Authors: Stig Bakken <ssb@fast.no> | -// | Jan Dankert <phpdb@jandankert.de> | -// +----------------------------------------------------------------------+ -// - -/** - * Datenbank-abhaengige Methoden fuer PDO. - * - * @author Jan Dankert - * @version $Revision: 1.5 $ - * @package openrat.database - */ -class DB_pdo -{ - /** - * Die PDO-Verbindung. - * - * @var Resource - */ - var $connection; - - /** - * Datenbank-Fehler. - * - * @var String - */ - var $error; - - var $lowercase = false; - - var $params; - - - function connect( $conf ) - { - $url = $conf['dsn' ]; - $user = $conf['user' ]; - $pw = $conf['password']; - - if ( !empty($conf['convert_to_lowercase']) ) - $this->lowercase = true; - - $options = array(); - foreach( $conf as $c ) - if ( is_string($c) && substr($c,0,7) == 'option_' ) - $options[substr($c,8)] = $conf[$c]; - - if ( $conf['persistent']) - $options[ PDO::ATTR_PERSISTENT ] = true; - - if ( !$conf['prepare']) - $options[ PDO::ATTR_EMULATE_PREPARES ] = true; - - $options[ PDO::ERRMODE_EXCEPTION ] = true; - $options[ PDO::ATTR_DEFAULT_FETCH_MODE ] = PDO::FETCH_ASSOC; - - $this->connection = new PDO($url, $user, $pw, $options); - - if ( !is_object($this->connection) ) - throw new OpenRatException( 'DATABASE_ERROR_CONNECTION',"Could not connect to database on host $host. ".PDO::errorInfo() ); - - return true; - } - - - - function disconnect() - { - $this->connection = null; - return true; - } - - - - function query($query) - { - $erg = $this->stmt->execute(); - - if ( $erg === false ) - { - throw new RuntimeException( 'Could not execute prepared statement "'.$query->query.'": '.implode('/',$this->stmt->errorInfo()) ); - } - - return $this->stmt; - } - - - function fetchRow( $result, $rownum ) - { - $row = $this->stmt->fetch( PDO::FETCH_ASSOC ); - - if ( is_array($row) && $this->lowercase ) - $row = array_change_key_case($row); - - return $row; - } - - - function freeResult($result) - { - return true; - } - - - function prepare( $query,$param) - { - $this->params = $param; - $offset = 0; - foreach( $param as $name=>$pos) - { - $name = ':'.$name; - $pos += $offset; - $query = substr($query,0,$pos).$name.substr($query,$pos); - - $offset = $offset + strlen($name); - } - - Logger::debug('PDO: SQL-before-preparation: '.$query); - - $this->stmt = $this->connection->prepare($query); - - if ( $this->stmt === false ) - throw new OpenRatException('ERROR_DATABASE_CONNECTION','Could not prepare statement: '.$query.' Cause: '.implode('/',$this->connection->errorInfo()) ); - - } - - - - function bind( $param,$value ) - { - $name = ':'.$param; - - if ( is_string($value) ) - $type = PDO::PARAM_STR; - elseif( is_int($value)) - $type = PDO::PARAM_INT; - elseif( is_null($value)) - $type = PDO::PARAM_NULL; - else - throw new RuntimeException( 'Unknown type' ); - - $this->stmt->bindValue($name,$value,$type); - - Logger::debug('PDO: SQL-Binding of parameter '.$name); - } - - - - /** - * Startet eine Transaktion. - */ - function start() - { - $this->connection->beginTransaction(); - } - - - - /** - * Beendet eine Transaktion. - */ - function commit() - { - $this->connection->commit(); - } - - - /** - * Bricht eine Transaktion ab. - */ - function rollback() - { - try - { - $this->connection->rollBack(); - } - catch ( PDOException $e ) - { - // Kommt vor, wenn keine Transaktion existiert. - } - } - - - - /** - * Setzt die letzte Abfrage zurueck. - */ - function clear() - { - $this->params = array(); - } - - - /** - * Why this? See http://e-mats.org/2008/07/fatal-error-exception-thrown-without-a-stack-frame-in-unknown-on-line-0/ - * - * @return array - */ - function __sleep() { - return array(); - } - -} - -?>- \ No newline at end of file diff --git a/db/include.inc.php b/db/include.inc.php @@ -1,9 +1,4 @@ <?php -require_once( OR_DBCLASSES_DIR."Database.class.php" ); -require_once( OR_DBCLASSES_DIR."Statement.class.php" ); -require_once( OR_DBCLASSES_DIR."Sql.class.php" ); -if (version_compare(PHP_VERSION, '5.1.0', '>')) - require_once( OR_DBCLASSES_DIR."driver/pdo.class.php" ); ?> \ No newline at end of file diff --git a/dispatcher.php b/dispatcher.php @@ -33,7 +33,7 @@ try require_once( OR_TEXTCLASSES_DIR ."include.inc.".PHP_EXT ); // Datenbank-Funktionen einbinden. - require_once( OR_DBCLASSES_DIR."include.inc.".PHP_EXT ); + require_once( OR_MODULES_DIR."database/require.".PHP_EXT ); // Jetzt erst die Sitzung starten (nachdem alle Klassen zur Verfügung stehen). session_start(); diff --git a/modules/database/Database.class.php b/modules/database/Database.class.php @@ -0,0 +1,208 @@ +<?php +// OpenRat Content Management System +// Copyright (C) 2002-2006 Jan Dankert, jandankert@jandankert.de +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +/** + * Darstellung einer Datenbank-Verbindung. + * + * Fuer die echten DB-Aufrufe werden die entsprechenden + * Methoden des passenden Clients aufgerufen. + * + * Diese Klasse stammt urspruenglich aus dem PHP-Pear-DB-Projekt, wurde hier aber intensiv veraendert. + * + * @author Jan Dankert + * @package openrat.database + */ +class DB +{ + /** + * Datenbank-Id. + * + * @var String + */ + var $id; + + /** + * Konfiguration der Datenbank-Verbindung + * + * @var Array + */ + var $conf; + + /** + * Kennzeichen, ob die Datenbank verf�gbar ist. + * + * @var Boolean + */ + var $available; + + /** + * Enth�lt eine Fehlermeldung (sofern verf�gbar). + * + * @var String + */ + var $error; + + /** + * Client. + * Enth�lt ein Objekt der Klasse db_<type>. + * + * @var Object + */ + var $client; + + /** + * Schalter, ob eine Transaktion begonnen wurde. + * @var boolean + */ + var $transactionInProgress = false; + + + /** + * Kontruktor. + * Erwartet die Datenbank-Konfiguration als Parameter. + * + * @param Array Konfiguration der Verbindung + * @param boolean admin Wenn es eine Admin-DB-Verbindung werden soll, die auch DDL ausfuehren darf + */ + public function DB( $dbconf,$admin=false ) + { + global $conf; + + $this->conf = $dbconf + $conf['database-default']['defaults']; // linksstehender Operator hat Priorität! + + if ( $admin ) + { + // Bevorzugung der Unter-Konfiguration 'update' + if ( isset($this->conf['update']) ) + $this->conf = $this->conf['update'] + $this->conf; // linksstehender Operator hat Priorität! + } + + $this->connect(); + } + + + /** + * Verbindung zur Datenbank aufbauen. + * + * @return Status + */ + public function connect() + { + // Ausfuehren des Systemkommandos vor Verbindungsaufbau + if ( !empty($this->conf['cmd'])) + { + $ausgabe = array(); + $rc = false; + + Logger::debug("Database command executing: ".$this->conf['cmd']); + exec( $this->conf['cmd'],$ausgabe,$rc ); + + foreach( $ausgabe as $zeile ) + Logger::debug("Database command output: ".$zeile); + + if ( $rc != 0 ) + { + throw new OpenRatException( 'ERROR_DATABASE_CONNECTION','Command failed: '.implode("",$ausgabe) ); + } + } + + $type = $this->conf['type']; + $classname = 'db_'.$type; + + if ( ! class_exists($classname) ) + { + $this->available = false; + throw new OpenRatException( 'ERROR_DATABASE_CONNECTION','Database type "'.$type.'" is not available'); + } + + // Client instanziieren + $this->client = new $classname; + + + $this->client->connect( $this->conf ); + + // SQL nach Verbindungsaufbau ausfuehren. + if ( ! empty($this->conf['connection_sql']) ) + { + $cmd = $this->conf['connection_sql']; + + $sql = $this->sql($cmd); + + $ok = $sql->execute(); + + if ( ! $ok ) + { + throw new OpenRatException( 'ERROR_DATABASE_CONNECTION',"Could not execute connection-query '".$cmd."'"); + } + } + + Logger::debug('database connection established'); + + $this->available = true; + return true; + } + + /** + * Startet eine Transaktion. + * Falls der Schalter 'transaction' nicht gesetzt ist, passiert nichts. + */ + public function start() + { + $this->transactionInProgress = true; + $this->client->start(); + } + + + /** + * Beendet und bestaetigt eine Transaktion. + * Falls der Schalter 'transaction' nicht gesetzt ist, passiert nichts. + */ + public function commit() + { + if ( $this->transactionInProgress ) + { + $this->client->commit(); + $this->transactionInProgress = false; + } + } + + + + /** + * Setzt eine Transaktion zurueck. + * Falls der Schalter 'transaction' nicht gesetzt ist, passiert nichts. + */ + public function rollback() + { + if ( $this->transactionInProgress ) + { + $this->client->rollback(); + $this->transactionInProgress = false; + } + } + + public function sql( $sql ) + { + return new Statement( $sql,$this->client,$this->conf); + } + +} + + +?>+ \ No newline at end of file diff --git a/modules/database/DbVersion.class.php b/modules/database/DbVersion.class.php @@ -0,0 +1,315 @@ +<?php + +define('OR_DB_INDEX_PREFIX' ,'IX'); +define('OR_DB_CONSTRAINT_PREFIX','FK'); + +abstract class DbVersion +{ + private $db; + private $tablePrefix; + private $tableSuffix; + private $dbmsType; + + function DbVersion( $db ) + { + $this->db = $db; + + switch( $db->conf['type'] ) + { + case 'mysql': + case 'mysqli': + $this->dbmsType = 'mysql'; + break; + case 'postgresql': + $this->dbmsType = 'postgresql'; + break; + case 'sqlite': + case 'sqlite3': + $this->dbmsType = 'sqlite'; + break; + case 'pdo': + $dsnParts = explode(':',$db->conf['dsn']); + switch( $dsnParts[0] ) + { + case 'mysql': + $this->dbmsType = 'mysql'; + break; + case 'pgsql': + $this->dbmsType = 'postgresql'; + break; + case 'sqlite': + $this->dbmsType = 'sqlite'; + break; + default: + Http::serverError('Datebase Configuration Error','Unknown DBMS in PDO-DSN: '.$dsnParts[0]); + } + break; + default: + Http::serverError('Datebase Configuration Error','Unknown DBMS type: '.$db->conf['type'] ); + } + + $this->tablePrefix = $db->conf['prefix']; + $this->tableSuffix = $db->conf['suffix']; + } + + // Muss überschrieben werden! + abstract function update(); + + + + + + + + + protected function getTableName( $name ) + { + return $this->tablePrefix.$name.$this->tableSuffix; + } + + + /** + * Erzeugt eine neue Tabelle. + * Die neue Tabelle enthält bereits eine Spalte "id" (da eine leere Tabelle i.d.R. nicht zulässig ist). + */ + function addTable( $tableName ) + { + $tableName = $this->getTableName($tableName); + + $table_opts = $this->dbmsType=='mysql'?' ENGINE=InnoDB CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci':''; + + $ddl = $this->db->sql('CREATE TABLE '.$tableName.'(id INTEGER)'.$table_opts.';'); + // The syntax 'TYPE = InnoDB' was deprecated in MySQL 5.0 and was removed in MySQL 5.1 and later versions. + + $ddl->query(); + } + + + # Creating a new column + # param 1: column name + # param 2: type (available are: INT,VARCHAR,TEXT,BLOB) + # param 3: size (number value) + # param 4: default (number value) + # param 5: nullable (available are: J,N) + function addColumn($tableName,$columnName,$type,$size,$default,$nullable) + { + $table = $this->getTableName($tableName); + + $type = strtoupper($type); + switch( $type ) + { + case 'INT': + switch( $this->dbmsType ) + { + case 'mysql': + if ( $size == 1 ) + $dbmsInternalType = 'TINYINT'; + else + $dbmsInternalType = 'INT'; + break; + + case 'oracle': + $dbmsInternalType = 'NUMBER'; + break; + + default: + $dbmsInternalType = 'INTEGER'; + + } + break; + + case 'VARCHAR': + switch( $this->dbmsType ) + { + default: + $dbmsInternalType = 'VARCHAR'; + + } + break; + + case 'TEXT': + switch( $this->dbmsType ) + { + case 'mysql': + $dbmsInternalType = 'MEDIUMTEXT'; + break; + + case 'oracle': + $dbmsInternalType = 'CLOB'; + break; + + default: + $dbmsInternalType = 'TEXT'; + + } + break; + + case 'BLOB': + switch( $this->dbmsType ) + { + case 'mysql': + $dbmsInternalType = 'MEDIUMBLOB'; + break; + + case 'oracle': + $dbmsInternalType = 'CLOB'; + break; + + case 'postgresql': + $dbmsInternalType = 'TEXT'; + break; + + case 'sqlite': + $dbmsInternalType = 'TEXT'; + break; + + default: + $dbmsInternalType = 'BLOB'; + + } + break; + default: + Http::serverError('Datebase Configuration Error','Unknown Column type: '.$type ); + } + + if ( $this->dbmsType == 'oracle') + { + // TEXT-columns should be nullable in Oracle, because empty strings are treated as NULL + if ( $type=='VARCHAR' || $type=='TEXT') + $nullable = true; + + } + + $ddl = $this->db->sql('ALTER TABLE '.$table. + ' ADD COLUMN '.$columnName.' '.$dbmsInternalType.($size!=null?'('.$size.')':''). + ($default!==null?' DEFAULT '.(is_string($default)?"'":'').$default.(is_string($default)?"'":''):''). + ' '.($nullable?'NULL':'NOT NULL').';' + ); + $ddl->query(); + + } + + + + function addPrimaryKey( $tableName,$columnNames) + { + $table = $this->getTableName($tableName); + + if ( !is_array($columnNames) ) + $columnNames = explode(',',$columnNames); + + $ddl = $this->db->sql('ALTER TABLE '.$table.' ADD PRIMARY KEY ('.implode(',',$columnNames).');'); + $ddl->query(); + + } + + + + # Creating a unique key + # param 1: name of index column. Seperate multiple columns with ',' + function addIndex($tableName,$columnNames,$unique=false) + { + $table = $this->getTableName($tableName); + + if ( !is_array($columnNames) ) + $columnNames = explode(',',$columnNames); + + $indexName = $this->tablePrefix.OR_DB_INDEX_PREFIX.'_'.$tableName.'_'.implode('_',$columnNames).$this->tableSuffix; + +// if [ "$type" == "oracle" ]; then +// cnt=$(($cnt+1)) +// echo "CREATE UNIQUE INDEX ${prefix}uidx_${cnt}" >> $outfile +// else + + $ddl = $this->db->sql('CREATE '.($unique?'UNIQUE ':'').'INDEX '.$indexName.' ON '.$table.' ('.implode(',',$columnNames).');'); + $ddl->query(); + + } + + + /** + * Creating a unique key. + * param 1: name of index column. Seperate multiple columns with ',' + * + */ + function addUniqueIndex($tableName,$columnNames) + { + $this->addIndex( $tableName,$columnNames,true ); + } + + + # Creating a foreign key + # param 1: column name + # param 2: target table name + # param 3: target column name + function addConstraint($tableName,$columnName,$targetTableName,$targetColumnName) + { + $table = $this->getTableName($tableName); + $targetTable = $this->getTableName($targetTableName); + + $constraintName = $this->tablePrefix.OR_DB_CONSTRAINT_PREFIX.'_'.$tableName.$this->tableSuffix.'_'.$columnName; + + // Oracle doesn't support "ON DELETE RESTRICT"-Statements, but its the default. + + $ddl = $this->db->sql('ALTER TABLE '.$table.' ADD CONSTRAINT '.$constraintName.' FOREIGN KEY ('.$columnName.') REFERENCES '.$targetTable.' ('.$targetColumnName.') ON DELETE RESTRICT ON UPDATE RESTRICT;'); + $ddl->query(); + } + + + + function dropTable( $tableName) + { + $table = $this->getTableName($tableName); + + $ddl = $this->db->sql('DROP TABLE '.$table.';' ); + $ddl->query(); + } + + function dropColumn( $tableName,$columnName ) + { + $table = $this->getTableName($tableName); + + $ddl = $this->db->sql('ALTER TABLE '.$table.' DROP COLUMN '.$columnName.';'); + $ddl->query(); + + + } + + function dropIndex( $indexName,$unique=false) + { + $ddl = $this->db->sql('DROP'.($unique?' UNIQUE':'').' INDEX '.$indexName.';' ); + $ddl->query(); + } + + function dropUniqueIndex( $indexName) + { + $this->dropIndex( $indexName,true ); + } + + function dropPrimaryKey( $tableName,$columnNames ) + { + $table = $this->getTableName($tableName); + + if ( !is_array($columnNames) ) + $columnNames = explode(',',$columnNames); + + $ddl = $this->db->sql('ALTER TABLE '.$table.' DROP PRIMARY KEY('.implode(',',$columnNames).')'); + $ddl->query(); + } + + + function dropConstraint( $constraintName) + { + $ddl = $this->db->sql('DROP CONSTRAINT '.$constraintName.';' ); + $ddl->query(); + } + + + function getDb() + { + return $this->db; + } + +} + +?>+ \ No newline at end of file diff --git a/modules/database/Sql.class.php b/modules/database/Sql.class.php @@ -0,0 +1,115 @@ +<?php +// OpenRat Content Management System +// Copyright (C) 2002-2006 Jan Dankert, jandankert@jandankert.de +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + + +/** + * SQL-Anweisung.<br> + * <br> + * Darstellen eines SQL-Statements incl. Methoden zum Fuellen von + * Platzhaltern im SQL-Befehl.<br> + * <br> + * Beispiel<br> + * <pre> + * // Neues Objekt erzeugen mit SQL-Anweisung + * $sql = $db->sql('SELECT * FROM xy WHERE id={uid} AND name={name}'); + * + * // Parameter f�llen + * $sql->setInt ('uid' ,1 ); + * $sql->setString('name','peter'); + * + * // Fertige SQL-Anweisung verwenden + * $xy->execute( $sql->query ); + * </pre> + * <br> + * Ziele dieser Klasse sind:<br> + * - Schreiben einfacher SQL-Anweisungen ohne Stringverarbeitung<br> + * - Verhindern von SQL-Injection.<br> + * <br> + * + * @author Jan Dankert, $Author$ + * @version $Revision$ + * @package openrat.services + */ + +class Sql +{ + /** + * SQL-Anweisung. + */ + var $query; + + /** + * Ein 1-dimensionales Array mit den Positionen der Parameter.<br> + * <br> + * Beispiel:<br> + * <pre> + * + * Array + * ( + * [lid] => 16 + * [oid] => 24 + * ) + * </pre> + */ + var $param = array(); + + + /** + * Erzeugt ein SQL-Objekt und analysiert die SQL-Anfrage. + */ + function Sql( $query = '' ) + { + $this->parseSourceQuery( $query ); + } + + + /** + * Die SQL-Anfrage wird auf Parameter untersucht. + */ + function parseSourceQuery( $query ) + { + Logger::debug( 'SQL-query: '.$query); + + while( true ) // Schleife wird solange durchlaufen, solange Parameter gefunden werden. + { + $posKlLinks = strpos($query,'{'); + $posKlRechts = strpos($query,'}'); + + if ( $posKlLinks === false || $posKlRechts === false ) + break; // Schleife abbrechen, wenn kein Parameter mehr gefunden wird. + + $nameParam = substr($query,$posKlLinks+1,$posKlRechts-$posKlLinks-1); // Name Parameter + + if ( isset($this->param[$nameParam ])) + throw new RuntimeException( 'Parameter '.$nameParam.' in Query mehrfach vorhanden.' ); + + $this->param[$nameParam] = $posKlLinks; + + $query = substr($query,0,$posKlLinks).substr($query,$posKlRechts+1); + } + + $this->query = $query; + + } + + +} + + +?>+ \ No newline at end of file diff --git a/modules/database/Statement.class.php b/modules/database/Statement.class.php @@ -0,0 +1,326 @@ +<?php +// OpenRat Content Management System +// Copyright (C) 2002-2006 Jan Dankert, jandankert@jandankert.de +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +/** + * Darstellung einer Datenbank-Abfrage. + * + * @author Jan Dankert + * @package openrat.database + */ +class Statement +{ + + /** + * SQL-Objekt. + * + * @var SQL + */ + var $sql; + + /** + * Client. + * Enth�lt ein Objekt der Klasse db_<type>. + * + * @var Object + */ + var $client; + + + /** + * Datenbank-Konfiguration + * @var Array + */ + var $conf; + + /** + * Kontruktor. + * Erwartet die Datenbank-Konfiguration als Parameter. + * + * @param Array Konfiguration der Verbindung + * @return Status 'true' wenn Verbindung erfolgreich aufgebaut. + */ + public function Statement( $sql, $client,$conf ) + { + // Tabellen-Praefixe ergaenzen. + $this->conf = $conf; + $this->client = $client; + + $sql = str_replace('{{',$conf['prefix'],$sql); + $sql = str_replace('}}',$conf['suffix'],$sql); + + $this->sql = new Sql( $sql ); + + // Vorbereitete Datenbankabfrage ("Prepared Statement") + $this->client->clear(); + + // Statement an die Datenbank schicken + $this->client->prepare( $this->sql->query,$this->sql->param ); + } + + + + /** + * Ausfuehren einer Datenbankanfrage. + * + * @param SQL-Objekt + * @return Object (Result) + */ + public function query( ) + { + return $this->execute(); + } + + + /** + * Ausfuehren einer Datenbankanfrage. + * + * @param SQL-Objekt + * @return Object (Result) + */ + public function execute( ) + { + // Ausfuehren... + $result = $this->client->query($this->sql); + + if ( $result === FALSE ) + { + throw new RuntimeException( 'Database error: '.$this->client->error); + } + + return $result; + } + + + /** + * Ermittelt genau 1 Datenbankergebnis aus einer SQL-Anfrage. + * Falls es mehrere Treffer gibt, wird die 1. Spalte aus der 1. Zeile genommen. + * + * @param String $this->query + * @return String + */ + public function &getOne() + { + $none = ''; + $result = $this->query(); + + $row = $this->client->fetchRow( $result,0 ); + $this->client->freeResult($result); + + if ( ! is_array($row) ) + return $none; + + $keys = array_keys($row); + + return $row[ $keys[0] ]; + } + + + /** + * Ermittelt eine Zeile aus der Datenbank. + * + * @param String $this->query + * @return Array + */ + public function &getRow() + { + $result = $this->query(); + + $row = $this->client->fetchRow( $result,0 ); + $this->client->freeResult($result); + + if ( ! is_array($row) ) + $row = array(); + + return $row; + } + + + /** + * Ermittelt eine (die 1.) Spalte aus dem Datenbankergebnis. + * + * @param String $this->query + * @return Array + */ + public function &getCol() + { + $result = $this->query(); + + $i = 0; + $col = array(); + while( $row = $this->client->fetchRow( $result,$i++ ) ) + { + if ( empty($row) ) + break; + + $keys = array_keys($row); + $col[] = $row[ $keys[0] ]; + } + + $this->client->freeResult($result); + + return $col; + } + + + /** + * Ermittelt ein assoziatives Array aus der Datenbank. + * + * @param String $this->query + * @param Boolean $force_array + * @return Array + */ + public function &getAssoc() + { + $force_array = false; + + $results = array(); + $result = $this->query(); + + $i = 0; + + while( $row = $this->client->fetchRow( $result,$i++ ) ) + { + if ( empty($row) ) + break; + + $keys = array_keys($row); + $key1 = $keys[0]; + $id = $row[$key1]; + + if ( count($row) > 2 || $force_array ) + { + unset( $row[$key1] ); + $results[ $id ] = $row; + } + else + { + $key2 = $keys[1]; + + $results[ $id ] = $row[$key2]; + } + } + + $this->client->freeResult( $result ); + + return $results; + } + + + /** + * Ermittelt alle Datenbankergebniszeilen. + * + * @param String $this->query + * @return Array + */ + public function &getAll() + { + $result = $this->query(); + + $results = array(); + $i = 0; + + while( $row = $this->client->fetchRow( $result,$i++ ) ) + { + $results[] = $row; + } + + $this->client->freeResult( $result ); + + return $results; + } + + + /** + * Führt eine Query aus und gibt nur zurück, ob diese funktioniert. + * + * @param unknown_type $this->query + * @return boolean + */ + public function testQuery() + { + try + { + $result = $this->query(); + return $result; + } + catch( Exception $e ) + { + return false; + } + } + + + /** + * Setzt eine Ganzzahl als Parameter.<br> + * + * @param name Name des Parameters + * @param value Inhalt + */ + function setInt( $name,$value ) + { + $this->client->bind( $name, (int)$value ); + } + + + + /** + * Setzt eine Zeichenkette als Parameter.<br> + * + * @param name Name des Parameters + * @param value Inhalt + */ + function setString( $name,$value ) + { + $this->client->bind( $name, (string)$value ); + } + + + + /** + * Setzt einen bool'schen Wert als Parameter.<br> + * Ist der Parameterwert wahr, dann wird eine 1 gesetzt. Sonst 0.<br> + * + * @param name Name des Parameters + * @param value Inhalt + */ + function setBoolean( $name,$value ) + { + if ( $value ) + $this->setInt( $name,1 ); + else + $this->setInt( $name,0 ); + } + + + + /** + * Setzt einen Parameter auf den Wert <code>null</code>.<br> + * + * @param name Name des Parameters + */ + function setNull( $name ) + { + $this->client->bind( $name, null ); + } + + +} + + +?>+ \ No newline at end of file diff --git a/modules/database/driver/pdo.class.php b/modules/database/driver/pdo.class.php @@ -0,0 +1,221 @@ +<?php + +// +// +----------------------------------------------------------------------+ +// | PHP version 4.0 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2001 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.02 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Authors: Stig Bakken <ssb@fast.no> | +// | Jan Dankert <phpdb@jandankert.de> | +// +----------------------------------------------------------------------+ +// + +/** + * Datenbank-abhaengige Methoden fuer PDO. + * + * @author Jan Dankert + * @version $Revision: 1.5 $ + * @package openrat.database + */ +class DB_pdo +{ + /** + * Die PDO-Verbindung. + * + * @var Resource + */ + var $connection; + + /** + * Datenbank-Fehler. + * + * @var String + */ + var $error; + + var $lowercase = false; + + var $params; + + + function connect( $conf ) + { + $url = $conf['dsn' ]; + $user = $conf['user' ]; + $pw = $conf['password']; + + if ( !empty($conf['convert_to_lowercase']) ) + $this->lowercase = true; + + $options = array(); + foreach( $conf as $c ) + if ( is_string($c) && substr($c,0,7) == 'option_' ) + $options[substr($c,8)] = $conf[$c]; + + if ( $conf['persistent']) + $options[ PDO::ATTR_PERSISTENT ] = true; + + if ( !$conf['prepare']) + $options[ PDO::ATTR_EMULATE_PREPARES ] = true; + + $options[ PDO::ERRMODE_EXCEPTION ] = true; + $options[ PDO::ATTR_DEFAULT_FETCH_MODE ] = PDO::FETCH_ASSOC; + + $this->connection = new PDO($url, $user, $pw, $options); + + if ( !is_object($this->connection) ) + throw new OpenRatException( 'DATABASE_ERROR_CONNECTION',"Could not connect to database on host $host. ".PDO::errorInfo() ); + + return true; + } + + + + function disconnect() + { + $this->connection = null; + return true; + } + + + + function query($query) + { + $erg = $this->stmt->execute(); + + if ( $erg === false ) + { + throw new RuntimeException( 'Could not execute prepared statement "'.$query->query.'": '.implode('/',$this->stmt->errorInfo()) ); + } + + return $this->stmt; + } + + + function fetchRow( $result, $rownum ) + { + $row = $this->stmt->fetch( PDO::FETCH_ASSOC ); + + if ( is_array($row) && $this->lowercase ) + $row = array_change_key_case($row); + + return $row; + } + + + function freeResult($result) + { + return true; + } + + + function prepare( $query,$param) + { + $this->params = $param; + $offset = 0; + foreach( $param as $name=>$pos) + { + $name = ':'.$name; + $pos += $offset; + $query = substr($query,0,$pos).$name.substr($query,$pos); + + $offset = $offset + strlen($name); + } + + Logger::debug('PDO: SQL-before-preparation: '.$query); + + $this->stmt = $this->connection->prepare($query); + + if ( $this->stmt === false ) + throw new OpenRatException('ERROR_DATABASE_CONNECTION','Could not prepare statement: '.$query.' Cause: '.implode('/',$this->connection->errorInfo()) ); + + } + + + + function bind( $param,$value ) + { + $name = ':'.$param; + + if ( is_string($value) ) + $type = PDO::PARAM_STR; + elseif( is_int($value)) + $type = PDO::PARAM_INT; + elseif( is_null($value)) + $type = PDO::PARAM_NULL; + else + throw new RuntimeException( 'Unknown type' ); + + $this->stmt->bindValue($name,$value,$type); + + Logger::debug('PDO: SQL-Binding of parameter '.$name); + } + + + + /** + * Startet eine Transaktion. + */ + function start() + { + $this->connection->beginTransaction(); + } + + + + /** + * Beendet eine Transaktion. + */ + function commit() + { + $this->connection->commit(); + } + + + /** + * Bricht eine Transaktion ab. + */ + function rollback() + { + try + { + $this->connection->rollBack(); + } + catch ( PDOException $e ) + { + // Kommt vor, wenn keine Transaktion existiert. + } + } + + + + /** + * Setzt die letzte Abfrage zurueck. + */ + function clear() + { + $this->params = array(); + } + + + /** + * Why this? See http://e-mats.org/2008/07/fatal-error-exception-thrown-without-a-stack-frame-in-unknown-on-line-0/ + * + * @return array + */ + function __sleep() { + return array(); + } + +} + +?>+ \ No newline at end of file diff --git a/modules/database/require.php b/modules/database/require.php @@ -0,0 +1,10 @@ +<?php + +include( dirname(__FILE__) . "/Database.class.php" ); +include( dirname(__FILE__) . "/Statement.class.php" ); +include( dirname(__FILE__) . "/Sql.class.php" ); + +if (version_compare(PHP_VERSION, '5.1.0', '>')) + include( dirname(__FILE__) . "/driver/pdo.class.php" ); + +?>+ \ No newline at end of file