Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sat, Feb 1, 10:56 PM

in-portal

Index: branches/5.2.x/LICENSE
===================================================================
--- branches/5.2.x/LICENSE (revision 16406)
+++ branches/5.2.x/LICENSE (revision 16407)
Property changes on: branches/5.2.x/LICENSE
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/LICENSE:r15931
Index: branches/5.2.x/robots.txt
===================================================================
--- branches/5.2.x/robots.txt (revision 16406)
+++ branches/5.2.x/robots.txt (revision 16407)
Property changes on: branches/5.2.x/robots.txt
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/robots.txt:r15931
Index: branches/5.2.x/core/kernel/db/db_load_balancer.php
===================================================================
--- branches/5.2.x/core/kernel/db/db_load_balancer.php (revision 16406)
+++ branches/5.2.x/core/kernel/db/db_load_balancer.php (revision 16407)
@@ -1,708 +1,708 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kDBLoadBalancer extends kBase {
/**
* Current database type
*
* @var string
* @access protected
*/
- protected $dbType = 'mysql';
+ protected $dbType = 'mysqli';
/**
* Function to handle sql errors
*
* @var string
* @access public
*/
public $errorHandler = '';
/**
* Database connection settings
*
* @var Array
* @access protected
*/
protected $servers = Array ();
/**
* Load of each slave server, given
*
* @var Array
* @access protected
*/
protected $serverLoads = Array ();
/**
* Caches replication lag of servers
*
* @var Array
* @access protected
*/
protected $serverLagTimes = Array ();
/**
* Connection references to opened connections
*
* @var Array
* @access protected
*/
protected $connections = Array ();
/**
* Index of last user slave connection
*
* @var int
* @access protected
*/
protected $slaveIndex = false;
/**
* Index of the server, that was used last
*
* @var int
* @access protected
*/
protected $lastUsedIndex = 0;
/**
* Consider slave down if it isn't responding for N milliseconds
*
* @var int
* @access protected
*/
protected $DBClusterTimeout = 10;
/**
* Scale load balancer polling time so that under overload conditions, the database server
* receives a SHOW STATUS query at an average interval of this many microseconds
*
* @var int
* @access protected
*/
protected $DBAvgStatusPoll = 2000;
/**
* Indicates, that next database query could be cached, when memory caching is enabled
*
* @var bool
* @access public
*/
public $nextQueryCachable = false;
/**
* Indicates, that next query should be sent to maser database
*
* @var bool
*/
public $nextQueryFromMaster = false;
/**
* Creates new instance of load balancer class
*
- * @param string $dbType
- * @param Array|string $errorHandler
+ * @param string $db_type
+ * @param Array|string $error_handler
*/
- function __construct($dbType, $errorHandler = '')
+ function __construct($db_type, $error_handler = '')
{
parent::__construct();
- $this->dbType = $dbType;
- $this->errorHandler = $errorHandler;
+ $this->dbType = $db_type;
+ $this->errorHandler = $error_handler;
$this->DBClusterTimeout *= 1e6; // convert to milliseconds
}
/**
* Setups load balancer according given configuration
*
* @param Array $config
* @return void
* @access public
*/
public function setup($config)
{
$this->servers = Array ();
$this->servers[0] = Array (
'DBHost' => $config['Database']['DBHost'],
'DBUser' => $config['Database']['DBUser'],
'DBUserPassword' => $config['Database']['DBUserPassword'],
'DBName' => $config['Database']['DBName'],
'DBLoad' => 0,
);
if ( isset($config['Databases']) ) {
$this->servers = array_merge($this->servers, $config['Databases']);
}
foreach ($this->servers as $server_index => $server_setting) {
$this->serverLoads[$server_index] = $server_setting['DBLoad'];
}
}
/**
* Returns connection index to master database
*
* @return int
* @access protected
*/
protected function getMasterIndex()
{
return 0;
}
/**
* Returns connection index to slave database. This takes into account load ratios and lag times.
* Side effect: opens connections to databases
*
* @return int
* @access protected
*/
protected function getSlaveIndex()
{
if ( count($this->servers) == 1 || $this->Application->isAdmin ) {
// skip the load balancing if there's only one server OR in admin console
return 0;
}
elseif ( $this->slaveIndex !== false ) {
// shortcut if generic reader exists already
return $this->slaveIndex;
}
$total_elapsed = 0;
$non_error_loads = $this->serverLoads;
$i = $found = $lagged_slave_mode = false;
// first try quickly looking through the available servers for a server that meets our criteria
do {
$current_loads = $non_error_loads;
$overloaded_servers = $total_threads_connected = 0;
while ($current_loads) {
if ( $lagged_slave_mode ) {
// when all slave servers are too lagged, then ignore lag and pick random server
$i = $this->pickRandom($current_loads);
}
else {
$i = $this->getRandomNonLagged($current_loads);
if ( $i === false && $current_loads ) {
// all slaves lagged -> pick random lagged slave then
$lagged_slave_mode = true;
$i = $this->pickRandom( $current_loads );
}
}
if ( $i === false ) {
// all slaves are down -> use master as a slave
$this->slaveIndex = $this->getMasterIndex();
return $this->slaveIndex;
}
$conn =& $this->openConnection($i);
if ( !$conn ) {
unset($non_error_loads[$i], $current_loads[$i]);
continue;
}
// Perform post-connection backoff
$threshold = isset($this->servers[$i]['DBMaxThreads']) ? $this->servers[$i]['DBMaxThreads'] : false;
$backoff = $this->postConnectionBackoff($conn, $threshold);
if ( $backoff ) {
// post-connection overload, don't use this server for now
$total_threads_connected += $backoff;
$overloaded_servers++;
unset( $current_loads[$i] );
}
else {
// return this server
break 2;
}
}
// no server found yet
$i = false;
// if all servers were down, quit now
if ( !$non_error_loads ) {
break;
}
// back off for a while
// scale the sleep time by the number of connected threads, to produce a roughly constant global poll rate
$avg_threads = $total_threads_connected / $overloaded_servers;
usleep($this->DBAvgStatusPoll * $avg_threads);
$total_elapsed += $this->DBAvgStatusPoll * $avg_threads;
} while ( $total_elapsed < $this->DBClusterTimeout );
if ( $i !== false ) {
// slave connection successful
if ( $this->slaveIndex <= 0 && $this->serverLoads[$i] > 0 && $i !== false ) {
$this->slaveIndex = $i;
}
}
return $i;
}
/**
* Returns random non-lagged server
*
* @param Array $loads
* @return int
* @access protected
*/
protected function getRandomNonLagged($loads)
{
// unset excessively lagged servers
$lags = $this->getLagTimes();
foreach ($lags as $i => $lag) {
if ( $i != 0 && isset($this->servers[$i]['DBMaxLag']) ) {
if ( $lag === false ) {
unset( $loads[$i] ); // server is not replicating
}
elseif ( $lag > $this->servers[$i]['DBMaxLag'] ) {
unset( $loads[$i] ); // server is excessively lagged
}
}
}
// find out if all the slaves with non-zero load are lagged
if ( !$loads || array_sum($loads) == 0 ) {
return false;
}
// return a random representative of the remainder
return $this->pickRandom($loads);
}
/**
* Select an element from an array of non-normalised probabilities
*
* @param Array $weights
* @return int
* @access protected
*/
protected function pickRandom($weights)
{
if ( !is_array($weights) || !$weights ) {
return false;
}
$sum = array_sum($weights);
if ( $sum == 0 ) {
return false;
}
$max = mt_getrandmax();
$rand = mt_rand(0, $max) / $max * $sum;
$index = $sum = 0;
foreach ($weights as $index => $weight) {
$sum += $weight;
if ( $sum >= $rand ) {
break;
}
}
return $index;
}
/**
* Get lag time for each server
* Results are cached for a short time in memcached, and indefinitely in the process cache
*
* @return Array
* @access protected
*/
protected function getLagTimes()
{
if ( $this->serverLagTimes ) {
return $this->serverLagTimes;
}
$expiry = 5;
$request_rate = 10;
$cache_key = 'lag_times:' . $this->servers[0]['DBHost'];
$times = $this->Application->getCache($cache_key);
if ( $times ) {
// randomly recache with probability rising over $expiry
$elapsed = adodb_mktime() - $times['timestamp'];
$chance = max(0, ($expiry - $elapsed) * $request_rate);
if ( mt_rand(0, $chance) != 0 ) {
unset( $times['timestamp'] );
$this->serverLagTimes = $times;
return $times;
}
}
// cache key missing or expired
$times = Array();
foreach ($this->servers as $index => $server) {
if ($index == 0) {
$times[$index] = 0; // master
}
else {
$conn =& $this->openConnection($index);
if ($conn !== false) {
$times[$index] = $conn->getSlaveLag();
}
}
}
// add a timestamp key so we know when it was cached
$times['timestamp'] = adodb_mktime();
$this->Application->setCache($cache_key, $times, $expiry);
// but don't give the timestamp to the caller
unset($times['timestamp']);
$this->serverLagTimes = $times;
return $this->serverLagTimes;
}
/**
* Determines whatever server should not be used, even, when connection was made
*
* @param kDBConnection $conn
* @param int $threshold
* @return int
* @access protected
*/
protected function postConnectionBackoff(&$conn, $threshold)
{
if ( !$threshold ) {
return 0;
}
$status = $conn->getStatus('Thread%');
return $status['Threads_running'] > $threshold ? $status['Threads_connected'] : 0;
}
/**
* Open a connection to the server given by the specified index
* Index must be an actual index into the array.
* If the server is already open, returns it.
*
* On error, returns false.
*
* @param integer $i Server index
* @return kDBConnection|false
* @access protected
*/
protected function &openConnection($i)
{
if ( isset($this->connections[$i]) ) {
$conn =& $this->connections[$i];
}
else {
$server = $this->servers[$i];
$server['serverIndex'] = $i;
$conn =& $this->reallyOpenConnection($server, $i == $this->getMasterIndex());
if ( $conn->connectionOpened ) {
$this->connections[$i] =& $conn;
$this->lastUsedIndex = $i;
}
else {
$conn = false;
}
}
if ( $this->nextQueryCachable && is_object($conn) ) {
$conn->nextQueryCachable = true;
$this->nextQueryCachable = false;
}
return $conn;
}
/**
* Checks if connection to the server given by the specified index is opened
*
* @param integer $i Server index
* @return bool
* @access public
*/
public function connectionOpened($i = null)
{
$conn =& $this->openConnection(isset($i) ? $i : $this->getMasterIndex());
return $conn ? $conn->connectionOpened : false;
}
/**
* Really opens a connection.
* Returns a database object whether or not the connection was successful.
*
* @param Array $server
* @param bool $is_master
* @return kDBConnection
*/
protected function &reallyOpenConnection($server, $is_master)
{
$debug_mode = $this->Application->isDebugMode();
$db_class = $debug_mode ? 'kDBConnectionDebug' : 'kDBConnection';
$db = $this->Application->makeClass($db_class, Array ($this->dbType, $this->errorHandler, $server['serverIndex']));
/* @var $db kDBConnection */
$db->debugMode = $debug_mode;
- $db->Connect($server['DBHost'], $server['DBUser'], $server['DBUserPassword'], $this->servers[0]['DBName'], true, !$is_master);
+ $db->Connect($server['DBHost'], $server['DBUser'], $server['DBUserPassword'], $this->servers[0]['DBName'], !$is_master);
return $db;
}
/**
* Returns first field of first line of recordset if query ok or false otherwise
*
* @param string $sql
* @param int $offset
* @return string
* @access public
*/
public function GetOne($sql, $offset = 0)
{
$conn =& $this->chooseConnection($sql);
return $conn->GetOne($sql, $offset);
}
/**
* Returns first row of recordset if query ok, false otherwise
*
* @param string $sql
* @param int $offset
* @return Array
* @access public
*/
public function GetRow($sql, $offset = 0)
{
$conn =& $this->chooseConnection($sql);
return $conn->GetRow($sql, $offset);
}
/**
* Returns 1st column of recordset as one-dimensional array or false otherwise
* Optional parameter $key_field can be used to set field name to be used as resulting array key
*
* @param string $sql
* @param string $key_field
* @return Array
* @access public
*/
public function GetCol($sql, $key_field = null)
{
$conn =& $this->chooseConnection($sql);
return $conn->GetCol($sql, $key_field);
}
/**
* Returns iterator for 1st column of a recordset or false in case of error.
* Optional parameter $key_field can be used to set field name to be used
* as resulting array key.
*
* @param string $sql
* @param string $key_field
* @return bool|kMySQLQueryCol
*/
public function GetColIterator($sql, $key_field = null)
{
$conn =& $this->chooseConnection($sql);
return $conn->GetColIterator($sql, $key_field);
}
/**
* Queries db with $sql query supplied and returns rows selected if any, false
* otherwise. Optional parameter $key_field allows to set one of the query fields
* value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @return Array
* @access public
*/
public function Query($sql, $key_field = null, $no_debug = false)
{
$conn =& $this->chooseConnection($sql);
return $conn->Query($sql, $key_field, $no_debug);
}
/**
* Returns iterator to a recordset, produced from running $sql query Queries db with $sql query supplied and returns kMySQLQuery iterator
* or false in case of error. Optional parameter $key_field allows to
* set one of the query fields value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @param string $iterator_class
* @return kMySQLQuery|bool
* @access public
*/
public function GetIterator($sql, $key_field = null, $no_debug = false, $iterator_class = 'kMySQLQuery')
{
$conn =& $this->chooseConnection($sql);
return $conn->GetIterator($sql, $key_field, $no_debug, $iterator_class);
}
/**
* Performs sql query, that will change database content
*
* @param string $sql
* @return bool
* @access public
*/
public function ChangeQuery($sql)
{
$conn =& $this->chooseConnection($sql);
return $conn->ChangeQuery($sql);
}
/**
* If it's a string, adds quotes and backslashes (only work since PHP 4.3.0)
* Otherwise returns as-is
*
* @param mixed $string
* @return string
* @access public
*/
public function qstr($string)
{
$conn =& $this->openConnection($this->lastUsedIndex);
return $conn->qstr($string);
}
/**
* Calls "qstr" function for each given array element
*
* @param Array $array
* @param string $function
* @return Array
*/
public function qstrArray($array, $function = 'qstr')
{
$conn =& $this->openConnection($this->lastUsedIndex);
return $conn->qstrArray($array, $function);
}
/**
* Performs insert of given data (useful with small number of queries)
* or stores it to perform multiple insert later (useful with large number of queries)
*
* @param Array $fields_hash
* @param string $table
* @param string $type
* @param bool $insert_now
* @return bool
* @access public
*/
public function doInsert($fields_hash, $table, $type = 'INSERT', $insert_now = true)
{
$conn =& $this->openConnection( $this->getMasterIndex() );
return $conn->doInsert($fields_hash, $table, $type, $insert_now);
}
/**
* Update given field values to given record using $key_clause
*
* @param Array $fields_hash
* @param string $table
* @param string $key_clause
* @return bool
* @access public
*/
public function doUpdate($fields_hash, $table, $key_clause)
{
$conn =& $this->openConnection( $this->getMasterIndex() );
return $conn->doUpdate($fields_hash, $table, $key_clause);
}
/**
* When undefined method is called, then send it directly to last used slave server connection
*
* @param string $name
* @param Array $arguments
* @return mixed
* @access public
*/
public function __call($name, $arguments)
{
$conn =& $this->openConnection($this->lastUsedIndex);
return call_user_func_array( Array (&$conn, $name), $arguments );
}
/**
* Returns appropriate connection based on sql
*
* @param string $sql
* @return kDBConnection
* @access protected
*/
protected function &chooseConnection($sql)
{
if ( $this->nextQueryFromMaster ) {
$this->nextQueryFromMaster = false;
$index = $this->getMasterIndex();
}
else {
$sid = isset($this->Application->Session) ? $this->Application->GetSID() : '9999999999999999999999';
if ( preg_match('/(^[ \t\r\n]*(ALTER|CREATE|DROP|RENAME|DELETE|DO|INSERT|LOAD|REPLACE|TRUNCATE|UPDATE))|ses_' . $sid . '/', $sql) ) {
$index = $this->getMasterIndex();
}
else {
$index = $this->getSlaveIndex();
}
}
$this->lastUsedIndex = $index;
$conn =& $this->openConnection($index);
return $conn;
}
}
Index: branches/5.2.x/core/kernel/db/db_connection.php
===================================================================
--- branches/5.2.x/core/kernel/db/db_connection.php (revision 16406)
+++ branches/5.2.x/core/kernel/db/db_connection.php (revision 16407)
@@ -1,1520 +1,1418 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
/**
* Multi database connection class
*
*/
class kDBConnection extends kBase {
/**
- * Current database type
- *
- * @var string
- * @access protected
- */
- protected $dbType = 'mysql';
-
- /**
* Created connection handle
*
- * @var resource
+ * @var mysqli
* @access protected
*/
- protected $connectionID = null;
+ protected $connectionID;
/**
* Remembers, that database connection was opened successfully
*
* @var bool
* @access public
*/
public $connectionOpened = false;
/**
* Connection parameters, that were used
*
* @var Array
* @access protected
*/
protected $connectionParams = Array ('host' => '', 'user' => '', 'pass' => '', 'db' => '');
/**
* Index of database server
*
* @var int
* @access protected
*/
protected $serverIndex = 0;
/**
* Handle of currently processed recordset
*
- * @var resource
+ * @var mysqli_result
* @access protected
*/
protected $queryID = null;
/**
- * DB type specific function mappings
- *
- * @var Array
- * @access protected
- */
- protected $metaFunctions = Array ();
-
- /**
* Function to handle sql errors
*
* @var Array|string
* @access public
*/
public $errorHandler = '';
/**
* Error code
*
* @var int
* @access protected
*/
protected $errorCode = 0;
/**
* Error message
*
* @var string
* @access protected
*/
protected $errorMessage = '';
/**
* Defines if database connection
* operations should generate debug
* information
*
* @var bool
* @access public
*/
public $debugMode = false;
/**
* Save query execution statistics
*
* @var bool
* @access protected
*/
protected $_captureStatistics = false;
/**
* Last query to database
*
* @var string
* @access public
*/
public $lastQuery = '';
/**
* Total processed queries count
*
* @var int
* @access protected
*/
protected $_queryCount = 0;
/**
* Total time, used for serving queries
*
* @var Array
* @access protected
*/
protected $_queryTime = 0;
/**
* Indicates, that next database query could be cached, when memory caching is enabled
*
* @var bool
* @access public
*/
public $nextQueryCachable = false;
/**
* For backwards compatibility with kDBLoadBalancer class
*
* @var bool
* @access public
*/
public $nextQueryFromMaster = false;
/**
* Initializes connection class with
* db type to used in future
*
- * @param string $dbType
- * @param string $errorHandler
+ * @param string $db_type
+ * @param string $error_handler
* @param int $server_index
* @access public
*/
- public function __construct($dbType, $errorHandler = '', $server_index = 0)
+ public function __construct($db_type, $error_handler = '', $server_index = 0)
{
if ( class_exists('kApplication') ) {
// prevents "Fatal Error" on 2nd installation step (when database is empty)
parent::__construct();
}
- $this->dbType = $dbType;
$this->serverIndex = $server_index;
-// $this->initMetaFunctions();
- if (!$errorHandler) {
+ if ( !$error_handler ) {
$this->errorHandler = Array(&$this, 'handleError');
}
else {
- $this->errorHandler = $errorHandler;
+ $this->errorHandler = $error_handler;
}
$this->_captureStatistics = defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !(defined('ADMIN') && ADMIN);
}
/**
* Set's custom error
*
* @param int $code
* @param string $msg
* @access protected
*/
protected function setError($code, $msg)
{
$this->errorCode = $code;
$this->errorMessage = $msg;
}
/**
* Checks if previous query execution
* raised an error.
*
* @return bool
* @access public
*/
public function hasError()
{
return $this->errorCode != 0;
}
/**
- * Caches function specific to requested
- * db type
- *
- * @access protected
- */
- protected function initMetaFunctions()
- {
- $ret = Array ();
-
- switch ( $this->dbType ) {
- case 'mysql':
- $ret = Array (); // only define functions, that name differs from "dbType_<meta_name>"
-
- break;
- }
-
- $this->metaFunctions = $ret;
- }
-
- /**
- * Gets function for specific db type
- * based on it's meta name
- *
- * @param string $name
- * @return string
- * @access protected
- */
- protected function getMetaFunction($name)
- {
- /*if ( !isset($this->metaFunctions[$name]) ) {
- $this->metaFunctions[$name] = $name;
- }*/
-
- return $this->dbType . '_' . $name;
- }
-
-
- /**
* Try to connect to database server
* using specified parameters and set
* database to $db if connection made
*
* @param string $host
* @param string $user
* @param string $pass
* @param string $db
- * @param bool $force_new
- * @param bool $retry
+ * @param bool $retry
+ *
* @return bool
* @access public
*/
- public function Connect($host, $user, $pass, $db, $force_new = false, $retry = false)
+ public function Connect($host, $user, $pass, $db, $retry = false)
{
$this->connectionParams = Array ('host' => $host, 'user' => $user, 'pass' => $pass, 'db' => $db);
- $func = $this->getMetaFunction('connect');
- $this->connectionID = $func($host, $user, $pass, $force_new);
+ $this->setError(0, ''); // reset error
+ $this->connectionID = mysqli_connect($host, $user, $pass, $db);
+ $this->errorCode = mysqli_connect_errno();
- if ($this->connectionID) {
- if (defined('DBG_SQL_MODE')) {
- $this->Query('SET sql_mode = \''.DBG_SQL_MODE.'\'');
+ if ( is_object($this->connectionID) ) {
+ if ( defined('DBG_SQL_MODE') ) {
+ $this->Query('SET SQL_MODE = "' . DBG_SQL_MODE . '"');
}
- if (defined('SQL_COLLATION') && defined('SQL_CHARSET')) {
- $this->Query('SET NAMES \''.SQL_CHARSET.'\' COLLATE \''.SQL_COLLATION.'\'');
+ if ( defined('SQL_COLLATION') && defined('SQL_CHARSET') ) {
+ $this->Query('SET NAMES \'' . SQL_CHARSET . '\' COLLATE \'' . SQL_COLLATION . '\'');
}
- $this->setError(0, ''); // reset error
- $this->setDB($db);
- }
-
- // process error (fatal in most cases)
- $func = $this->getMetaFunction('errno');
- $this->errorCode = $this->connectionID ? $func($this->connectionID) : $func();
-
- if ( is_resource($this->connectionID) && !$this->hasError() ) {
- $this->connectionOpened = true;
+ if ( !$this->hasError() ) {
+ $this->connectionOpened = true;
- return true;
+ return true;
+ }
}
- $func = $this->getMetaFunction('error');
- $this->errorMessage = $this->connectionID ? $func($this->connectionID) : $func();
+ $this->errorMessage = mysqli_connect_error();
$error_msg = 'Database connection failed, please check your connection settings.<br/>Error (' . $this->errorCode . '): ' . $this->errorMessage;
if ( (defined('IS_INSTALL') && IS_INSTALL) || $retry ) {
trigger_error($error_msg, E_USER_WARNING);
}
else {
$this->Application->redirectToMaintenance();
throw new RuntimeException($error_msg);
}
$this->connectionOpened = false;
return false;
}
/**
* Checks if connection to database is opened
*
* @return bool
* @access public
*/
public function connectionOpened()
{
return $this->connectionOpened;
}
/**
* Setups the connection according given configuration
*
* @param Array $config
* @return bool
* @access public
*/
public function setup($config)
{
if ( is_object($this->Application) ) {
$this->debugMode = $this->Application->isDebugMode();
}
return $this->Connect(
$config['Database']['DBHost'],
$config['Database']['DBUser'],
$config['Database']['DBUserPassword'],
$config['Database']['DBName']
);
}
/**
* Performs 3 reconnect attempts in case if connection to a DB was lost in the middle of script run (e.g. server restart)
*
- * @param bool $force_new
* @return bool
* @access protected
*/
- protected function ReConnect($force_new = false)
+ protected function ReConnect()
{
$retry_count = 0;
$connected = false;
- $func = $this->getMetaFunction('close');
- $func($this->connectionID);
+ $this->connectionID->close();
while ( $retry_count < 3 ) {
sleep(5); // wait 5 seconds before each reconnect attempt
$connected = $this->Connect(
$this->connectionParams['host'],
$this->connectionParams['user'],
$this->connectionParams['pass'],
$this->connectionParams['db'],
- $force_new, true
+ true
);
if ( $connected ) {
break;
}
$retry_count++;
}
return $connected;
}
/**
* Shows error message from previous operation
* if it failed
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @return bool
* @access protected
*/
protected function showError($sql = '', $key_field = null, $no_debug = false)
{
static $retry_count = 0;
- $func = $this->getMetaFunction('errno');
-
- if (!$this->connectionID) {
+ if ( !is_object($this->connectionID) ) {
// no connection while doing mysql_query
- $this->errorCode = $func();
+ $this->errorCode = mysqli_connect_errno();
if ( $this->hasError() ) {
- $func = $this->getMetaFunction('error');
- $this->errorMessage = $func();
+ $this->errorMessage = mysqli_connect_error();
$ret = $this->callErrorHandler($sql);
if (!$ret) {
exit;
}
}
return false;
}
// checking if there was an error during last mysql_query
- $this->errorCode = $func($this->connectionID);
+ $this->errorCode = $this->connectionID->errno;
if ( $this->hasError() ) {
- $func = $this->getMetaFunction('error');
- $this->errorMessage = $func($this->connectionID);
+ $this->errorMessage = $this->connectionID->error;
$ret = $this->callErrorHandler($sql);
if ( ($this->errorCode == 2006 || $this->errorCode == 2013) && ($retry_count < 3) ) {
// #2006 - MySQL server has gone away
// #2013 - Lost connection to MySQL server during query
$retry_count++;
if ( $this->ReConnect() ) {
return $this->Query($sql, $key_field, $no_debug);
}
}
if (!$ret) {
exit;
}
}
else {
$retry_count = 0;
}
return false;
}
/**
* Sends db error to a predefined error handler
*
* @param $sql
* @return bool
* @access protected
*/
protected function callErrorHandler($sql)
{
if (is_array($this->errorHandler)) {
$func = $this->errorHandler[1];
$ret = $this->errorHandler[0]->$func($this->errorCode, $this->errorMessage, $sql);
}
else {
$func = $this->errorHandler;
$ret = $func($this->errorCode, $this->errorMessage, $sql);
}
return $ret;
}
/**
* Default error handler for sql errors
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access public
*/
public function handleError($code, $msg, $sql)
{
echo '<strong>Processing SQL</strong>: ' . $sql . '<br/>';
echo '<strong>Error (' . $code . '):</strong> ' . $msg . '<br/>';
return false;
}
/**
- * Set's database name for connection
- * to $new_name
- *
- * @param string $new_name
- * @return bool
- * @access protected
- */
- protected function setDB($new_name)
- {
- if (!$this->connectionID) return false;
- $func = $this->getMetaFunction('select_db');
- return $func($new_name, $this->connectionID);
- }
-
- /**
* Returns first field of first line
* of recordset if query ok or false
* otherwise
*
* @param string $sql
* @param int $offset
* @return string
* @access public
*/
public function GetOne($sql, $offset = 0)
{
$row = $this->GetRow($sql, $offset);
if ( !$row ) {
return false;
}
return array_shift($row);
}
/**
* Returns first row of recordset
* if query ok, false otherwise
*
* @param string $sql
* @param int $offset
* @return Array
* @access public
*/
public function GetRow($sql, $offset = 0)
{
$sql .= ' ' . $this->getLimitClause($offset, 1);
$ret = $this->Query($sql);
if ( !$ret ) {
return false;
}
return array_shift($ret);
}
/**
* Returns 1st column of recordset as
* one-dimensional array or false otherwise
* Optional parameter $key_field can be used
* to set field name to be used as resulting
* array key
*
* @param string $sql
* @param string $key_field
* @return Array
* @access public
*/
public function GetCol($sql, $key_field = null)
{
$rows = $this->Query($sql);
if ( !$rows ) {
return $rows;
}
$i = 0;
$row_count = count($rows);
$ret = Array ();
if ( isset($key_field) ) {
while ( $i < $row_count ) {
$ret[$rows[$i][$key_field]] = array_shift($rows[$i]);
$i++;
}
}
else {
while ( $i < $row_count ) {
$ret[] = array_shift($rows[$i]);
$i++;
}
}
return $ret;
}
/**
* Returns iterator for 1st column of a recordset or false in case of error.
* Optional parameter $key_field can be used to set field name to be used
* as resulting array key.
*
* @param string $sql
* @param string $key_field
* @return bool|kMySQLQueryCol
*/
public function GetColIterator($sql, $key_field = null)
{
return $this->GetIterator($sql, $key_field, false, 'kMySQLQueryCol');
}
/**
* Queries db with $sql query supplied
* and returns rows selected if any, false
* otherwise. Optional parameter $key_field
* allows to set one of the query fields
* value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @return Array
* @access public
*/
public function Query($sql, $key_field = null, $no_debug = false)
{
$this->_queryCount++;
$this->lastQuery = $sql;
- $query_func = $this->getMetaFunction('query');
-
// set 1st checkpoint: begin
$start_time = $this->_captureStatistics ? microtime(true) : 0;
// set 1st checkpoint: end
$this->setError(0, ''); // reset error
- $this->queryID = $query_func($sql, $this->connectionID);
+ $this->queryID = $this->connectionID->query($sql);
- if ( is_resource($this->queryID) ) {
+ if ( is_object($this->queryID) ) {
$ret = Array ();
- $fetch_func = $this->getMetaFunction('fetch_assoc');
if ( isset($key_field) ) {
- while (($row = $fetch_func($this->queryID))) {
+ while ( $row = $this->queryID->fetch_assoc() ) {
$ret[$row[$key_field]] = $row;
}
}
else {
- while (($row = $fetch_func($this->queryID))) {
+ while ( $row = $this->queryID->fetch_assoc() ) {
$ret[] = $row;
}
}
// set 2nd checkpoint: begin
if ( $this->_captureStatistics ) {
$query_time = microtime(true) - $start_time;
if ( $query_time > DBG_MAX_SQL_TIME ) {
$this->Application->logSlowQuery($sql, $query_time);
}
$this->_queryTime += $query_time;
}
// set 2nd checkpoint: end
$this->Destroy();
return $ret;
}
else {
// set 2nd checkpoint: begin
if ( $this->_captureStatistics ) {
$this->_queryTime += microtime(true) - $start_time;
}
// set 2nd checkpoint: end
}
return $this->showError($sql, $key_field, $no_debug);
}
/**
* Returns iterator to a recordset, produced from running $sql query Queries db with $sql query supplied and returns kMySQLQuery iterator
* or false in case of error. Optional parameter $key_field allows to
* set one of the query fields value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @param string $iterator_class
* @return kMySQLQuery|bool
* @access public
*/
public function GetIterator($sql, $key_field = null, $no_debug = false, $iterator_class = 'kMySQLQuery')
{
$this->_queryCount++;
$this->lastQuery = $sql;
- $query_func = $this->getMetaFunction('query');
-
// set 1st checkpoint: begin
$start_time = $this->_captureStatistics ? microtime(true) : 0;
// set 1st checkpoint: end
$this->setError(0, ''); // reset error
- $this->queryID = $query_func($sql, $this->connectionID);
+ $this->queryID = $this->connectionID->query($sql);
- if ( is_resource($this->queryID) ) {
+ if ( is_object($this->queryID) ) {
$ret = new $iterator_class($this->queryID, $key_field);
/* @var $ret kMySQLQuery */
// set 2nd checkpoint: begin
if ( $this->_captureStatistics ) {
$query_time = microtime(true) - $start_time;
if ( $query_time > DBG_MAX_SQL_TIME ) {
$this->Application->logSlowQuery($sql, $query_time);
}
$this->_queryTime += $query_time;
}
// set 2nd checkpoint: end
return $ret;
}
else {
// set 2nd checkpoint: begin
if ( $this->_captureStatistics ) {
$this->_queryTime += microtime(true) - $start_time;
}
// set 2nd checkpoint: end
}
return $this->showError($sql, $key_field, $no_debug);
}
/**
* Free memory used to hold recordset handle
*
* @access public
*/
public function Destroy()
{
- $free_func = $this->getMetaFunction('free_result');
- $free_func($this->queryID);
-
+ $this->queryID->free();
unset($this->queryID);
}
/**
* Performs sql query, that will change database content
*
* @param string $sql
* @return bool
* @access public
*/
public function ChangeQuery($sql)
{
$this->Query($sql);
return !$this->hasError();
}
/**
* Returns auto increment field value from
* insert like operation if any, zero otherwise
*
* @return int
* @access public
*/
public function getInsertID()
{
- $func = $this->getMetaFunction('insert_id');
- return $func($this->connectionID);
+ return $this->connectionID->insert_id;
}
/**
* Returns row count affected by last query
*
* @return int
* @access public
*/
public function getAffectedRows()
{
- $func = $this->getMetaFunction('affected_rows');
- return $func($this->connectionID);
+ return $this->connectionID->affected_rows;
}
/**
* Returns LIMIT sql clause part for specific db
*
* @param int $offset
* @param int $rows
* @return string
* @access public
*/
public function getLimitClause($offset, $rows)
{
if ( !($rows > 0) ) {
return '';
}
- switch ( $this->dbType ) {
- default:
- return 'LIMIT ' . $offset . ',' . $rows;
- break;
- }
+ return 'LIMIT ' . $offset . ',' . $rows;
}
/**
* If it's a string, adds quotes and backslashes (only work since PHP 4.3.0)
* Otherwise returns as-is
*
* @param mixed $string
* @return string
* @access public
*/
public function qstr($string)
{
if ( is_null($string) ) {
return 'NULL';
}
# This will also quote numeric values. This should be harmless,
# and protects against weird problems that occur when they really
# _are_ strings such as article titles and string->number->string
# conversion is not 1:1.
- return "'" . mysql_real_escape_string($string, $this->connectionID) . "'";
+ return "'" . $this->connectionID->real_escape_string($string) . "'";
}
/**
* Calls "qstr" function for each given array element
*
* @param Array $array
* @param string $function
* @return Array
*/
public function qstrArray($array, $function = 'qstr')
{
return array_map(Array (&$this, $function), $array);
}
/**
* Escapes strings (only work since PHP 4.3.0)
*
* @param mixed $string
* @return string
* @access public
*/
public function escape($string)
{
if ( is_null($string) ) {
return 'NULL';
}
- $string = mysql_real_escape_string($string, $this->connectionID);
+ $string = $this->connectionID->real_escape_string($string);
// prevent double-escaping of MySQL wildcard symbols ("%" and "_") in case if they were already escaped
return str_replace(Array ('\\\\%', '\\\\_'), Array ('\\%', '\\_'), $string);
}
/**
* Returns last error code occurred
*
* @return int
* @access public
*/
public function getErrorCode()
{
return $this->errorCode;
}
/**
* Returns last error message
*
* @return string
* @access public
*/
public function getErrorMsg()
{
return $this->errorMessage;
}
/**
* Performs insert of given data (useful with small number of queries)
* or stores it to perform multiple insert later (useful with large number of queries)
*
* @param Array $fields_hash
* @param string $table
* @param string $type
* @param bool $insert_now
* @return bool
* @access public
*/
public function doInsert($fields_hash, $table, $type = 'INSERT', $insert_now = true)
{
static $value_sqls = Array ();
if ($insert_now) {
$fields_sql = '`' . implode('`,`', array_keys($fields_hash)) . '`';
}
$values_sql = '';
foreach ($fields_hash as $field_name => $field_value) {
$values_sql .= $this->qstr($field_value) . ',';
}
// don't use preg here, as it may fail when string is too long
$value_sqls[] = rtrim($values_sql, ',');
$insert_result = true;
if ($insert_now) {
$insert_count = count($value_sqls);
if (($insert_count > 1) && ($value_sqls[$insert_count - 1] == $value_sqls[$insert_count - 2])) {
// last two records are the same
array_pop($value_sqls);
}
$sql = strtoupper($type) . ' INTO `' . $table . '` (' . $fields_sql . ') VALUES (' . implode('),(', $value_sqls) . ')';
$value_sqls = Array (); // reset before query to prevent repeated call from error handler to insert 2 records instead of 1
$insert_result = $this->ChangeQuery($sql);
}
return $insert_result;
}
/**
* Update given field values to given record using $key_clause
*
* @param Array $fields_hash
* @param string $table
* @param string $key_clause
* @return bool
* @access public
*/
public function doUpdate($fields_hash, $table, $key_clause)
{
if (!$fields_hash) return true;
$fields_sql = '';
foreach ($fields_hash as $field_name => $field_value) {
$fields_sql .= '`'.$field_name.'` = ' . $this->qstr($field_value) . ',';
}
// don't use preg here, as it may fail when string is too long
$fields_sql = rtrim($fields_sql, ',');
$sql = 'UPDATE `'.$table.'` SET '.$fields_sql.' WHERE '.$key_clause;
return $this->ChangeQuery($sql);
}
/**
* Allows to detect table's presence in database
*
* @param string $table_name
* @param bool $force
* @return bool
* @access public
*/
public function TableFound($table_name, $force = false)
{
static $table_found = false;
if ( $table_found === false ) {
$table_found = array_flip($this->GetCol('SHOW TABLES'));
}
if ( !preg_match('/^' . preg_quote(TABLE_PREFIX, '/') . '(.*)/', $table_name) ) {
$table_name = TABLE_PREFIX . $table_name;
}
if ( $force ) {
if ( $this->Query('SHOW TABLES LIKE ' . $this->qstr($table_name)) ) {
$table_found[$table_name] = 1;
}
else {
unset($table_found[$table_name]);
}
}
return isset($table_found[$table_name]);
}
/**
* Returns query processing statistics
*
* @return Array
* @access public
*/
public function getQueryStatistics()
{
return Array ('time' => $this->_queryTime, 'count' => $this->_queryCount);
}
/**
* Get status information from SHOW STATUS in an associative array
*
* @param string $which
* @return Array
* @access public
*/
public function getStatus($which = '%')
{
$status = Array ();
$records = $this->Query('SHOW STATUS LIKE "' . $which . '"');
foreach ($records as $record) {
$status[ $record['Variable_name'] ] = $record['Value'];
}
return $status;
}
/**
* Get slave replication lag. It will only work if the DB user has the PROCESS privilege.
*
* @return int
* @access public
*/
public function getSlaveLag()
{
// don't use kDBConnection::Query method, since it will create an array of all server processes
$processes = $this->GetIterator('SHOW PROCESSLIST');
$skip_states = Array (
'Waiting for master to send event',
'Connecting to master',
'Queueing master event to the relay log',
'Waiting for master update',
'Requesting binlog dump',
);
// find slave SQL thread
foreach ($processes as $process) {
if ( $process['User'] == 'system user' && !in_array($process['State'], $skip_states) ) {
// this is it, return the time (except -ve)
return $process['Time'] > 0x7fffffff ? false : $process['Time'];
}
}
return false;
}
}
class kDBConnectionDebug extends kDBConnection {
protected $_profileSQLs = false;
/**
* Info about this database connection to show in debugger report
*
* @var string
* @access protected
*/
protected $serverInfoLine = '';
/**
* Initializes connection class with
* db type to used in future
*
- * @param string $dbType
- * @param string $errorHandler
+ * @param string $db_type
+ * @param string $error_handler
* @param int $server_index
* @access public
*/
- public function __construct($dbType, $errorHandler = '', $server_index = 0)
+ public function __construct($db_type, $error_handler = '', $server_index = 0)
{
- parent::__construct($dbType, $errorHandler, $server_index);
+ parent::__construct($db_type, $error_handler, $server_index);
$this->_profileSQLs = defined('DBG_SQL_PROFILE') && DBG_SQL_PROFILE;
}
/**
* Try to connect to database server
* using specified parameters and set
* database to $db if connection made
*
* @param string $host
* @param string $user
* @param string $pass
* @param string $db
* @param bool $force_new
* @param bool $retry
* @return bool
* @access public
*/
public function Connect($host, $user, $pass, $db, $force_new = false, $retry = false)
{
if ( defined('DBG_SQL_SERVERINFO') && DBG_SQL_SERVERINFO ) {
$this->serverInfoLine = $this->serverIndex . ' (' . $host . ')';
}
return parent::Connect($host, $user, $pass, $db, $force_new, $retry);
}
/**
* Queries db with $sql query supplied
* and returns rows selected if any, false
* otherwise. Optional parameter $key_field
* allows to set one of the query fields
* value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @return Array
* @access public
*/
public function Query($sql, $key_field = null, $no_debug = false)
{
if ( $no_debug ) {
return parent::Query($sql, $key_field, $no_debug);
}
global $debugger;
$this->_queryCount++;
$this->lastQuery = $sql;
- $query_func = $this->getMetaFunction('query');
-
// set 1st checkpoint: begin
if ( $this->_profileSQLs ) {
$queryID = $debugger->generateID();
$debugger->profileStart('sql_' . $queryID, $debugger->formatSQL($sql));
}
// set 1st checkpoint: end
$this->setError(0, ''); // reset error
- $this->queryID = $query_func($sql, $this->connectionID);
+ $this->queryID = $this->connectionID->query($sql);
- if ( is_resource($this->queryID) ) {
+ if ( is_object($this->queryID) ) {
$ret = Array ();
- $fetch_func = $this->getMetaFunction('fetch_assoc');
if ( isset($key_field) ) {
- while (($row = $fetch_func($this->queryID))) {
+ while ( $row = $this->queryID->fetch_assoc() ) {
$ret[$row[$key_field]] = $row;
}
}
else {
- while (($row = $fetch_func($this->queryID))) {
+ while ( $row = $this->queryID->fetch_assoc() ) {
$ret[] = $row;
}
}
// set 2nd checkpoint: begin
if ( $this->_profileSQLs ) {
$current_element = current($ret);
$first_cell = count($ret) == 1 && count($current_element) == 1 ? current($current_element) : null;
if ( strlen($first_cell) > 200 ) {
$first_cell = substr($first_cell, 0, 50) . ' ...';
}
$debugger->profileFinish('sql_' . $queryID, null, null, $this->getAffectedRows(), $first_cell, $this->_queryCount, $this->nextQueryCachable, $this->serverInfoLine);
$debugger->profilerAddTotal('sql', 'sql_' . $queryID);
$this->nextQueryCachable = false;
}
// set 2nd checkpoint: end
$this->Destroy();
return $ret;
}
else {
// set 2nd checkpoint: begin
if ( $this->_profileSQLs ) {
$debugger->profileFinish('sql_' . $queryID, null, null, $this->getAffectedRows(), null, $this->_queryCount, $this->nextQueryCachable, $this->serverInfoLine);
$debugger->profilerAddTotal('sql', 'sql_' . $queryID);
$this->nextQueryCachable = false;
}
// set 2nd checkpoint: end
}
return $this->showError($sql, $key_field);
}
/**
* Queries db with $sql query supplied and returns kMySQLQuery iterator
* or false in case of error. Optional parameter $key_field allows to
* set one of the query fields value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @param string $iterator_class
* @return kMySQLQuery|bool
* @access public
*/
public function GetIterator($sql, $key_field = null, $no_debug = false, $iterator_class = 'kMySQLQuery')
{
if ( $no_debug ) {
return parent::Query($sql, $key_field, $no_debug, $iterator_class);
}
global $debugger;
$this->_queryCount++;
$this->lastQuery = $sql;
- $query_func = $this->getMetaFunction('query');
-
// set 1st checkpoint: begin
if ( $this->_profileSQLs ) {
$queryID = $debugger->generateID();
$debugger->profileStart('sql_' . $queryID, $debugger->formatSQL($sql));
}
// set 1st checkpoint: end
$this->setError(0, ''); // reset error
- $this->queryID = $query_func($sql, $this->connectionID);
+ $this->queryID = $this->connectionID->query($sql);
- if ( is_resource($this->queryID) ) {
+ if ( is_object($this->queryID) ) {
$ret = new $iterator_class($this->queryID, $key_field);
/* @var $ret kMySQLQuery */
// set 2nd checkpoint: begin
if ( $this->_profileSQLs ) {
$first_cell = count($ret) == 1 && $ret->fieldCount() == 1 ? current($ret->current()) : null;
if ( strlen($first_cell) > 200 ) {
$first_cell = substr($first_cell, 0, 50) . ' ...';
}
$debugger->profileFinish('sql_' . $queryID, null, null, $this->getAffectedRows(), $first_cell, $this->_queryCount, $this->nextQueryCachable, $this->serverInfoLine);
$debugger->profilerAddTotal('sql', 'sql_' . $queryID);
$this->nextQueryCachable = false;
}
// set 2nd checkpoint: end
return $ret;
}
else {
// set 2nd checkpoint: begin
if ( $this->_profileSQLs ) {
$debugger->profileFinish('sql_' . $queryID, null, null, $this->getAffectedRows(), null, $this->_queryCount, $this->nextQueryCachable, $this->serverInfoLine);
$debugger->profilerAddTotal('sql', 'sql_' . $queryID);
$this->nextQueryCachable = false;
}
// set 2nd checkpoint: end
}
return $this->showError($sql, $key_field);
}
}
class kMySQLQuery implements Iterator, Countable, SeekableIterator {
/**
* Current index in recordset
*
* @var int
* @access protected
*/
protected $position = -1;
/**
* Query resource
*
- * @var resource
+ * @var mysqli_result
* @access protected
*/
protected $result;
/**
* Field to act as key in a resulting array
*
* @var string
* @access protected
*/
protected $keyField = null;
/**
* Data in current row of recordset
*
* @var Array
* @access protected
*/
protected $rowData = Array ();
/**
* Row count in a result
*
* @var int
* @access protected
*/
protected $rowCount = 0;
/**
* Creates new instance of a class
*
- * @param resource $result
+ * @param mysqli_result $result
* @param null|string $key_field
*/
- public function __construct($result, $key_field = null)
+ public function __construct(mysqli_result $result, $key_field = null)
{
$this->result = $result;
$this->keyField = $key_field;
- $this->rowCount = mysql_num_rows($this->result);
+ $this->rowCount = $this->result->num_rows;
$this->rewind();
}
/**
* Moves recordset pointer to first element
*
* @return void
* @access public
* @implements Iterator::rewind
*/
public function rewind()
{
$this->seek(0);
}
/**
* Returns value at current position
*
* @return mixed
* @access public
* @implements Iterator::current
*/
function current()
{
return $this->rowData;
}
/**
* Returns key at current position
*
* @return mixed
* @access public
* @implements Iterator::key
*/
function key()
{
return $this->keyField ? $this->rowData[$this->keyField] : $this->position;
}
/**
* Moves recordset pointer to next position
*
* @return void
* @access public
* @implements Iterator::next
*/
function next()
{
$this->seek($this->position + 1);
}
/**
* Detects if current position is within recordset bounds
*
* @return bool
* @access public
* @implements Iterator::valid
*/
public function valid()
{
return $this->position < $this->rowCount;
}
/**
* Counts recordset rows
*
* @return int
* @access public
* @implements Countable::count
*/
public function count()
{
return $this->rowCount;
}
/**
* Counts fields in current row
*
* @return int
* @access public
*/
public function fieldCount()
{
return count($this->rowData);
}
/**
* Moves cursor into given position within recordset
*
* @param int $position
* @throws OutOfBoundsException
* @access public
* @implements SeekableIterator::seek
*/
public function seek($position)
{
if ( $this->position == $position ) {
return;
}
$this->position = $position;
if ( $this->valid() ) {
- mysql_data_seek($this->result, $this->position);
+ $this->result->data_seek($this->position);
- $this->rowData = mysql_fetch_assoc($this->result);
+ $this->rowData = $this->result->fetch_assoc();
}
/*if ( !$this->valid() ) {
throw new OutOfBoundsException('Invalid seek position (' . $position . ')');
}*/
}
/**
* Returns first recordset row
*
* @return Array
* @access public
*/
public function first()
{
$this->seek(0);
return $this->rowData;
}
/**
* Closes recordset and freese memory
*
* @return void
* @access public
*/
public function close()
{
- mysql_free_result($this->result);
+ $this->result->free();
unset($this->result);
}
/**
* Frees memory when object is destroyed
*
* @return void
* @access public
*/
public function __destruct()
{
$this->close();
}
/**
* Returns all keys
*
* @return Array
* @access public
*/
public function keys()
{
$ret = Array ();
foreach ($this as $key => $value) {
$ret[] = $key;
}
return $ret;
}
/**
* Returns all values
*
* @return Array
* @access public
*/
public function values()
{
$ret = Array ();
foreach ($this as $value) {
$ret[] = $value;
}
return $ret;
}
/**
* Returns whole recordset as array
*
* @return Array
* @access public
*/
public function toArray()
{
$ret = Array ();
foreach ($this as $key => $value) {
$ret[$key] = $value;
}
return $ret;
}
}
class kMySQLQueryCol extends kMySQLQuery {
/**
* Returns value at current position
*
* @return mixed
* @access public
* @implements Iterator::current
*/
function current()
{
return reset($this->rowData);
}
/**
* Returns first column of first recordset row
*
* @return string
* @access public
*/
public function first()
{
$this->seek(0);
return reset($this->rowData);
}
}
Index: branches/5.2.x/core/kernel/startup.php
===================================================================
--- branches/5.2.x/core/kernel/startup.php (revision 16406)
+++ branches/5.2.x/core/kernel/startup.php (revision 16407)
@@ -1,211 +1,211 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
define('KERNEL_PATH', FULL_PATH . '/core/kernel');
$globals_start = microtime(true);
include_once(KERNEL_PATH . '/globals.php'); // some non-OOP functions and kUtil static class used through kernel
include_once(KERNEL_PATH . '/utility/multibyte.php'); // emulating multi-byte php extension
$globals_end = microtime(true);
$vars = kUtil::getConfigVars();
$charset = isset($vars['WebsiteCharset']) ? $vars['WebsiteCharset'] : 'utf-8';
define('CHARSET', $charset);
$admin_directory = isset($vars['AdminDirectory']) ? $vars['AdminDirectory'] : '/admin';
define('ADMIN_DIRECTORY', $admin_directory);
$admin_Presets_directory = isset($vars['AdminPresetsDirectory']) ? $vars['AdminPresetsDirectory'] : ADMIN_DIRECTORY;
define('ADMIN_PRESETS_DIRECTORY', $admin_Presets_directory);
$https_mark = getArrayValue($_SERVER, 'HTTPS');
define('PROTOCOL', ($https_mark == 'on') || ($https_mark == '1') ? 'https://' : 'http://');
if ( isset($_SERVER['HTTP_HOST']) ) {
// accessed from browser
$http_host = $_SERVER['HTTP_HOST'];
}
else {
// accessed from command line
$http_host = $vars['Domain'];
$_SERVER['HTTP_HOST'] = $vars['Domain'];
}
$port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : false;
if ($port) {
if ( (PROTOCOL == 'http://' && $port != '80') || (PROTOCOL == 'https://' && $port != '443') ) {
// if non-standard port is used, then define it
define('PORT', $port);
}
$http_host = preg_replace('/:' . $port . '$/', '', $http_host);
}
define('SERVER_NAME', $http_host);
if (!$vars) {
echo 'In-Portal is probably not installed, or configuration file is missing.<br/>';
echo 'Please use the installation script to fix the problem.<br/><br/>';
$base_path = rtrim(preg_replace('/'.preg_quote(rtrim($admin_directory, '/'), '/').'$/', '', str_replace('\\', '/', dirname($_SERVER['PHP_SELF']))), '/');
echo '<a href="' . PROTOCOL . SERVER_NAME . $base_path . '/core/install.php">Go to installation script</a><br><br>';
flush();
exit;
}
if ( !file_exists(FULL_PATH . '/vendor/autoload.php') ) {
echo 'Cannot find an "/vendor/autoload.php" file, have you executed "composer install" command?<br/>';
flush();
exit;
}
// variable WebsitePath is auto-detected once during installation/upgrade
define('BASE_PATH', $vars['WebsitePath']);
define('APPLICATION_CLASS', isset($vars['ApplicationClass']) ? $vars['ApplicationClass'] : 'kApplication');
define('APPLICATION_PATH', isset($vars['ApplicationPath']) ? $vars['ApplicationPath'] : '/core/kernel/application.php');
if (isset($vars['WriteablePath'])) {
define('WRITEABLE', FULL_PATH . $vars['WriteablePath']);
define('WRITEBALE_BASE', $vars['WriteablePath']);
}
if ( isset($vars['RestrictedPath']) ) {
define('RESTRICTED', FULL_PATH . $vars['RestrictedPath']);
}
define('SQL_TYPE', $vars['DBType']);
define('SQL_SERVER', $vars['DBHost']);
define('SQL_USER', $vars['DBUser']);
define('SQL_PASS', $vars['DBUserPassword']);
define('SQL_DB', $vars['DBName']);
if (isset($vars['DBCollation']) && isset($vars['DBCharset'])) {
- define('SQL_COLLATION', $vars['DBCollation']);
- define('SQL_CHARSET', $vars['DBCharset']);
+ define('SQL_COLLATION', $vars['DBCollation']); // utf8_general_ci
+ define('SQL_CHARSET', $vars['DBCharset']); // utf8
}
define('TABLE_PREFIX', $vars['TablePrefix']);
define('DOMAIN', getArrayValue($vars, 'Domain'));
ini_set('memory_limit', '50M');
define('MODULES_PATH', FULL_PATH . DIRECTORY_SEPARATOR . 'modules');
define('EXPORT_BASE_PATH', WRITEBALE_BASE . '/export');
define('EXPORT_PATH', FULL_PATH . EXPORT_BASE_PATH);
define('GW_CLASS_PATH', MODULES_PATH . '/in-commerce/units/gateways/gw_classes'); // Payment Gateway Classes Path
define('SYNC_CLASS_PATH', FULL_PATH . '/sync'); // path for 3rd party user syncronization scripts
define('ENV_VAR_NAME','env');
define('IMAGES_PATH', WRITEBALE_BASE . '/images/');
define('IMAGES_PENDING_PATH', IMAGES_PATH . 'pending/');
define('MAX_UPLOAD_SIZE', min(ini_get('upload_max_filesize'), ini_get('post_max_size'))*1024*1024);
define('EDITOR_PATH', isset($vars['EditorPath']) ? $vars['EditorPath'] : '/core/ckeditor/');
// caching types
define('CACHING_TYPE_NONE', 0);
define('CACHING_TYPE_MEMORY', 1);
define('CACHING_TYPE_TEMPORARY', 2);
class CacheSettings {
static public $unitCacheRebuildTime;
static public $structureTreeRebuildTime;
static public $cmsMenuRebuildTime;
static public $templateMappingRebuildTime;
static public $sectionsParsedRebuildTime;
static public $domainsParsedRebuildTime;
}
CacheSettings::$unitCacheRebuildTime = isset($vars['UnitCacheRebuildTime']) ? $vars['UnitCacheRebuildTime'] : 10;
CacheSettings::$structureTreeRebuildTime = isset($vars['StructureTreeRebuildTime']) ? $vars['StructureTreeRebuildTime'] : 10;
CacheSettings::$cmsMenuRebuildTime = isset($vars['CmsMenuRebuildTime']) ? $vars['CmsMenuRebuildTime'] : 10;
CacheSettings::$templateMappingRebuildTime = isset($vars['TemplateMappingRebuildTime']) ? $vars['TemplateMappingRebuildTime'] : 5;
CacheSettings::$sectionsParsedRebuildTime = isset($vars['SectionsParsedRebuildTime']) ? $vars['SectionsParsedRebuildTime'] : 10;
CacheSettings::$domainsParsedRebuildTime = isset($vars['DomainsParsedRebuildTime']) ? $vars['DomainsParsedRebuildTime'] : 2;
class MaintenanceMode {
const NONE = 0;
const SOFT = 1;
const HARD = 2;
}
unset($vars); // just in case someone will be still using it
if (ini_get('safe_mode')) {
// safe mode will be removed at all in PHP6
define('SAFE_MODE', 1);
}
if (file_exists(WRITEABLE . '/debug.php')) {
include_once(WRITEABLE . '/debug.php');
if (array_key_exists('DEBUG_MODE', $dbg_options) && $dbg_options['DEBUG_MODE']) {
$debugger_start = microtime(true);
include_once(KERNEL_PATH . '/utility/debugger.php');
$debugger_end = microtime(true);
if (isset($debugger) && kUtil::constOn('DBG_PROFILE_INCLUDES')) {
$debugger->profileStart('inc_globals', KERNEL_PATH . '/globals.php', $globals_start);
$debugger->profileFinish('inc_globals', KERNEL_PATH . '/globals.php', $globals_end);
$debugger->profilerAddTotal('includes', 'inc_globals');
$debugger->profileStart('inc_debugger', KERNEL_PATH . '/utility/debugger.php', $debugger_start);
$debugger->profileFinish('inc_debugger', KERNEL_PATH . '/utility/debugger.php', $debugger_end);
$debugger->profilerAddTotal('includes', 'inc_debugger');
}
}
}
kUtil::safeDefine('SILENT_LOG', 0); // can be set in "debug.php" too
$includes = Array(
KERNEL_PATH . "/interfaces/cacheable.php",
KERNEL_PATH . '/application.php',
FULL_PATH . APPLICATION_PATH,
KERNEL_PATH . "/kbase.php",
KERNEL_PATH . '/db/db_connection.php',
KERNEL_PATH . '/db/db_load_balancer.php',
KERNEL_PATH . '/utility/event.php',
KERNEL_PATH . '/utility/logger.php',
KERNEL_PATH . "/utility/factory.php",
KERNEL_PATH . "/languages/phrases_cache.php",
KERNEL_PATH . "/db/dblist.php",
KERNEL_PATH . "/db/dbitem.php",
KERNEL_PATH . "/event_handler.php",
KERNEL_PATH . '/db/db_event_handler.php',
FULL_PATH . '/vendor/autoload.php',
);
foreach ($includes as $a_file) {
kUtil::includeOnce($a_file);
}
if (defined('DEBUG_MODE') && DEBUG_MODE && isset($debugger)) {
$debugger->AttachToApplication();
}
if( !function_exists('adodb_mktime') ) {
include_once(KERNEL_PATH . '/utility/adodb-time.inc.php');
}
// system users
define('USER_ROOT', -1);
define('USER_GUEST', -2);
Index: branches/5.2.x/core/kernel/utility/temp_handler.php
===================================================================
--- branches/5.2.x/core/kernel/utility/temp_handler.php (revision 16406)
+++ branches/5.2.x/core/kernel/utility/temp_handler.php (revision 16407)
@@ -1,1057 +1,1057 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kTempTablesHandler extends kBase {
var $Tables = Array();
/**
* Master table name for temp handler
*
* @var string
* @access private
*/
var $MasterTable = '';
/**
* IDs from master table
*
* @var Array
* @access private
*/
var $MasterIDs = Array();
var $AlreadyProcessed = Array();
var $DroppedTables = Array();
var $FinalRefs = Array();
var $TableIdCounter = 0;
var $CopiedTables = Array();
/**
* Foreign key cache
*
* @var Array
*/
var $FKeysCache = Array ();
/**
* IDs of newly cloned items (key - prefix.special, value - array of ids)
*
* @var Array
*/
var $savedIDs = Array();
/**
* Window ID of current window
*
* @var mixed
*/
var $WindowID = '';
/**
* Event, that was used to create this object
*
* @var kEvent
* @access protected
*/
protected $parentEvent = null;
/**
* Sets new parent event to the object
*
* @param kEvent $event
* @return void
* @access public
*/
public function setParentEvent($event)
{
$this->parentEvent = $event;
}
function SetTables($tables)
{
// set table name as key for tables array
$this->Tables = $tables;
$this->MasterTable = $tables['TableName'];
}
function saveID($prefix, $special = '', $id = null)
{
if (!isset($this->savedIDs[$prefix.($special ? '.' : '').$special])) {
$this->savedIDs[$prefix.($special ? '.' : '').$special] = array();
}
if (is_array($id)) {
foreach ($id as $tmp_id => $live_id) {
$this->savedIDs[$prefix.($special ? '.' : '').$special][$tmp_id] = $live_id;
}
}
else {
$this->savedIDs[$prefix.($special ? '.' : '').$special][] = $id;
}
}
/**
* Get temp table name
*
* @param string $table
* @return string
*/
function GetTempName($table)
{
return $this->Application->GetTempName($table, $this->WindowID);
}
function GetTempTablePrefix()
{
return $this->Application->GetTempTablePrefix($this->WindowID);
}
/**
* Return live table name based on temp table name
*
* @param string $temp_table
* @return string
*/
function GetLiveName($temp_table)
{
return $this->Application->GetLiveName($temp_table);
}
function IsTempTable($table)
{
return $this->Application->IsTempTable($table);
}
/**
* Return temporary table name for master table
*
* @return string
* @access public
*/
function GetMasterTempName()
{
return $this->GetTempName($this->MasterTable);
}
function CreateTempTable($table)
{
$sql = 'CREATE TABLE ' . $this->GetTempName($table) . '
SELECT *
FROM ' . $table . '
WHERE 0';
$this->Conn->Query($sql);
}
function BuildTables($prefix, $ids)
{
$this->WindowID = $this->Application->GetVar('m_wid');
$this->TableIdCounter = 0;
$tables = Array(
'TableName' => $this->Application->getUnitOption($prefix, 'TableName'),
'IdField' => $this->Application->getUnitOption($prefix, 'IDField'),
'IDs' => $ids,
'Prefix' => $prefix,
'TableId' => $this->TableIdCounter++,
);
/*$parent_prefix = $this->Application->getUnitOption($prefix, 'ParentPrefix');
if ($parent_prefix) {
$tables['ForeignKey'] = $this->Application->getUnitOption($prefix, 'ForeignKey');
$tables['ParentPrefix'] = $parent_prefix;
$tables['ParentTableKey'] = $this->Application->getUnitOption($prefix, 'ParentTableKey');
}*/
$this->FinalRefs[ $tables['TableName'] ] = $tables['TableId']; // don't forget to add main table to FinalRefs too
$sub_items = $this->Application->getUnitOption($prefix, 'SubItems', Array ());
/* @var $sub_items Array */
if ( is_array($sub_items) ) {
foreach ($sub_items as $prefix) {
$this->AddTables($prefix, $tables);
}
}
$this->SetTables($tables);
}
/**
* Searches through TempHandler tables info for required prefix
*
* @param string $prefix
* @param Array $master
* @return mixed
*/
function SearchTable($prefix, $master = null)
{
if (is_null($master)) {
$master = $this->Tables;
}
if ($master['Prefix'] == $prefix) {
return $master;
}
if (isset($master['SubTables'])) {
foreach ($master['SubTables'] as $sub_table) {
$found = $this->SearchTable($prefix, $sub_table);
if ($found !== false) {
return $found;
}
}
}
return false;
}
function AddTables($prefix, &$tables)
{
if ( !$this->Application->prefixRegistred($prefix) ) {
// allows to skip subitem processing if subitem module not enabled/installed
return ;
}
$tmp = Array(
'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
'ForeignKey' => $this->Application->getUnitOption($prefix,'ForeignKey'),
'ParentPrefix' => $this->Application->getUnitOption($prefix, 'ParentPrefix'),
'ParentTableKey' => $this->Application->getUnitOption($prefix,'ParentTableKey'),
'Prefix' => $prefix,
'AutoClone' => $this->Application->getUnitOption($prefix,'AutoClone'),
'AutoDelete' => $this->Application->getUnitOption($prefix,'AutoDelete'),
'TableId' => $this->TableIdCounter++,
);
$this->FinalRefs[ $tmp['TableName'] ] = $tmp['TableId'];
$constrain = $this->Application->getUnitOption($prefix, 'Constrain');
if ( $constrain ) {
$tmp['Constrain'] = $constrain;
$this->FinalRefs[ $tmp['TableName'] . $tmp['Constrain'] ] = $tmp['TableId'];
}
$sub_items = $this->Application->getUnitOption($prefix, 'SubItems', Array ());
/* @var $sub_items Array */
if ( is_array($sub_items) ) {
foreach ($sub_items as $prefix) {
$this->AddTables($prefix, $tmp);
}
}
if ( !is_array(getArrayValue($tables, 'SubTables')) ) {
$tables['SubTables'] = Array ();
}
$tables['SubTables'][] = $tmp;
}
function CloneItems($prefix, $special, $ids, $master = null, $foreign_key = null, $parent_prefix = null, $skip_filenames = false)
{
if (!isset($master)) $master = $this->Tables;
// recalling by different name, because we may get kDBList, if we recall just by prefix
if (!preg_match('/(.*)-item$/', $special)) {
$special .= '-item';
}
$object = $this->Application->recallObject($prefix.'.'.$special, $prefix, Array('skip_autoload' => true, 'parent_event' => $this->parentEvent));
/* @var $object kCatDBItem */
$object->PopulateMultiLangFields();
foreach ($ids as $id) {
$mode = 'create';
$cloned_ids = getArrayValue($this->AlreadyProcessed, $master['TableName']);
if ( $cloned_ids ) {
// if we have already cloned the id, replace it with cloned id and set mode to update
// update mode is needed to update second ForeignKey for items cloned by first ForeignKey
if ( getArrayValue($cloned_ids, $id) ) {
$id = $cloned_ids[$id];
$mode = 'update';
}
}
$object->Load($id);
$original_values = $object->GetFieldValues();
if (!$skip_filenames) {
$object->NameCopy($master, $foreign_key);
}
elseif ($master['TableName'] == $this->MasterTable) {
// kCatDBItem class only has this attribute
$object->useFilenames = false;
}
if (isset($foreign_key)) {
$master_foreign_key_field = is_array($master['ForeignKey']) ? $master['ForeignKey'][$parent_prefix] : $master['ForeignKey'];
$object->SetDBField($master_foreign_key_field, $foreign_key);
}
if ($mode == 'create') {
$this->RaiseEvent('OnBeforeClone', $master['Prefix'], $special, Array($object->GetId()), $foreign_key);
}
$object->inCloning = true;
$res = $mode == 'update' ? $object->Update() : $object->Create();
$object->inCloning = false;
if ($res)
{
if ( $mode == 'create' && is_array( getArrayValue($master, 'ForeignKey')) ) {
// remember original => clone mapping for dual ForeignKey updating
$this->AlreadyProcessed[$master['TableName']][$id] = $object->GetId();
}
if ($mode == 'create') {
$this->RaiseEvent('OnAfterClone', $master['Prefix'], $special, Array($object->GetId()), $foreign_key, array('original_id' => $id) );
$this->saveID($master['Prefix'], $special, $object->GetID());
}
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach($master['SubTables'] as $sub_table) {
if (!getArrayValue($sub_table, 'AutoClone')) continue;
$sub_TableName = $object->IsTempTable() ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
$foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
if (!$foreign_key_field || !$parent_key_field) continue;
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$sub_ids = $this->Conn->GetCol($query);
if ( is_array(getArrayValue($sub_table, 'ForeignKey')) ) {
// $sub_ids could containt newly cloned items, we need to remove it here
// to escape double cloning
$cloned_ids = getArrayValue($this->AlreadyProcessed, $sub_table['TableName']);
if ( !$cloned_ids ) $cloned_ids = Array();
$new_ids = array_values($cloned_ids);
$sub_ids = array_diff($sub_ids, $new_ids);
}
$parent_key = $object->GetDBField($parent_key_field);
$this->CloneItems($sub_table['Prefix'], $special, $sub_ids, $sub_table, $parent_key, $master['Prefix']);
}
}
}
}
if (!$ids) {
$this->savedIDs[$prefix.($special ? '.' : '').$special] = Array();
}
return $this->savedIDs[$prefix.($special ? '.' : '').$special];
}
function DeleteItems($prefix, $special, $ids, $master=null, $foreign_key=null)
{
if ( !$ids ) {
return;
}
if ( !isset($master) ) {
$master = $this->Tables;
}
if ( strpos($prefix, '.') !== false ) {
list($prefix, $special) = explode('.', $prefix, 2);
}
$prefix_special = rtrim($prefix . '.' . $special, '.');
//recalling by different name, because we may get kDBList, if we recall just by prefix
$recall_prefix = $prefix_special . ($special ? '' : '.') . '-item';
$object = $this->Application->recallObject($recall_prefix, $prefix, Array ('skip_autoload' => true, 'parent_event' => $this->parentEvent));
/* @var $object kDBItem */
foreach ($ids as $id) {
$object->Load($id);
$original_values = $object->GetFieldValues();
if ( !$object->Delete($id) ) {
continue;
}
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach ($master['SubTables'] as $sub_table) {
if ( !getArrayValue($sub_table, 'AutoDelete') ) {
continue;
}
$sub_TableName = $object->IsTempTable() ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? getArrayValue($sub_table, 'ParentTableKey', $master['Prefix']) : $sub_table['ParentTableKey'];
if ( !$foreign_key_field || !$parent_key_field ) {
continue;
}
$sql = 'SELECT ' . $sub_table['IdField'] . '
FROM ' . $sub_TableName . '
WHERE ' . $foreign_key_field . ' = ' . $original_values[$parent_key_field];
$sub_ids = $this->Conn->GetCol($sql);
$parent_key = $object->GetDBField(is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$prefix] : $sub_table['ParentTableKey']);
$this->DeleteItems($sub_table['Prefix'], $special, $sub_ids, $sub_table, $parent_key);
}
}
}
}
function DoCopyLiveToTemp($master, $ids, $parent_prefix=null)
{
// when two tables refers the same table as sub-sub-table, and ForeignKey and ParentTableKey are arrays
// the table will be first copied by first sub-table, then dropped and copied over by last ForeignKey in the array
// this should not do any problems :)
if ( !preg_match("/.*\.[0-9]+/", $master['Prefix']) ) {
if( $this->DropTempTable($master['TableName']) )
{
$this->CreateTempTable($master['TableName']);
}
}
if (is_array($ids)) {
$ids = join(',', $ids);
}
$table_sig = $master['TableName'].(isset($master['Constrain']) ? $master['Constrain'] : '');
if ($ids != '' && !in_array($table_sig, $this->CopiedTables)) {
if ( getArrayValue($master, 'ForeignKey') ) {
if ( is_array($master['ForeignKey']) ) {
$key_field = $master['ForeignKey'][$parent_prefix];
}
else {
$key_field = $master['ForeignKey'];
}
}
else {
$key_field = $master['IdField'];
}
$query = 'INSERT INTO '.$this->GetTempName($master['TableName']).'
SELECT * FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
$query = 'SELECT '.$master['IdField'].' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->RaiseEvent( 'OnAfterCopyToTemp', $master['Prefix'], '', $this->Conn->GetCol($query) );
}
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$parent_key = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
if (!$parent_key) continue;
if ( $ids != '' && $parent_key != $key_field ) {
$query = 'SELECT '.$parent_key.' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
$sub_foreign_keys = join(',', $this->Conn->GetCol($query));
}
else {
$sub_foreign_keys = $ids;
}
$this->DoCopyLiveToTemp($sub_table, $sub_foreign_keys, $master['Prefix']);
}
}
}
function GetForeignKeys($master, $sub_table, $live_id, $temp_id=null)
{
$mode = 1; //multi
if (!is_array($live_id)) {
$live_id = Array($live_id);
$mode = 2; //single
}
if (isset($temp_id) && !is_array($temp_id)) $temp_id = Array($temp_id);
if ( isset($sub_table['ParentTableKey']) ) {
if ( is_array($sub_table['ParentTableKey']) ) {
$parent_key_field = $sub_table['ParentTableKey'][$master['Prefix']];
}
else {
$parent_key_field = $sub_table['ParentTableKey'];
}
}
else {
$parent_key_field = $master['IdField'];
}
$cached = getArrayValue($this->FKeysCache, $master['TableName'].'.'.$parent_key_field);
if ( $cached ) {
if ( array_key_exists(serialize($live_id), $cached) ) {
list($live_foreign_key, $temp_foreign_key) = $cached[serialize($live_id)];
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
}
if ($parent_key_field != $master['IdField']) {
$query = 'SELECT '.$parent_key_field.' FROM '.$master['TableName'].'
WHERE '.$master['IdField'].' IN ('.join(',', $live_id).')';
$live_foreign_key = $this->Conn->GetCol($query);
if (isset($temp_id)) {
// because DoCopyTempToOriginal resets negative IDs to 0 in temp table (one by one) before copying to live
$temp_key = $temp_id < 0 ? 0 : $temp_id;
$query = 'SELECT '.$parent_key_field.' FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' IN ('.join(',', $temp_key).')';
$temp_foreign_key = $this->Conn->GetCol($query);
}
else {
$temp_foreign_key = Array();
}
}
else {
$live_foreign_key = $live_id;
$temp_foreign_key = $temp_id;
}
$this->FKeysCache[$master['TableName'].'.'.$parent_key_field][serialize($live_id)] = Array($live_foreign_key, $temp_foreign_key);
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
/**
* Copies data from temp to live table and returns IDs of copied records
*
* @param Array $master
* @param string $parent_prefix
* @param Array $current_ids
* @return Array
* @access public
*/
public function DoCopyTempToOriginal($master, $parent_prefix = null, $current_ids = Array())
{
if ( !$current_ids ) {
$query = 'SELECT ' . $master['IdField'] . ' FROM ' . $this->GetTempName($master['TableName']);
if ( isset($master['Constrain']) ) {
$query .= ' WHERE ' . $master['Constrain'];
}
$current_ids = $this->Conn->GetCol($query);
}
$table_sig = $master['TableName'] . (isset($master['Constrain']) ? $master['Constrain'] : '');
if ($current_ids) {
// delete all ids from live table - for MasterTable ONLY!
// because items from Sub Tables get deteleted in CopySubTablesToLive !BY ForeignKey!
if ( $master['TableName'] == $this->MasterTable ) {
$this->RaiseEvent('OnBeforeDeleteFromLive', $master['Prefix'], '', $current_ids);
$query = 'DELETE FROM ' . $master['TableName'] . ' WHERE ' . $master['IdField'] . ' IN (' . join(',', $current_ids) . ')';
$this->Conn->Query($query);
}
if ( getArrayValue($master, 'SubTables') ) {
if ( in_array($table_sig, $this->CopiedTables) || $this->FinalRefs[$table_sig] != $master['TableId'] ) {
return Array ();
}
foreach ($current_ids AS $id) {
$this->RaiseEvent('OnBeforeCopyToLive', $master['Prefix'], '', Array ($id));
//reset negative ids to 0, so autoincrement in live table works fine
if ( $id < 0 ) {
$query = ' UPDATE ' . $this->GetTempName($master['TableName']) . '
SET ' . $master['IdField'] . ' = 0
WHERE ' . $master['IdField'] . ' = ' . $id;
if ( isset($master['Constrain']) ) {
$query .= ' AND ' . $master['Constrain'];
}
$this->Conn->Query($query);
$id_to_copy = 0;
}
else {
$id_to_copy = $id;
}
//copy current id_to_copy (0 for new or real id) to live table
$query = ' INSERT INTO ' . $master['TableName'] . '
SELECT * FROM ' . $this->GetTempName($master['TableName']) . '
WHERE ' . $master['IdField'] . ' = ' . $id_to_copy;
$this->Conn->Query($query);
$insert_id = $id_to_copy == 0 ? $this->Conn->getInsertID() : $id_to_copy;
$this->saveID($master['Prefix'], '', array ($id => $insert_id));
$this->RaiseEvent('OnAfterCopyToLive', $master['Prefix'], '', Array ($insert_id), null, Array ('temp_id' => $id));
$this->UpdateForeignKeys($master, $insert_id, $id);
//delete already copied record from master temp table
$query = ' DELETE FROM ' . $this->GetTempName($master['TableName']) . '
WHERE ' . $master['IdField'] . ' = ' . $id_to_copy;
if ( isset($master['Constrain']) ) {
$query .= ' AND ' . $master['Constrain'];
}
$this->Conn->Query($query);
}
$this->CopiedTables[] = $table_sig;
// when all of ids in current master has been processed, copy all sub-tables data
$this->CopySubTablesToLive($master, $current_ids);
}
elseif ( !in_array($table_sig, $this->CopiedTables) && ($this->FinalRefs[$table_sig] == $master['TableId']) ) { //If current master doesn't have sub-tables - we could use mass operations
// We don't need to delete items from live here, as it get deleted in the beginning of the method for MasterTable
// or in parent table processing for sub-tables
$live_ids = Array ();
$this->RaiseEvent('OnBeforeCopyToLive', $master['Prefix'], '', $current_ids);
foreach ($current_ids as $an_id) {
if ( $an_id > 0 ) {
$live_ids[$an_id] = $an_id;
// positive (already live) IDs will be copied in on query all togather below,
// so we just store it here
continue;
}
else { // zero or negative ids should be copied one by one to get their InsertId
// resetting to 0 so it get inserted into live table with autoincrement
$query = ' UPDATE ' . $this->GetTempName($master['TableName']) . '
SET ' . $master['IdField'] . ' = 0
WHERE ' . $master['IdField'] . ' = ' . $an_id;
// constrain is not needed here because ID is already unique
$this->Conn->Query($query);
// copying
$query = ' INSERT INTO ' . $master['TableName'] . '
SELECT * FROM ' . $this->GetTempName($master['TableName']) . '
WHERE ' . $master['IdField'] . ' = 0';
$this->Conn->Query($query);
$live_ids[$an_id] = $this->Conn->getInsertID(); //storing newly created live id
//delete already copied record from master temp table
$query = ' DELETE FROM ' . $this->GetTempName($master['TableName']) . '
WHERE ' . $master['IdField'] . ' = 0';
$this->Conn->Query($query);
$this->UpdateChangeLogForeignKeys($master, $live_ids[$an_id], $an_id);
}
}
// copy ALL records to live table
$query = ' INSERT INTO ' . $master['TableName'] . '
SELECT * FROM ' . $this->GetTempName($master['TableName']);
if ( isset($master['Constrain']) ) {
$query .= ' WHERE ' . $master['Constrain'];
}
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
$this->RaiseEvent('OnAfterCopyToLive', $master['Prefix'], '', $live_ids);
$this->saveID($master['Prefix'], '', $live_ids);
// no need to clear temp table - it will be dropped by next statement
}
}
if ( $this->FinalRefs[ $master['TableName'] ] != $master['TableId'] ) {
return Array ();
}
/*if ( is_array(getArrayValue($master, 'ForeignKey')) ) { //if multiple ForeignKeys
if ( $master['ForeignKey'][$parent_prefix] != end($master['ForeignKey']) ) {
return; // Do not delete temp table if not all ForeignKeys have been processed (current is not the last)
}
}*/
$this->DropTempTable($master['TableName']);
$this->Application->resetCounters($master['TableName']);
if ( !isset($this->savedIDs[ $master['Prefix'] ]) ) {
$this->savedIDs[ $master['Prefix'] ] = Array ();
}
return $this->savedIDs[ $master['Prefix'] ];
}
/**
* Create separate connection for locking purposes
*
* @return kDBConnection
*/
function &_getSeparateConnection()
{
static $connection = null;
if (!isset($connection)) {
$connection = $this->Application->makeClass( 'kDBConnection', Array (SQL_TYPE, Array ($this->Application, 'handleSQLError')) );
/* @var $connection kDBConnection */
$connection->debugMode = $this->Application->isDebugMode();
- $connection->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB, true);
+ $connection->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB);
}
return $connection;
}
function UpdateChangeLogForeignKeys($master, $live_id, $temp_id)
{
if ($live_id == $temp_id) {
return ;
}
$prefix = $master['Prefix'];
$main_prefix = $this->Application->GetTopmostPrefix($prefix);
$ses_var_name = $main_prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$changes = $this->Application->RecallVar($ses_var_name);
$changes = $changes ? unserialize($changes) : Array ();
foreach ($changes as $key => $rec) {
if ($rec['Prefix'] == $prefix && $rec['ItemId'] == $temp_id) {
// main item change log record
$changes[$key]['ItemId'] = $live_id;
}
if ($rec['MasterPrefix'] == $prefix && $rec['MasterId'] == $temp_id) {
// sub item change log record
$changes[$key]['MasterId'] = $live_id;
}
if (in_array($prefix, $rec['ParentPrefix']) && $rec['ParentId'][$prefix] == $temp_id) {
// parent item change log record
$changes[$key]['ParentId'][$prefix] = $live_id;
if (array_key_exists('DependentFields', $rec)) {
// these are fields from table of $rec['Prefix'] table!
// when one of dependent fields goes into idfield of it's parent item, that was changed
$parent_table_key = $this->Application->getUnitOption($rec['Prefix'], 'ParentTableKey');
$parent_table_key = is_array($parent_table_key) ? $parent_table_key[$prefix] : $parent_table_key;
if ($parent_table_key == $master['IdField']) {
$foreign_key = $this->Application->getUnitOption($rec['Prefix'], 'ForeignKey');
$foreign_key = is_array($foreign_key) ? $foreign_key[$prefix] : $foreign_key;
$changes[$key]['DependentFields'][$foreign_key] = $live_id;
}
}
}
}
$this->Application->StoreVar($ses_var_name, serialize($changes));
}
function UpdateForeignKeys($master, $live_id, $temp_id)
{
$this->UpdateChangeLogForeignKeys($master, $live_id, $temp_id);
foreach ($master['SubTables'] as $sub_table) {
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
if (!$foreign_key_field) {
continue;
}
list ($live_foreign_key, $temp_foreign_key) = $this->GetForeignKeys($master, $sub_table, $live_id, $temp_id);
//Update ForeignKey in sub TEMP table
if ($live_foreign_key != $temp_foreign_key) {
$query = 'UPDATE '.$this->GetTempName($sub_table['TableName']).'
SET '.$foreign_key_field.' = '.$live_foreign_key.'
WHERE '.$foreign_key_field.' = '.$temp_foreign_key;
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
}
function CopySubTablesToLive($master, $current_ids) {
foreach ($master['SubTables'] as $sub_table) {
$table_sig = $sub_table['TableName'].(isset($sub_table['Constrain']) ? $sub_table['Constrain'] : '');
// delete records from live table by foreign key, so that records deleted from temp table
// get deleted from live
if (count($current_ids) > 0 && !in_array($table_sig, $this->CopiedTables) ) {
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
if (!$foreign_key_field) continue;
$foreign_keys = $this->GetForeignKeys($master, $sub_table, $current_ids);
if (count($foreign_keys) > 0) {
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
if ( $this->RaiseEvent( 'OnBeforeDeleteFromLive', $sub_table['Prefix'], '', $this->Conn->GetCol($query), $foreign_keys ) ){
$query = 'DELETE FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
}
//sub_table passed here becomes master in the method, and recursively updated and copy its sub tables
$this->DoCopyTempToOriginal($sub_table, $master['Prefix']);
}
}
/**
* Raises event using IDs, that are currently being processed in temp handler
*
* @param string $name
* @param string $prefix
* @param string $special
* @param Array $ids
* @param string $foreign_key
* @param Array $add_params
* @return bool
* @access protected
*/
protected function RaiseEvent($name, $prefix, $special, $ids, $foreign_key = null, $add_params = null)
{
if ( !is_array($ids) ) {
return true;
}
$event_key = $prefix . ($special ? '.' : '') . $special . ':' . $name;
$event = new kEvent($event_key);
$event->MasterEvent = $this->parentEvent;
if ( isset($foreign_key) ) {
$event->setEventParam('foreign_key', $foreign_key);
}
$set_temp_id = ($name == 'OnAfterCopyToLive') && (!is_array($add_params) || !array_key_exists('temp_id', $add_params));
foreach ($ids as $index => $id) {
$event->setEventParam('id', $id);
if ( $set_temp_id ) {
$event->setEventParam('temp_id', $index);
}
if ( is_array($add_params) ) {
foreach ($add_params as $name => $val) {
$event->setEventParam($name, $val);
}
}
$this->Application->HandleEvent($event);
}
return $event->status == kEvent::erSUCCESS;
}
function DropTempTable($table)
{
if ( in_array($table, $this->DroppedTables) ) {
return false;
}
$query = 'DROP TABLE IF EXISTS ' . $this->GetTempName($table);
array_push($this->DroppedTables, $table);
$this->DroppedTables = array_unique($this->DroppedTables);
$this->Conn->Query($query);
return true;
}
function PrepareEdit()
{
$this->DoCopyLiveToTemp($this->Tables, $this->Tables['IDs']);
if ($this->Application->getUnitOption($this->Tables['Prefix'],'CheckSimulatniousEdit')) {
$this->CheckSimultaniousEdit();
}
}
function SaveEdit($master_ids = Array())
{
// SessionKey field is required for deleting records from expired sessions
$conn =& $this->_getSeparateConnection();
$sleep_count = 0;
do {
// acquire lock
$conn->ChangeQuery('LOCK TABLES '.TABLE_PREFIX.'Semaphores WRITE');
$sql = 'SELECT SessionKey
FROM ' . TABLE_PREFIX . 'Semaphores
WHERE (MainPrefix = ' . $conn->qstr($this->Tables['Prefix']) . ')';
$another_coping_active = $conn->GetOne($sql);
if ($another_coping_active) {
// another user is coping data from temp table to live -> release lock and try again after 1 second
$conn->ChangeQuery('UNLOCK TABLES');
$sleep_count++;
sleep(1);
}
} while ($another_coping_active && ($sleep_count <= 30));
if ($sleep_count > 30) {
// another coping process failed to finished in 30 seconds
$error_message = $this->Application->Phrase('la_error_TemporaryTableCopyingFailed');
$this->Application->SetVar('_temp_table_message', $error_message);
return false;
}
// mark, that we are coping from temp to live right now, so other similar attempt (from another script) will fail
$fields_hash = Array (
'SessionKey' => $this->Application->GetSID(),
'Timestamp' => adodb_mktime(),
'MainPrefix' => $this->Tables['Prefix'],
);
$conn->doInsert($fields_hash, TABLE_PREFIX.'Semaphores');
$semaphore_id = $conn->getInsertID();
// unlock table now to prevent permanent lock in case, when coping will end with SQL error in the middle
$conn->ChangeQuery('UNLOCK TABLES');
$ids = $this->DoCopyTempToOriginal($this->Tables, null, $master_ids);
// remove mark, that we are coping from temp to live
$conn->Query('LOCK TABLES '.TABLE_PREFIX.'Semaphores WRITE');
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Semaphores
WHERE SemaphoreId = ' . $semaphore_id;
$conn->ChangeQuery($sql);
$conn->ChangeQuery('UNLOCK TABLES');
return $ids;
}
function CancelEdit($master=null)
{
if (!isset($master)) $master = $this->Tables;
$this->DropTempTable($master['TableName']);
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$this->CancelEdit($sub_table);
}
}
}
/**
* Checks, that someone is editing selected records and returns true, when no one.
*
* @param Array $ids
*
* @return bool
*/
function CheckSimultaniousEdit($ids = null)
{
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/' . TABLE_PREFIX . 'ses_(.*)_edit_' . $this->MasterTable . '$/';
$my_sid = $this->Application->GetSID();
$my_wid = $this->Application->GetVar('m_wid');
$ids = implode(',', isset($ids) ? $ids : $this->Tables['IDs']);
$sids = Array ();
if (!$ids) {
return true;
}
foreach ($tables as $table) {
if ( preg_match($mask_edit_table, $table, $rets) ) {
$sid = preg_replace('/(.*)_(.*)/', '\\1', $rets[1]); // remove popup's wid from sid
if ($sid == $my_sid) {
if ($my_wid) {
// using popups for editing
if (preg_replace('/(.*)_(.*)/', '\\2', $rets[1]) == $my_wid) {
// don't count window, that is being opened right now
continue;
}
}
else {
// not using popups for editing -> don't count my session tables
continue;
}
}
$sql = 'SELECT COUNT(' . $this->Tables['IdField'] . ')
FROM ' . $table . '
WHERE ' . $this->Tables['IdField'] . ' IN (' . $ids . ')';
$found = $this->Conn->GetOne($sql);
if (!$found || in_array($sid, $sids)) {
continue;
}
$sids[] = $sid;
}
}
if ($sids) {
// detect who is it
$sql = 'SELECT
CONCAT(IF (s.PortalUserId = ' . USER_ROOT . ', \'root\',
IF (s.PortalUserId = ' . USER_GUEST . ', \'Guest\',
CONCAT(u.FirstName, \' \', u.LastName, \' (\', u.Username, \')\')
)
), \' IP: \', s.IpAddress, \'\') FROM ' . TABLE_PREFIX . 'UserSessions AS s
LEFT JOIN ' . TABLE_PREFIX . 'Users AS u
ON u.PortalUserId = s.PortalUserId
WHERE s.SessionKey IN (' . implode(',', $sids) . ')';
$users = $this->Conn->GetCol($sql);
if ($users) {
$this->Application->SetVar('_simultaneous_edit_message',
sprintf($this->Application->Phrase('la_record_being_edited_by'), join(",\n", $users))
);
return false;
}
}
return true;
}
-}
\ No newline at end of file
+}
Index: branches/5.2.x/core/install/step_templates/db_reconfig.tpl
===================================================================
--- branches/5.2.x/core/install/step_templates/db_reconfig.tpl (revision 16406)
+++ branches/5.2.x/core/install/step_templates/db_reconfig.tpl (revision 16407)
@@ -1,67 +1,67 @@
<tr class="table-color2">
<td class="text"><b>Database Server Type<span class="error">*</span>:</b></td>
<td align="left">
<select name="DBType">
<?php
- $options = Array ('mysql' => 'MySQL', /*'mssql' => 'MS-SQL Server', 'pgsql' => 'pgSQL'*/);
+ $options = Array ('mysqli' => 'MySQL', /*'mssql' => 'MS-SQL Server', 'pgsql' => 'pgSQL'*/);
$option_tpl = '<option value="%1$s"%2$s>%3$s</option>'."\n";
foreach ($options as $option_key => $option_title) {
$selected = $option_key == $this->toolkit->getSystemConfig('Database', 'DBType') ? ' selected' : '';
echo sprintf($option_tpl, $option_key, $selected, $option_title);
}
?>
</select>
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database Hostname <span class="error">*</span>:</b></td>
<td align="left">
<input type="text" name="DBHost" class="text" value="<?php echo $this->toolkit->getSystemConfig('Database', 'DBHost'); ?>" />
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database Name <span class="error">*</span>:</b></td>
<td align="left">
<input type="text" name="DBName" class="text" value="<?php echo $this->toolkit->getSystemConfig('Database', 'DBName'); ?>" />
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database User Name <span class="error">*</span>:</b></td>
<td align="left">
<input type="text" name="DBUser" class="text" value="<?php echo $this->toolkit->getSystemConfig('Database', 'DBUser'); ?>" />
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database User Password:</b></td>
<td align="left">
<input type="password" name="DBUserPassword" class="text" value="<?php echo $this->toolkit->getSystemConfig('Database', 'DBUserPassword'); ?>" />
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database Collation <span class="error">*</span>:</b></td>
<td align="left">
<select name="DBCollation" class="text">
<?php
$option_tpl = '<option value="%1$s"%2$s>%1$s</option>'."\n";
$collations = Array ('utf8_general_ci', 'latin1_swedish_ci');
foreach ($collations as $collation) {
$selected = ($collation == $this->toolkit->getSystemConfig('Database', 'DBCollation')) ? ' selected="selected"' : '';
echo sprintf($option_tpl, $collation, $selected);
}
?>
</select>
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Prefix for Table Names:</b></td>
<td align="left">
<input type="text" name="TablePrefix" class="text" maxlength="7" value="<?php echo $this->toolkit->getSystemConfig('Database', 'TablePrefix'); ?>" />
</td>
</tr>
\ No newline at end of file
Index: branches/5.2.x/core/install/step_templates/db_config.tpl
===================================================================
--- branches/5.2.x/core/install/step_templates/db_config.tpl (revision 16406)
+++ branches/5.2.x/core/install/step_templates/db_config.tpl (revision 16407)
@@ -1,77 +1,77 @@
<tr class="table-color2">
<td class="text"><b>Database Server Type<span class="error">*</span>:</b></td>
<td align="left">
<select name="DBType">
<?php
- $options = Array ('mysql' => 'MySQL', /*'mssql' => 'MS-SQL Server', 'pgsql' => 'pgSQL'*/);
+ $options = Array ('mysqli' => 'MySQL', /*'mssql' => 'MS-SQL Server', 'pgsql' => 'pgSQL'*/);
$option_tpl = '<option value="%1$s"%2$s>%3$s</option>'."\n";
foreach ($options as $option_key => $option_title) {
$selected = $option_key == $this->toolkit->getSystemConfig('Database', 'DBType') ? ' selected' : '';
echo sprintf($option_tpl, $option_key, $selected, $option_title);
}
?>
</select>
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database Hostname <span class="error">*</span>:</b></td>
<td align="left">
<input type="text" name="DBHost" class="text" value="<?php echo $this->toolkit->getSystemConfig('Database', 'DBHost'); ?>" />
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database Name <span class="error">*</span>:</b></td>
<td align="left">
<input type="text" name="DBName" class="text" value="<?php echo $this->toolkit->getSystemConfig('Database', 'DBName'); ?>" />
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database User Name <span class="error">*</span>:</b></td>
<td align="left">
<input type="text" name="DBUser" class="text" value="<?php echo $this->toolkit->getSystemConfig('Database', 'DBUser'); ?>" />
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database User Password:</b></td>
<td align="left">
<input type="password" name="DBUserPassword" class="text" value="<?php echo $this->toolkit->getSystemConfig('Database', 'DBUserPassword'); ?>" />
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Database Collation <span class="error">*</span>:</b></td>
<td align="left">
<select name="DBCollation" class="text">
<?php
$option_tpl = '<option value="%1$s"%2$s>%1$s</option>'."\n";
$collations = Array ('utf8_general_ci', 'latin1_swedish_ci');
foreach ($collations as $collation) {
$selected = ($collation == $this->toolkit->getSystemConfig('Database', 'DBCollation')) ? ' selected="selected"' : '';
echo sprintf($option_tpl, $collation, $selected);
}
?>
</select>
</td>
</tr>
<tr class="table-color2">
<td class="text"><b>Prefix for Table Names:</b></td>
<td align="left">
<input type="text" name="TablePrefix" class="text" maxlength="7" value="<?php echo $this->toolkit->getSystemConfig('Database', 'TablePrefix'); ?>" />
</td>
</tr>
<?php if ($this->GetVar('preset') != 'already_installed') { ?>
-<!--show this option ONLY when config.php is empty or cant connect to In-Portal installation using current DB settings -->
+<!--show this option ONLY when config.php is empty or cant connect to In-Portal installation using current DB settings -->
<tr class="table-color2">
<td class="text" width="55%"><b>Use existing In-Portal installation in this Database:</b></td>
<td align="left">
<input type="radio" name="UseExistingSetup" id="UseExistingSetup_1" value="1"/> <label for="UseExistingSetup_1">Yes</label> <input type="radio" name="UseExistingSetup" id="UseExistingSetup_0" value="0" checked/> <label for="UseExistingSetup_0">No</label>
</td>
</tr>
<?php } ?>
\ No newline at end of file
Index: branches/5.2.x/core/install/prerequisites.php
===================================================================
--- branches/5.2.x/core/install/prerequisites.php (revision 16406)
+++ branches/5.2.x/core/install/prerequisites.php (revision 16407)
@@ -1,243 +1,243 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
$prerequisite_class = 'InPortalPrerequisites';
/**
* Class, that holds all prerequisite scripts for "In-Portal" module
*
*/
class InPortalPrerequisites {
/**
* Install toolkit instance
*
* @var kInstallToolkit
*/
var $_toolkit = null;
/**
* Connection to database
*
* @var kDBConnection
* @access protected
*/
protected $Conn = null;
/**
* Version upgrade rules
*
* @var array
* @access private
*/
private $upgradeRules = Array (
'5.0.0' => Array ('from' => '5.0.0-B1', 'to' => '5.1.0-B1'),
'5.1.0' => Array ('from' => '5.1.0-B1', 'to' => '5.2.0-B1'),
'5.2.0' => Array ('from' => '5.2.0-B1', 'to' => '5.3.0-B1'),
);
/**
* Sets common instance of installator toolkit
*
* @param kInstallToolkit $instance
*/
function setToolkit(&$instance)
{
$this->_toolkit =& $instance;
}
/**
* Checks minimal version, that could be upgradeable
*
* @return kDBConnection
*/
function getConnection()
{
return $this->_toolkit->Conn;
}
/**
* Checks minimal version, that could be upgradeable
*
* @param Array $versions
* @param string $mode when called mode {install, upgrade, standalone)
* @return Array
*/
function CheckPrerequisites($versions, $mode)
{
$errors = Array ();
if ( $mode == 'upgrade' ) {
$sql = 'SELECT Version
FROM ' . TABLE_PREFIX . 'Modules
WHERE Name = "In-Portal"';
$inportal_version = $this->getConnection()->GetOne($sql);
if ( $inportal_version === false ) {
// only, when In-Portal was installed (below 4.3.x)
return $errors;
}
$min_version = '4.3.1'; // K4-based installator was created, that no longer maintained old upgrade scripts
if ( version_compare($inportal_version, $min_version, '<') ) {
$errors[] = 'Please upgrade "In-Portal" to version ' . $min_version . ' first';
}
// example: to upgrade to 5.1.0-B1 or more you at least need to have 5.0.0 installed
foreach ($this->upgradeRules as $min_version => $version_rules) {
if ( version_compare($versions[0], $version_rules['from'], '<') && version_compare($versions[1], $version_rules['to'], '>=') ) {
$errors[] = 'Please upgrade "In-Portal" to version ' . $min_version . ' first';
break;
}
}
}
return $errors;
}
/**
* Returns information about system requirements
*
* @return array
*/
function CheckSystemRequirements()
{
$ret = Array ();
$ret['php_version'] = version_compare(PHP_VERSION, '5.3.2', '>=');
if ( function_exists('apache_get_modules') ) {
$mod_rewrite = in_array('mod_rewrite', apache_get_modules());
}
else {
$mod_rewrite = getenv('HTTP_MOD_REWRITE') == 'On';
}
$ret['url_rewriting'] = $mod_rewrite;
$ret['memcache'] = class_exists('Memcache');
$ret['curl'] = function_exists('curl_init');
$ret['simplexml'] = function_exists('simplexml_load_string');
$ret['spl'] = function_exists('spl_autoload_register');
$ret['freetype'] = function_exists('imagettfbbox');
$ret['gd_version'] = false;
if ( function_exists('gd_info') ) {
$gd_info = gd_info();
$gd_version = preg_replace('/[^\d.]/', '', $gd_info['GD Version']);
$ret['gd_version'] = version_compare($gd_version, '1.8', '>=');
}
$ret['jpeg'] = function_exists('imagecreatefromjpeg');
- $ret['mysql'] = function_exists('mysql_connect');
+ $ret['mysql'] = function_exists('mysqli_connect');
$ret['json'] = function_exists('json_encode');
$output = shell_exec('java -version 2>&1');
$ret['java'] = stripos($output, 'java version') !== false;
$ret['composer'] = file_exists(FULL_PATH . '/vendor/autoload.php');
$ret['memory_limit'] = $this->isPhpSettingChangeable('memory_limit', '33M');
$ret['display_errors'] = $this->isPhpSettingChangeable('display_errors', '1');
$ret['error_reporting'] = $this->canChangeErrorReporting();
$ret['date.timezone'] = ini_get('date.timezone') != '';
$ret['variables_order'] = $this->_hasLetters(ini_get('variables_order'), Array ('G', 'P', 'C', 'S'));
$output_buffering = strtolower(ini_get('output_buffering'));
$ret['output_buffering'] = $output_buffering == 'on' || $output_buffering > 0;
return $ret;
}
/**
* Determines of a setting string has all given letters (ignoring order) in it
*
* @param string $setting
* @param Array $search_letters
* @return bool
* @access protected
*/
protected function _hasLetters($setting, $search_letters)
{
$setting = preg_replace('/(' . implode('|', $search_letters) . ')/', '*', $setting);
return substr_count($setting, '*') == count($search_letters);
}
/**
* Detects if error reporting can be changed at runtime
*
* @return bool
* @access protected
*/
protected function canChangeErrorReporting()
{
$old_value = error_reporting(E_PARSE);
$new_value = error_reporting();
if ( $new_value == E_PARSE ) {
error_reporting($old_value);
return true;
}
return false;
}
/**
* Detects if setting of php.ini can be changed
*
* @param string $setting_name
* @param string $new_value
* @return bool
*/
protected function isPhpSettingChangeable($setting_name, $new_value)
{
$old_value = ini_get($setting_name);
if ( ini_set($setting_name, $new_value) === false ) {
return false;
}
ini_set($setting_name, $old_value);
return true;
}
/**
* Returns information about DB requirements
*
* @return array
*/
function CheckDBRequirements()
{
// check PHP version 5.2+
$ret = Array();
$sql = 'SELECT VERSION()';
$conn = $this->getConnection();
$db_version = preg_replace('/[^\d.]/', '', $conn->GetOne($sql));
$ret['version'] = version_compare($db_version, '5.0', '>=');
$sql = 'SHOW VARIABLES LIKE "max_allowed_packet"';
$db_variables = $conn->Query($sql, 'Variable_name');
$ret['packet_size'] = $db_variables['max_allowed_packet']['Value'] >= 1048576;
return $ret;
}
}
Index: branches/5.2.x/CREDITS
===================================================================
--- branches/5.2.x/CREDITS (revision 16406)
+++ branches/5.2.x/CREDITS (revision 16407)
Property changes on: branches/5.2.x/CREDITS
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/CREDITS:r15931
Index: branches/5.2.x/README
===================================================================
--- branches/5.2.x/README (revision 16406)
+++ branches/5.2.x/README (revision 16407)
Property changes on: branches/5.2.x/README
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/README:r15931
Index: branches/5.2.x/index.php
===================================================================
--- branches/5.2.x/index.php (revision 16406)
+++ branches/5.2.x/index.php (revision 16407)
Property changes on: branches/5.2.x/index.php
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/index.php:r15931
Index: branches/5.2.x/LICENSES
===================================================================
--- branches/5.2.x/LICENSES (revision 16406)
+++ branches/5.2.x/LICENSES (revision 16407)
Property changes on: branches/5.2.x/LICENSES
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/LICENSES:r15931
Index: branches/5.2.x/INSTALL
===================================================================
--- branches/5.2.x/INSTALL (revision 16406)
+++ branches/5.2.x/INSTALL (revision 16407)
Property changes on: branches/5.2.x/INSTALL
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/INSTALL:r15931
Index: branches/5.2.x/COPYRIGHT
===================================================================
--- branches/5.2.x/COPYRIGHT (revision 16406)
+++ branches/5.2.x/COPYRIGHT (revision 16407)
Property changes on: branches/5.2.x/COPYRIGHT
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/COPYRIGHT:r15931
Index: branches/5.2.x/.htaccess
===================================================================
--- branches/5.2.x/.htaccess (revision 16406)
+++ branches/5.2.x/.htaccess (revision 16407)
Property changes on: branches/5.2.x/.htaccess
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/.htaccess:r15931
Index: branches/5.2.x
===================================================================
--- branches/5.2.x (revision 16406)
+++ branches/5.2.x (revision 16407)
Property changes on: branches/5.2.x
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x:r15931

Event Timeline