openrat-cms

# OpenRat Content Management System
git clone http://git.code.weiherhei.de/openrat-cms.git
Log | Files | Refs

commit 5040c278741e4920d88d2f96a5f23f84c111a3cd
parent 074e840792f3c01c6aa0b278d9b108bd6bbb6f2b
Author: Jan Dankert <develop@jandankert.de>
Date:   Mon, 20 May 2019 01:15:43 +0200

Refactoring: Das Prüfen der DB-Version erfolgt mit der Standard-DB-Verbindung. Erst beim Update wird auf die Admin-Verbindung gewechselt.

Diffstat:
modules/cms-core/Dispatcher.class.php | 19++++++++++++++-----
modules/database-update/DbUpdate.class.php | 46++++++++++++++++++++++++++++------------------
modules/database/driver/PDODriver.class.php | 497+++++++++++++++++++++++++++++++++++++++----------------------------------------
3 files changed, 288 insertions(+), 274 deletions(-)

diff --git a/modules/cms-core/Dispatcher.class.php b/modules/cms-core/Dispatcher.class.php @@ -400,12 +400,22 @@ class Dispatcher */ private function updateDatabase($dbid) { - try { - $dbConfig = Conf()->subset('database')->subset($dbid); + $dbConfig = Conf()->subset('database')->subset($dbid); + + if ( ! $dbConfig->is('check_version',true)) + return; // Check for DB version is disabled. + + $updater = new DbUpdate(); + + if ( ! $updater->isUpdateRequired( db() ) ) + return; + + + if ( ! $dbConfig->is('auto_update',true)) + throw new \LogicException('DB Update required, but auto-update is disabled. '.OR_TITLE." ".OR_VERSION." needs DB-version ".DbUpdate::SUPPORTED_VERSION ); - if ( ! $dbConfig->is('check_version',true)) - return; // Check for DB version is disabled. + try { $adminDb = new Database( $dbConfig->subset('admin')->getConfig() + $dbConfig->getConfig() ); $adminDb->id = $dbid; } catch (\Exception $e) { @@ -413,7 +423,6 @@ class Dispatcher throw new OpenRatException('DATABASE_ERROR_CONNECTION', $e->getMessage()); } - $updater = new DbUpdate(); $updater->update($adminDb); // Try to close the PDO connection. PDO doc: diff --git a/modules/database-update/DbUpdate.class.php b/modules/database-update/DbUpdate.class.php @@ -2,32 +2,42 @@ use database\Database; -define('OR_DB_SUPPORTED_VERSION' ,19); - -define('OR_DB_STATUS_UPDATE_PROGRESS', 0); -define('OR_DB_STATUS_UPDATE_SUCCESS' , 1); class DbUpdate { + // This is the required DB version: + const SUPPORTED_VERSION = 19; + // ----------------------------^^----------------------------- + + const STATUS_UPDATE_PROGRESS = 0; + const STATUS_UPDATE_SUCCESS = 1; + + public function isUpdateRequired( Database $db ) + { + $version = $this->getDbVersion($db); + + Logger::debug("Need DB-Version: ".self::SUPPORTED_VERSION."; Actual DB-Version: ".$version); + + if ( $version == self::SUPPORTED_VERSION ) + // Cool, der aktuelle DB-Stand passt zu dieser Version. Das ist auch der Normalfall. Weiter so. + return false; + + if ( $version > self::SUPPORTED_VERSION ) + // Oh oh, in der Datenbank ist eine neuere Version, als wir unterstützen. + throw new \LogicException('Actual DB version is not supported. '."DB-Version is $version, but ".OR_TITLE." ".OR_VERSION." only supports version ".self::SUPPORTED_VERSION ); + } + + + /** * @param Database $db */ - function update(Database $db ) + public function update(Database $db ) { $version = $this->getDbVersion($db); - if ( $version == OR_DB_SUPPORTED_VERSION ) - // Cool, der aktuelle DB-Stand passt zu dieser Version. Das ist auch der Normalfall. Weiter so. - return; - - if ( $version > OR_DB_SUPPORTED_VERSION ) - // Oh oh, in der Datenbank ist eine neue Version, als wir unterstüzten. - throw new \LogicException('Actual DB version is not supported. '."DB-Version is $version, but this is OpenRat ".OR_VERSION." which only supports version ".OR_DB_SUPPORTED_VERSION ); - if ( ! $db->conf['auto_update']) - throw new \LogicException('DB Update necessary. '."DB-Version is $version. Auto-Update is disabled, but this is OpenRat ".OR_VERSION." needs the version ".OR_DB_SUPPORTED_VERSION ); - - for( $installVersion = $version + 1; $installVersion <= OR_DB_SUPPORTED_VERSION; $installVersion++ ) + for( $installVersion = $version + 1; $installVersion <= self::SUPPORTED_VERSION; $installVersion++ ) { if ( $installVersion > 2 ) // Up to version 2 there was no table 'version'. { @@ -35,7 +45,7 @@ class DbUpdate $sql = $db->sql('INSERT INTO {{version}} (id,version,status,installed) VALUES( {id},{version},{status},{time} )',$db->id); $sql->setInt('id' , $installVersion); $sql->setInt('version', $installVersion); - $sql->setInt('status' , OR_DB_STATUS_UPDATE_PROGRESS); + $sql->setInt('status' , self::STATUS_UPDATE_PROGRESS); $sql->setInt('time' , time() ); $sql->query(); $db->commit(); @@ -55,7 +65,7 @@ class DbUpdate { $db->start(); $sql = $db->sql('UPDATE {{version}} SET status={status},installed={time} WHERE version={version}',$db->id); - $sql->setInt('status' , OR_DB_STATUS_UPDATE_SUCCESS); + $sql->setInt('status' , self::STATUS_UPDATE_SUCCESS); $sql->setInt('version', $installVersion); $sql->setInt('time' , time() ); $sql->query(); diff --git a/modules/database/driver/PDODriver.class.php b/modules/database/driver/PDODriver.class.php @@ -1,252 +1,247 @@ -<?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> | -// +----------------------------------------------------------------------+ -// -namespace database\driver; - -use database\Sql; -use \Logger; -use \PDO; -use \PDOException; -use PDOStatement; -use \RuntimeException; - -/** - * Datenbank-abhaengige Methoden fuer PDO. - * - * @author Jan Dankert - * @version $Revision: 1.5 $ - * @package openrat.database - */ -class PDODriver -{ - /** - * Die PDO-Verbindung. - * - * @var PDO - */ - private $connection; - - - /** - * @var PDOStatement - */ - public $stmt; - - - 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']) - // From the docs: - // "Many web applications will benefit from making persistent connections to database servers. - // Persistent connections are not closed at the end of the script, but are cached and re-used - // when another script requests a connection using the same credentials." - // "The persistent connection cache allows you to avoid the overhead of establishing a new - // connection every time a script needs to talk to a database, resulting in a faster web application." - $options[ PDO::ATTR_PERSISTENT ] = true; - - // From the docs: - // "try to use native prepared statements (if FALSE). - // It will always fall back to emulating the prepared statement if the driver cannot successfully prepare the current query" - $options[ PDO::ATTR_EMULATE_PREPARES ] = false; - - // Convert numeric values to strings when fetching => NO - $options[ PDO::ATTR_STRINGIFY_FETCHES ] = false; - - // From the docs: - // "If this value is FALSE, PDO attempts to disable autocommit so that the connection begins a transaction." - // We do NOT need transactions for reading actions (GET requests). - // We are opening a transaction with PDO::beginTransaction at the beginning of a POST-request. - // do NOT set this to false, otherwise there will be left open transactions. - //$options[ PDO::ATTR_AUTOCOMMIT ] = true; - - // We like Exceptions - $options[ PDO::ERRMODE_EXCEPTION ] = true; - $options[ PDO::ATTR_DEFAULT_FETCH_MODE ] = PDO::FETCH_ASSOC; - - try - { - $this->connection = new PDO($url, $user, $pw, $options); - } - catch(\PDOException $e) - { - Logger::warn( "Could not connect to database with dsn=$url and user=$user: ".$e->getMessage() ); - throw new \RuntimeException("Could not connect to database on host $url.",0,$e); - } - - // This should never happen, because PDO should throw an exception if the connection fails. - if ( !is_object($this->connection) ) - throw new RuntimeException("Could not connect to database on host '$url', Reason: ".PDO::errorInfo() ); - - return true; - } - - - /** - * Disconnects the database connection. - * - * @return bool - */ - public function disconnect() - { - // There is no disconnection-function. - // So the GC will call the finalize-method of the connection object. - $this->connection = null; - - return true; - } - - - /** - * @param $stmt PDOStatement - * @param $query Sql - * @return PDOStatement - */ - public function query($stmt,$query) - { - $erg = $stmt->execute(); - - if ( $erg === false ) - { - throw new RuntimeException( 'Could not execute prepared statement "'.$query->query.'": '.implode('/',$stmt->errorInfo()) ); - } - - return $stmt; - } - - - /** - * @param $stmt PDOStatement - * @param $result - * @param $rownum - * @return mixed Row - */ - public function fetchRow( $stmt, $result, $rownum ) - { - $row = $stmt->fetch( PDO::FETCH_ASSOC ); - - return $row; - } - - - public function prepare( $query,$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); - } - - $stmt = $this->connection->prepare($query); - - if ( $stmt === false ) - throw new RuntimeException("Could not prepare statement:\n$query\nCause: ".implode(' / ',$this->connection->errorInfo()) ); - - return $stmt; - } - - - /** - * Binding a parameter value. - * - * @param $stmt PDOStatement - * @param $param - * @param $value - */ - public function bind( $stmt,$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' ); - - $stmt->bindValue($name,$value,$type); - } - - - - /** - * Startet eine Transaktion. - */ - public function start() - { - $this->connection->beginTransaction(); - } - - - - /** - * Beendet eine Transaktion. - */ - public function commit() - { - $this->connection->commit(); - } - - - /** - * Bricht eine Transaktion ab. - */ - public function rollback() - { - try - { - $this->connection->rollBack(); - } - catch ( PDOException $e ) - { - // Kommt vor, wenn keine Transaktion existiert. - } - } - - - /** - * 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(); - } - -} - +<?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> | +// +----------------------------------------------------------------------+ +// +namespace database\driver; + +use database\Sql; +use \Logger; +use \PDO; +use \PDOException; +use PDOStatement; +use \RuntimeException; + +/** + * Datenbank-abhaengige Methoden fuer PDO. + * + * @author Jan Dankert + */ +class PDODriver +{ + /** + * Die PDO-Verbindung. + * + * @var PDO + */ + private $connection; + + + /** + * @var PDOStatement + */ + public $stmt; + + + function connect( $conf ) + { + $url = $conf['dsn' ]; + $user = $conf['user' ]; + $pw = $conf['password']; + + $options = array(); + foreach( $conf as $c ) + if ( is_string($c) && substr($c,0,7) == 'option_' ) + $options[substr($c,8)] = $conf[$c]; + + if ( $conf['persistent']) + // From the docs: + // "Many web applications will benefit from making persistent connections to database servers. + // Persistent connections are not closed at the end of the script, but are cached and re-used + // when another script requests a connection using the same credentials." + // "The persistent connection cache allows you to avoid the overhead of establishing a new + // connection every time a script needs to talk to a database, resulting in a faster web application." + $options[ PDO::ATTR_PERSISTENT ] = true; + + // From the docs: + // "try to use native prepared statements (if FALSE). + // It will always fall back to emulating the prepared statement if the driver cannot successfully prepare the current query" + $options[ PDO::ATTR_EMULATE_PREPARES ] = false; + + // Convert numeric values to strings when fetching => NO + $options[ PDO::ATTR_STRINGIFY_FETCHES ] = false; + + // From the docs: + // "If this value is FALSE, PDO attempts to disable autocommit so that the connection begins a transaction." + // We do NOT need transactions for reading actions (GET requests). + // We are opening a transaction with PDO::beginTransaction at the beginning of a POST-request. + // do NOT set this to false, otherwise there will be left open transactions. + //$options[ PDO::ATTR_AUTOCOMMIT ] = true; + + // We like Exceptions + $options[ PDO::ERRMODE_EXCEPTION ] = true; + $options[ PDO::ATTR_DEFAULT_FETCH_MODE ] = PDO::FETCH_ASSOC; + + try + { + $this->connection = new PDO($url, $user, $pw, $options); + } + catch(\PDOException $e) + { + Logger::warn( "Could not connect to database with dsn=$url and user=$user: ".$e->getMessage() ); + throw new \RuntimeException("Could not connect to database on host $url.",0,$e); + } + + // This should never happen, because PDO should throw an exception if the connection fails. + if ( !is_object($this->connection) ) + throw new RuntimeException("Could not connect to database on host '$url', Reason: ".PDO::errorInfo() ); + + return true; + } + + + /** + * Disconnects the database connection. + * + * @return bool + */ + public function disconnect() + { + // There is no disconnection-function. + // So the GC will call the finalize-method of the connection object. + $this->connection = null; + + return true; + } + + + /** + * @param $stmt PDOStatement + * @param $query Sql + * @return PDOStatement + */ + public function query($stmt,$query) + { + $erg = $stmt->execute(); + + if ( $erg === false ) + { + throw new RuntimeException( 'Could not execute prepared statement "'.$query->query.'": '.implode('/',$stmt->errorInfo()) ); + } + + return $stmt; + } + + + /** + * @param $stmt PDOStatement + * @param $result + * @param $rownum + * @return mixed Row + */ + public function fetchRow( $stmt, $result, $rownum ) + { + $row = $stmt->fetch( PDO::FETCH_ASSOC ); + + return $row; + } + + + public function prepare( $query,$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); + } + + $stmt = $this->connection->prepare($query); + + if ( $stmt === false ) + throw new RuntimeException("Could not prepare statement:\n$query\nCause: ".implode(' / ',$this->connection->errorInfo()) ); + + return $stmt; + } + + + /** + * Binding a parameter value. + * + * @param $stmt PDOStatement + * @param $param + * @param $value + */ + public function bind( $stmt,$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' ); + + $stmt->bindValue($name,$value,$type); + } + + + + /** + * Startet eine Transaktion. + */ + public function start() + { + $this->connection->beginTransaction(); + } + + + + /** + * Beendet eine Transaktion. + */ + public function commit() + { + $this->connection->commit(); + } + + + /** + * Bricht eine Transaktion ab. + */ + public function rollback() + { + try + { + $this->connection->rollBack(); + } + catch ( PDOException $e ) + { + // Kommt vor, wenn keine Transaktion existiert. + } + } + + + /** + * 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