diff --git a/includes/kernel.php b/includes/kernel.php index d0567a8f..11794e38 100644 --- a/includes/kernel.php +++ b/includes/kernel.php @@ -8,7 +8,7 @@ ini_set('serialize_precision', 4); require 'includes/defines.php'; require 'config/config.php'; -require 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using mysqli variant: https://bitbucket.org/brainreaver/dbsimple/src) +require 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master) require 'includes/utilities.php'; // misc™ data 'n func require 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests require 'includes/user.class.php'; diff --git a/includes/libs/DbSimple/CacherImpl.php b/includes/libs/DbSimple/CacherImpl.php new file mode 100644 index 00000000..986cb130 --- /dev/null +++ b/includes/libs/DbSimple/CacherImpl.php @@ -0,0 +1,45 @@ +callback = $callback; + } else { + $this->callback = $this->callbackDummy; + } + } + + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) {} + + public function remove($id) {} + + public function test($id) {} + + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + return call_user_func($this->callback, $id, $data); + } + + public function load($id, $doNotTestCacheValidity = false) + { + return call_user_func($this->callback, $id); + } + + public function setDirectives($directives) {} + + protected function callbackDummy($k, $v) + { + return null; + } + +} // CacherImpl class \ No newline at end of file diff --git a/includes/libs/DbSimple/Connect.php b/includes/libs/DbSimple/Connect.php index 4706069a..6489c89a 100644 --- a/includes/libs/DbSimple/Connect.php +++ b/includes/libs/DbSimple/Connect.php @@ -118,7 +118,7 @@ class DbSimple_Connect if (!isset($parsed['scheme'])) $this->errorHandler('Невозможно загрузить драйвер базы данных', $parsed); $this->shema = ucfirst($parsed['scheme']); - require_once dirname(__FILE__).'/'.$this->shema.'.php'; + require_once __DIR__.'/'.$this->shema.'.php'; $class = 'DbSimple_'.$this->shema; $this->DbSimple = new $class($parsed); $this->errmsg = &$this->DbSimple->errmsg; @@ -256,18 +256,7 @@ class DbSimple_Connect */ protected function parseDSN($dsn) { - $parsed = parse_url($dsn); - if (!$parsed) - return null; - $params = null; - if (!empty($parsed['query'])) - { - parse_str($parsed['query'], $params); - $parsed += $params; - } - $parsed['dsn'] = $dsn; - return $parsed; + return DbSimple_Generic::parseDSN($dsn); } -} -?> +} diff --git a/includes/libs/DbSimple/Database.php b/includes/libs/DbSimple/Database.php index 1a3a6ad9..86719ae1 100644 --- a/includes/libs/DbSimple/Database.php +++ b/includes/libs/DbSimple/Database.php @@ -74,6 +74,15 @@ if (!defined('DBSIMPLE_ARRAY_KEY')) if (!defined('DBSIMPLE_PARENT_KEY')) define('DBSIMPLE_PARENT_KEY', 'PARENT_KEY'); // forrest-based resultset support + +if ( !interface_exists('Zend_Cache_Backend_Interface', false) ) { + require_once __DIR__ . '/Zend/Cache.php'; + require_once __DIR__ . '/Zend/Cache/Backend/Interface.php'; +} + +require_once __DIR__ . '/CacherImpl.php'; + + /** * * Base class for all databases. @@ -262,10 +271,24 @@ abstract class DbSimple_Database extends DbSimple_LastError * Set cache mechanism called during each query if specified. * Returns previous handler. */ - public function setCacher(Zend_Cache_Backend_Interface $cacher=null) + public function setCacher($cacher=null) { $prev = $this->_cacher; - $this->_cacher = $cacher; + + if ( is_null($cacher) ) { + return $prev; + } + + if ($cacher instanceof Zend_Cache_Backend_Interface) { + $this->_cacher = $cacher; + return $prev; + } + + if ( is_callable($cacher) ) { + $this->_cacher = new CacherImpl($cacher); + return $prev; + } + return $prev; } @@ -444,7 +467,7 @@ abstract class DbSimple_Database extends DbSimple_LastError $rows = false; $cache_it = false; // Кешер у нас либо null либо соответствует Zend интерфейсу - if (!empty($this->attributes['CACHE']) && $this->_cacher) + if ( !empty($this->attributes['CACHE']) && ($this->_cacher instanceof Zend_Cache_Backend_Interface) ) { $hash = $this->_cachePrefix . md5(serialize($query)); @@ -1323,7 +1346,7 @@ abstract class DbSimple_LastError * Return part of stacktrace before calling first library method. * Used in debug purposes (query logging etc.). */ - protected function findLibraryCaller() + public function findLibraryCaller() { $caller = call_user_func( array(&$this, 'debug_backtrace_smart'), @@ -1387,4 +1410,3 @@ abstract class DbSimple_LastError } } -?> diff --git a/includes/libs/DbSimple/Generic.php b/includes/libs/DbSimple/Generic.php index 919cd63e..5dc2f144 100644 --- a/includes/libs/DbSimple/Generic.php +++ b/includes/libs/DbSimple/Generic.php @@ -85,8 +85,17 @@ class DbSimple_Generic * Universal static function to connect ANY database using DSN syntax. * Choose database driver according to DSN. Return new instance * of this driver. + * + * You can connect to MySQL by socket using this new syntax (like PDO DSN): + * $dsn = 'mysqli:unix_socket=/cloudsql/app:instance;user=root;pass=;dbname=testdb'; + * $dsn = 'mypdo:unix_socket=/cloudsql/app:instance;charset=utf8;user=testuser;pass=mypassword;dbname=testdb'; + * + * Connection by host also can be made with this syntax. + * Or you can use old syntax: + * $dsn = 'mysql://testuser:mypassword@127.0.0.1/testdb'; + * */ - function connect($dsn) + public static function connect($dsn) { // Load database driver and create its instance. $parsed = DbSimple_Generic::parseDSN($dsn); @@ -96,7 +105,7 @@ class DbSimple_Generic } $class = 'DbSimple_'.ucfirst($parsed['scheme']); if (!class_exists($class)) { - $file = dirname(__FILE__).'/'.ucfirst($parsed['scheme']). ".php"; + $file = __DIR__.'/'.ucfirst($parsed['scheme']). ".php"; if (is_file($file)) { require_once($file); } else { @@ -118,19 +127,67 @@ class DbSimple_Generic * Parse a data source name. * See parse_url() for details. */ - function parseDSN($dsn) + public static function parseDSN($dsn) { if (is_array($dsn)) return $dsn; $parsed = parse_url($dsn); if (!$parsed) return null; + $params = null; if (!empty($parsed['query'])) { parse_str($parsed['query'], $params); $parsed += $params; } + + if ( empty($parsed['host']) && empty($parsed['socket']) ) { + // Parse as DBO DSN string + $parsedPdo = self::parseDsnPdo($parsed['path']); + unset($parsed['path']); + $parsed = array_merge($parsed, $parsedPdo); + } + $parsed['dsn'] = $dsn; return $parsed; - } -} + } // parseDSN -?> + + /** + * Parse string as DBO DSN string. + * + * @param $str + * @return array + */ + public static function parseDsnPdo($str) { + + if (substr($str, 0, strlen('mysql:')) == 'mysql:') { + $str = substr($str, strlen('mysql:')); + } + + $arr = explode(';', $str); + + $result = array(); + foreach ($arr as $k=>$v) { + $v = explode('=', $v); + if (count($v) == 2) + $result[ $v[0] ] = $v[1]; + } + + if ( isset($result['unix_socket']) ) { + $result['socket'] = $result['unix_socket']; + unset($result['unix_socket']); + } + + if ( isset($result['dbname']) ) { + $result['path'] = $result['dbname']; + unset($result['dbname']); + } + + if ( isset($result['charset']) ) { + $result['enc'] = $result['charset']; + unset($result['charset']); + } + + return $result; + } // parseDsnPdo + +} // DbSimple_Generic class diff --git a/includes/libs/DbSimple/Ibase.php b/includes/libs/DbSimple/Ibase.php deleted file mode 100644 index 839feef9..00000000 --- a/includes/libs/DbSimple/Ibase.php +++ /dev/null @@ -1,288 +0,0 @@ -_setLastError("-1", "Interbase/Firebird extension is not loaded", "ibase_connect"); - } - $ok = $this->link = ibase_connect( - $p['host'] . (empty($p['port'])? "" : ":".$p['port']) .':'.preg_replace('{^/}s', '', $p['path']), - $p['user'], - $p['pass'], - isset($p['CHARSET']) ? $p['CHARSET'] : 'win1251', - isset($p['BUFFERS']) ? $p['BUFFERS'] : 0, - isset($p['DIALECT']) ? $p['DIALECT'] : 3, - isset($p['ROLE']) ? $p['ROLE'] : '' - ); - if (isset($p['TRANSACTION'])) $this->DbSimple_Ibase_BEST_TRANSACTION = eval($p['TRANSACTION'].";"); - $this->_resetLastError(); - if (!$ok) return $this->_setDbError('ibase_connect()'); - } - - function _performEscape($s, $isIdent=false) - { - if (!$isIdent) - return "'" . str_replace("'", "''", $s) . "'"; - else - return '"' . str_replace('"', '_', $s) . '"'; - } - - function _performTransaction($parameters=null) - { - if ($parameters === null) $parameters = $this->DbSimple_Ibase_BEST_TRANSACTION; - $this->trans = @ibase_trans($parameters, $this->link); - } - - function _performNewBlob($blobid=null) - { - return new DbSimple_Ibase_Blob($this, $blobid); - } - - function _performGetBlobFieldNames($result) - { - $blobFields = array(); - for ($i=ibase_num_fields($result)-1; $i>=0; $i--) { - $info = ibase_field_info($result, $i); - if ($info['type'] === "BLOB") $blobFields[] = $info['name']; - } - return $blobFields; - } - - function _performGetPlaceholderIgnoreRe() - { - return ' - " (?> [^"\\\\]+|\\\\"|\\\\)* " | - \' (?> [^\'\\\\]+|\\\\\'|\\\\)* \' | - ` (?> [^`]+ | ``)* ` | # backticks - /\* .*? \*/ # comments - '; - } - - function _performCommit() - { - if (!is_resource($this->trans)) return false; - $result = @ibase_commit($this->trans); - if (true === $result) { - $this->trans = null; - } - return $result; - } - - - function _performRollback() - { - if (!is_resource($this->trans)) return false; - $result = @ibase_rollback($this->trans); - if (true === $result) { - $this->trans = null; - } - return $result; - } - - function _performTransformQuery(&$queryMain, $how) - { - // If we also need to calculate total number of found rows... - switch ($how) { - // Prepare total calculation (if possible) - case 'CALC_TOTAL': - // Not possible - return true; - - // Perform total calculation. - case 'GET_TOTAL': - // TODO: GROUP BY ... -> COUNT(DISTINCT ...) - $re = '/^ - (?> -- [^\r\n]* | \s+)* - (\s* SELECT \s+) #1 - ((?:FIRST \s+ \S+ \s+ (?:SKIP \s+ \S+ \s+)? )?) #2 - (.*?) #3 - (\s+ FROM \s+ .*?) #4 - ((?:\s+ ORDER \s+ BY \s+ .*)?) #5 - $/six'; - $m = null; - if (preg_match($re, $queryMain[0], $m)) { - $queryMain[0] = $m[1] . $this->_fieldList2Count($m[3]) . " AS C" . $m[4]; - $skipHead = substr_count($m[2], '?'); - if ($skipHead) array_splice($queryMain, 1, $skipHead); - $skipTail = substr_count($m[5], '?'); - if ($skipTail) array_splice($queryMain, -$skipTail); - } - return true; - } - - return false; - } - - function _performQuery($queryMain) - { - $this->_lastQuery = $queryMain; - $this->_expandPlaceholders($queryMain, $this->DbSimple_Ibase_USE_NATIVE_PHOLDERS); - - $hash = $queryMain[0]; - - if (!isset($this->prepareCache[$hash])) { - $this->prepareCache[$hash] = @ibase_prepare((is_resource($this->trans) ? $this->trans : $this->link), $queryMain[0]); - } else { - // Prepare cache hit! - } - - $prepared = $this->prepareCache[$hash]; - if (!$prepared) return $this->_setDbError($queryMain[0]); - $queryMain[0] = $prepared; - $result = @call_user_func_array('ibase_execute', $queryMain); - // ATTENTION!!! - // WE MUST save prepared ID (stored in $prepared variable) somewhere - // before returning $result because of ibase destructor. Now it is done - // by $this->prepareCache. When variable $prepared goes out of scope, it - // is destroyed, and memory for result also freed by PHP. Totally we - // got "Invalud statement handle" error message. - - if ($result === false) return $this->_setDbError($queryMain[0]); - if (!is_resource($result)) { - // Non-SELECT queries return number of affected rows, SELECT - resource. - return @ibase_affected_rows((is_resource($this->trans) ? $this->trans : $this->link)); - } - return $result; - } - - function _performFetch($result) - { - // Select fetch mode. - $flags = $this->fetchFlags; - if (empty($this->attributes['BLOB_OBJ'])) $flags = $flags | IBASE_TEXT; - else $flags = $flags & ~IBASE_TEXT; - - $row = @ibase_fetch_assoc($result, $flags); - if (ibase_errmsg()) return $this->_setDbError($this->_lastQuery); - return $row; - } - - - function _setDbError($query) - { - return $this->_setLastError(ibase_errcode(), ibase_errmsg(), $query); - } - -} - -class DbSimple_Ibase_Blob implements DbSimple_Blob -{ - var $blob; // resourse link - var $id; - var $database; - - function DbSimple_Ibase_Blob(&$database, $id=null) - { - $this->database =& $database; - $this->id = $id; - $this->blob = null; - } - - function read($len) - { - if ($this->id === false) return ''; // wr-only blob - if (!($e=$this->_firstUse())) return $e; - $data = @ibase_blob_get($this->blob, $len); - if ($data === false) return $this->_setDbError('read'); - return $data; - } - - function write($data) - { - if (!($e=$this->_firstUse())) return $e; - $ok = @ibase_blob_add($this->blob, $data); - if ($ok === false) return $this->_setDbError('add data to'); - return true; - } - - function close() - { - if (!($e=$this->_firstUse())) return $e; - if ($this->blob) { - $id = @ibase_blob_close($this->blob); - if ($id === false) return $this->_setDbError('close'); - $this->blob = null; - } else { - $id = null; - } - return $this->id ? $this->id : $id; - } - - function length() - { - if ($this->id === false) return 0; // wr-only blob - if (!($e=$this->_firstUse())) return $e; - $info = @ibase_blob_info($this->id); - if (!$info) return $this->_setDbError('get length of'); - return $info[0]; - } - - function _setDbError($query) - { - $hId = $this->id === null ? "null" : ($this->id === false ? "false" : $this->id); - $query = "-- $query BLOB $hId"; - $this->database->_setDbError($query); - } - - // Called on each blob use (reading or writing). - function _firstUse() - { - // BLOB is opened - nothing to do. - if (is_resource($this->blob)) return true; - // Open or create blob. - if ($this->id !== null) { - $this->blob = @ibase_blob_open($this->id); - if ($this->blob === false) return $this->_setDbError('open'); - } else { - $this->blob = @ibase_blob_create($this->database->link); - if ($this->blob === false) return $this->_setDbError('create'); - } - return true; - } -} - -?> \ No newline at end of file diff --git a/includes/libs/DbSimple/Mysql.php b/includes/libs/DbSimple/Mysql.php deleted file mode 100644 index 171ae62c..00000000 --- a/includes/libs/DbSimple/Mysql.php +++ /dev/null @@ -1,208 +0,0 @@ -_setLastError("-1", "MySQL extension is not loaded", $connect); - $ok = $this->link = @call_user_func($connect, - $dsn['host'] . (empty($dsn['port'])? "" : ":".$dsn['port']), - empty($dsn['user'])?'':$dsn['user'], - empty($dsn['pass'])?'':$dsn['pass'], - true - ); - $this->_resetLastError(); - if (!$ok) - if (!$ok) return $this->_setDbError('mysql_connect("' . $str . '", "' . $p['user'] . '")'); - $ok = @mysql_select_db(preg_replace('{^/}s', '', $dsn['path']), $this->link); - if (!$ok) - return $this->_setDbError('mysql_select_db()'); - mysql_query('SET NAMES '.(isset($dsn['enc'])?$dsn['enc']:'UTF8')); - } - - - protected function _performEscape($s, $isIdent=false) - { - if (!$isIdent) - return "'" . mysql_real_escape_string($s, $this->link) . "'"; - else - return "`" . str_replace('`', '``', $s) . "`"; - } - - - protected function _performNewBlob($blobid=null) - { - return new DbSimple_Mysql_Blob($this, $blobid); - } - - - protected function _performGetBlobFieldNames($result) - { - $blobFields = array(); - for ($i=mysql_num_fields($result)-1; $i>=0; $i--) - { - $type = mysql_field_type($result, $i); - if (stripos($type, "BLOB") !== false) - $blobFields[] = mysql_field_name($result, $i); - } - return $blobFields; - } - - - protected function _performGetPlaceholderIgnoreRe() - { - return ' - " (?> [^"\\\\]+|\\\\"|\\\\)* " | - \' (?> [^\'\\\\]+|\\\\\'|\\\\)* \' | - ` (?> [^`]+ | ``)* ` | # backticks - /\* .*? \*/ # comments - '; - } - - - protected function _performTransaction($parameters=null) - { - return $this->query('BEGIN'); - } - - - protected function _performCommit() - { - return $this->query('COMMIT'); - } - - - protected function _performRollback() - { - return $this->query('ROLLBACK'); - } - - - protected function _performTransformQuery(&$queryMain, $how) - { - // If we also need to calculate total number of found rows... - switch ($how) - { - // Prepare total calculation (if possible) - case 'CALC_TOTAL': - $m = null; - if (preg_match('/^(\s* SELECT)(.*)/six', $queryMain[0], $m)) - $queryMain[0] = $m[1] . ' SQL_CALC_FOUND_ROWS' . $m[2]; - return true; - - // Perform total calculation. - case 'GET_TOTAL': - // Built-in calculation available? - $queryMain = array('SELECT FOUND_ROWS()'); - return true; - } - - return false; - } - - - protected function _performQuery($queryMain) - { - $this->_lastQuery = $queryMain; - $this->_expandPlaceholders($queryMain, false); - $result = mysql_query($queryMain[0], $this->link); - if ($result === false) - return $this->_setDbError($queryMain[0]); - if (!is_resource($result)) { - if (preg_match('/^\s* INSERT \s+/six', $queryMain[0])) - { - // INSERT queries return generated ID. - return mysql_insert_id($this->link); - } - // Non-SELECT queries return number of affected rows, SELECT - resource. - return mysql_affected_rows($this->link); - } - return $result; - } - - - protected function _performFetch($result) - { - $row = mysql_fetch_assoc($result); - if (mysql_error()) return $this->_setDbError($this->_lastQuery); - if ($row === false) return null; - return $row; - } - - - protected function _setDbError($query) - { - if ($this->link) { - return $this->_setLastError(mysql_errno($this->link), mysql_error($this->link), $query); - } else { - return $this->_setLastError(mysql_errno(), mysql_error(), $query); - } - } -} - - -class DbSimple_Mysql_Blob implements DbSimple_Blob -{ - // MySQL does not support separate BLOB fetching. - private $blobdata = null; - private $curSeek = 0; - - public function __construct(&$database, $blobdata=null) - { - $this->blobdata = $blobdata; - $this->curSeek = 0; - } - - public function read($len) - { - $p = $this->curSeek; - $this->curSeek = min($this->curSeek + $len, strlen($this->blobdata)); - return substr($this->blobdata, $p, $len); - } - - public function write($data) - { - $this->blobdata .= $data; - } - - public function close() - { - return $this->blobdata; - } - - public function length() - { - return strlen($this->blobdata); - } -} -?> \ No newline at end of file diff --git a/includes/libs/DbSimple/Mysqli.php b/includes/libs/DbSimple/Mysqli.php index 44b1271d..2329e607 100644 --- a/includes/libs/DbSimple/Mysqli.php +++ b/includes/libs/DbSimple/Mysqli.php @@ -1,6 +1,6 @@ _setLastError('-1', 'mysqli extension is not loaded', 'mysqli'); + /** + * constructor(string $dsn) + * Connect to MySQL server. + */ + function DbSimple_Mysqli($dsn) + { - try - { - $this->link = mysqli_init(); + if (!is_callable("mysqli_connect")) + return $this->_setLastError("-1", "MySQLi extension is not loaded", "mysqli_connect"); - $this->link->options(MYSQLI_OPT_CONNECT_TIMEOUT, - isset($dsn['timeout']) && $dsn['timeout'] ? $dsn['timeout'] : 0); - - if (@$this->link->real_connect((isset($dsn['persist']) && $dsn['persist'])?'p:'.$dsn['host']:$dsn['host'], - $dsn['user'], isset($dsn['pass'])?$dsn['pass']:'', $base, - empty($dsn['port'])?NULL:$dsn['port'], NULL, - (isset($dsn['compression']) && $dsn['compression']) ? MYSQLI_CLIENT_COMPRESS : NULL)) - { - $this->link->set_charset((isset($dsn['enc']) ? $dsn['enc'] : 'UTF8')); - - $this->isMySQLnd = method_exists('mysqli_result', 'fetch_all'); + if (!empty($dsn["persist"])) { + if (version_compare(PHP_VERSION, '5.3') < 0) { + return $this->_setLastError("-1", "Persistent connections in MySQLi is allowable since PHP 5.3", "mysqli_connect"); + } else { + $dsn["host"] = "p:".$dsn["host"]; } - else - return $this->_setDbError(null, 'mysqli_real_connect @ ' . $dsn['host']); - } - catch (mysqli_sql_exception $e) - { - $this->_setLastError($e->getCode() , $e->getMessage(), 'new mysqli'); - } - } + } - protected function _performGetPlaceholderIgnoreRe() - { - return ' - " (?> [^"\\\\]+|\\\\"|\\\\)* " | - \' (?> [^\'\\\\]+|\\\\\'|\\\\)* \' | - ` (?> [^`]+ | ``)* ` | # backticks - /\* .*? \*/ # comments - '; - } + if ( isset($dsn['socket']) ) { + // Socket connection + $this->link = mysqli_connect( + null // host + ,empty($dsn['user']) ? 'root' : $dsn['user'] // user + ,empty($dsn['pass']) ? '' : $dsn['pass'] // password + ,preg_replace('{^/}s', '', $dsn['path']) // schema + ,null // port + ,$dsn['socket'] // socket + ); + } else if (isset($dsn['host']) ) { + // Host connection + $this->link = mysqli_connect( + $dsn['host'] + ,empty($dsn['user']) ? 'root' : $dsn['user'] + ,empty($dsn['pass']) ? '' : $dsn['pass'] + ,preg_replace('{^/}s', '', $dsn['path']) + ,empty($dsn['port']) ? null : $dsn['port'] + ); + } else { + return $this->_setDbError('mysqli_connect()'); + } + $this->_resetLastError(); + if (!$this->link) return $this->_setDbError('mysqli_connect()'); - protected function _performEscape($s, $isIdent=false) - { - if (!$isIdent) - { - return "'" .$this->link->escape_string($s). "'"; - } - else - { - return "`" . str_replace('`', '``', $s) . "`"; - } - } + mysqli_set_charset($this->link, isset($dsn['enc']) ? $dsn['enc'] : 'UTF8'); + } - protected function _performTransaction($parameters=null) - { - return $this->link->query('BEGIN'); - } - protected function _performCommit() - { - return $this->link->query('COMMIT'); - } + protected function _performEscape($s, $isIdent=false) + { + if (!$isIdent) + return "'" . mysqli_real_escape_string($this->link, $s) . "'"; + else + return "`" . str_replace('`', '``', $s) . "`"; + } - protected function _performRollback() - { - return $this->link->query('ROLLBACK'); - } - protected function _performQuery($queryMain) - { - $this->_lastQuery = $queryMain; + protected function _performNewBlob($blobid=null) + { + return new DbSimple_Mysqli_Blob($this, $blobid); + } - $this->_expandPlaceholders($queryMain, false); - $result = $this->link->query($queryMain[0]); + protected function _performGetBlobFieldNames($result) + { + $allFields = mysqli_fetch_fields($result); + $blobFields = array(); - if (!$result) - return $this->_setDbError($this->link, $queryMain[0]); + if (!empty($allFields)) + { + foreach ($allFields as $field) + if (stripos($field["type"], "BLOB") !== false) + $blobFields[] = $field["name"]; + } + return $blobFields; + } - if ($this->link->errno!=0) - return $this->_setDbError($this->link, $queryMain[0]); - if (preg_match('/^\s* INSERT \s+/six', $queryMain[0])) - return $this->link->insert_id; + protected function _performGetPlaceholderIgnoreRe() + { + return ' + " (?> [^"\\\\]+|\\\\"|\\\\)* " | + \' (?> [^\'\\\\]+|\\\\\'|\\\\)* \' | + ` (?> [^`]+ | ``)* ` | # backticks + /\* .*? \*/ # comments + '; + } - if ($this->link->field_count == 0) - return $this->link->affected_rows; - if ($this->isMySQLnd) - { - $res = $result->fetch_all(MYSQLI_ASSOC); - $result->close(); - } - else - { - $res = $result; - } + protected function _performTransaction($parameters=null) + { + return mysqli_begin_transaction($this->link); + } - return $res; - } - protected function _performTransformQuery(&$queryMain, $how) - { - // If we also need to calculate total number of found rows... - switch ($how) - { - // Prepare total calculation (if possible) - case 'CALC_TOTAL': - $m = null; - if (preg_match('/^(\s* SELECT)(.*)/six', $queryMain[0], $m)) - $queryMain[0] = $m[1] . ' SQL_CALC_FOUND_ROWS' . $m[2]; - return true; + protected function _performCommit() + { + return mysqli_commit($this->link); + } - // Perform total calculation. - case 'GET_TOTAL': - // Built-in calculation available? - $queryMain = array('SELECT FOUND_ROWS()'); - return true; - } - return false; - } - protected function _setDbError($obj,$q) - { - $info=$obj?$obj:$this->link; - return $this->_setLastError($info->errno, $info->error, $q); - } + protected function _performRollback() + { + return mysqli_rollback($this->link); + } - protected function _performNewBlob($id=null) - { - } - protected function _performGetBlobFieldNames($result) - { - return array(); - } + protected function _performTransformQuery(&$queryMain, $how) + { + // If we also need to calculate total number of found rows... + switch ($how) + { + // Prepare total calculation (if possible) + case 'CALC_TOTAL': + $m = null; + if (preg_match('/^(\s* SELECT)(.*)/six', $queryMain[0], $m)) + $queryMain[0] = $m[1] . ' SQL_CALC_FOUND_ROWS' . $m[2]; + return true; - protected function _performFetch($result) - { - if ($this->isMySQLnd) - return $result; + // Perform total calculation. + case 'GET_TOTAL': + // Built-in calculation available? + $queryMain = array('SELECT FOUND_ROWS()'); + return true; + } - $row = $result->fetch_assoc(); + return false; + } - if ($this->link->error) - return $this->_setDbError($this->_lastQuery); - if ($row === false) - { - $result->close(); - return null; - } - + protected function _performQuery($queryMain) + { + $this->_lastQuery = $queryMain; + $this->_expandPlaceholders($queryMain, false); + $result = mysqli_query($this->link, $queryMain[0]); + if ($result === false) + return $this->_setDbError($queryMain[0]); + if (!is_object($result)) { + if (preg_match('/^\s* INSERT \s+/six', $queryMain[0])) + { + // INSERT queries return generated ID. + return mysqli_insert_id($this->link); + } + // Non-SELECT queries return number of affected rows, SELECT - resource. + return mysqli_affected_rows($this->link); + } + return $result; + } + + + protected function _performFetch($result) + { + $row = mysqli_fetch_assoc($result); + if (mysql_error()) return $this->_setDbError($this->_lastQuery); + if ($row === false) return null; return $row; - } + } + + + protected function _setDbError($query) + { + if ($this->link) { + return $this->_setLastError(mysqli_errno($this->link), mysqli_error($this->link), $query); + } else { + return $this->_setLastError(mysqli_connect_errno(), mysqli_connect_error(), $query); + } + } } -?> \ No newline at end of file + +class DbSimple_Mysqli_Blob implements DbSimple_Blob +{ + // MySQL does not support separate BLOB fetching. + private $blobdata = null; + private $curSeek = 0; + + public function __construct(&$database, $blobdata=null) + { + $this->blobdata = $blobdata; + $this->curSeek = 0; + } + + public function read($len) + { + $p = $this->curSeek; + $this->curSeek = min($this->curSeek + $len, strlen($this->blobdata)); + return substr($this->blobdata, $p, $len); + } + + public function write($data) + { + $this->blobdata .= $data; + } + + public function close() + { + return $this->blobdata; + } + + public function length() + { + return strlen($this->blobdata); + } +} diff --git a/includes/libs/DbSimple/Postgresql.php b/includes/libs/DbSimple/Postgresql.php deleted file mode 100644 index 3dc3af8f..00000000 --- a/includes/libs/DbSimple/Postgresql.php +++ /dev/null @@ -1,312 +0,0 @@ -_setLastError("-1", "PostgreSQL extension is not loaded", "pg_connect"); - } - - // Prepare+execute works only in PHP 5.1+. - $this->DbSimple_Postgresql_USE_NATIVE_PHOLDERS = function_exists('pg_prepare'); - - $ok = $this->link = @pg_connect( - $t = (!empty($p['host']) ? 'host='.$p['host'].' ' : ''). - (!empty($p['port']) ? 'port='.$p['port'].' ' : ''). - 'dbname='.preg_replace('{^/}s', '', $p['path']).' '. - (!empty($p['user']) ? 'user='.$p['user'].' ' : ''). - (!empty($p['pass']) ? 'password='.$p['pass'].' ' : '') - ); - $this->_resetLastError(); - if (!$ok) return $this->_setDbError('pg_connect()'); - } - - - function _performEscape($s, $isIdent=false) - { - if (!$isIdent) - return "'" . str_replace("'", "''", $s) . "'"; - else - return '"' . str_replace('"', '_', $s) . '"'; - } - - - function _performTransaction($parameters=null) - { - return $this->query('BEGIN'); - } - - - function& _performNewBlob($blobid=null) - { - $obj =& new DbSimple_Postgresql_Blob($this, $blobid); - return $obj; - } - - - function _performGetBlobFieldNames($result) - { - $blobFields = array(); - for ($i=pg_num_fields($result)-1; $i>=0; $i--) { - $type = pg_field_type($result, $i); - if (strpos($type, "BLOB") !== false) $blobFields[] = pg_field_name($result, $i); - } - return $blobFields; - } - - // TODO: Real PostgreSQL escape - function _performGetPlaceholderIgnoreRe() - { - return ' - " (?> [^"\\\\]+|\\\\"|\\\\)* " | - \' (?> [^\'\\\\]+|\\\\\'|\\\\)* \' | - /\* .*? \*/ # comments - '; - } - - function _performGetNativePlaceholderMarker($n) - { - // PostgreSQL uses specific placeholders such as $1, $2, etc. - return '$' . ($n + 1); - } - - function _performCommit() - { - return $this->query('COMMIT'); - } - - - function _performRollback() - { - return $this->query('ROLLBACK'); - } - - - function _performTransformQuery(&$queryMain, $how) - { - - // If we also need to calculate total number of found rows... - switch ($how) { - // Prepare total calculation (if possible) - case 'CALC_TOTAL': - // Not possible - return true; - - // Perform total calculation. - case 'GET_TOTAL': - // TODO: GROUP BY ... -> COUNT(DISTINCT ...) - $re = '/^ - (?> -- [^\r\n]* | \s+)* - (\s* SELECT \s+) #1 - (.*?) #2 - (\s+ FROM \s+ .*?) #3 - ((?:\s+ ORDER \s+ BY \s+ .*?)?) #4 - ((?:\s+ LIMIT \s+ \S+ \s* (?: OFFSET \s* \S+ \s*)? )?) #5 - $/six'; - $m = null; - if (preg_match($re, $queryMain[0], $m)) { - $queryMain[0] = $m[1] . $this->_fieldList2Count($m[2]) . " AS C" . $m[3]; - $skipTail = substr_count($m[4] . $m[5], '?'); - if ($skipTail) array_splice($queryMain, -$skipTail); - } - return true; - } - - return false; - } - - - function _performQuery($queryMain) - { - $this->_lastQuery = $queryMain; - $isInsert = preg_match('/^\s* INSERT \s+/six', $queryMain[0]); - - // - // Note that in case of INSERT query we CANNOT work with prepare...execute - // cache, because RULEs do not work after pg_execute(). This is a very strange - // bug... To reproduce: - // $DB->query("CREATE TABLE test(id SERIAL, str VARCHAR(10)) WITH OIDS"); - // $DB->query("CREATE RULE test_r AS ON INSERT TO test DO (SELECT 111 AS id)"); - // print_r($DB->query("INSERT INTO test(str) VALUES ('test')")); - // In case INSERT + pg_execute() it returns new row OID (numeric) instead - // of result of RULE query. Strange, very strange... - // - - if ($this->DbSimple_Postgresql_USE_NATIVE_PHOLDERS && !$isInsert) { - // Use native placeholders only if PG supports them. - $this->_expandPlaceholders($queryMain, true); - $hash = md5($queryMain[0]); - if (!isset($this->prepareCache[$hash])) { - $this->prepareCache[$hash] = true; - $prepared = @pg_prepare($this->link, $hash, $queryMain[0]); - if ($prepared === false) return $this->_setDbError($queryMain[0]); - } else { - // Prepare cache hit! - } - $result = pg_execute($this->link, $hash, array_slice($queryMain, 1)); - } else { - // No support for native placeholders or INSERT query. - $this->_expandPlaceholders($queryMain, false); - $result = @pg_query($this->link, $queryMain[0]); - } - - if ($result === false) return $this->_setDbError($queryMain); - if (!pg_num_fields($result)) { - if ($isInsert) { - // INSERT queries return generated OID (if table is WITH OIDs). - // - // Please note that unfortunately we cannot use lastval() PostgreSQL - // stored function because it generates fatal error if INSERT query - // does not contain sequence-based field at all. This error terminates - // the current transaction, and we cannot continue to work nor know - // if table contains sequence-updateable field or not. - // - // To use auto-increment functionality you must invoke - // $insertedId = $DB->query("SELECT lastval()") - // manually where it is really needed. - // - return @pg_last_oid($result); - } - // Non-SELECT queries return number of affected rows, SELECT - resource. - return @pg_affected_rows($result); - } - return $result; - } - - - function _performFetch($result) - { - $row = @pg_fetch_assoc($result); - if (pg_last_error($this->link)) return $this->_setDbError($this->_lastQuery); - if ($row === false) return null; - return $row; - } - - - function _setDbError($query) - { - return $this->_setLastError(null, pg_last_error($this->link), $query); - } - - function _getVersion() - { - } -} - - -class DbSimple_Postgresql_Blob extends DbSimple_Generic_Blob -{ - var $blob; // resourse link - var $id; - var $database; - - function DbSimple_Postgresql_Blob(&$database, $id=null) - { - $this->database =& $database; - $this->database->transaction(); - $this->id = $id; - $this->blob = null; - } - - function read($len) - { - if ($this->id === false) return ''; // wr-only blob - if (!($e=$this->_firstUse())) return $e; - $data = @pg_lo_read($this->blob, $len); - if ($data === false) return $this->_setDbError('read'); - return $data; - } - - function write($data) - { - if (!($e=$this->_firstUse())) return $e; - $ok = @pg_lo_write($this->blob, $data); - if ($ok === false) return $this->_setDbError('add data to'); - return true; - } - - function close() - { - if (!($e=$this->_firstUse())) return $e; - if ($this->blob) { - $id = @pg_lo_close($this->blob); - if ($id === false) return $this->_setDbError('close'); - $this->blob = null; - } else { - $id = null; - } - $this->database->commit(); - return $this->id? $this->id : $id; - } - - function length() - { - if (!($e=$this->_firstUse())) return $e; - - @pg_lo_seek($this->blob, 0, PGSQL_SEEK_END); - $len = @pg_lo_tell($this->blob); - @pg_lo_seek($this->blob, 0, PGSQL_SEEK_SET); - - if (!$len) return $this->_setDbError('get length of'); - return $len; - } - - function _setDbError($query) - { - $hId = $this->id === null? "null" : ($this->id === false? "false" : $this->id); - $query = "-- $query BLOB $hId"; - $this->database->_setDbError($query); - } - - // Called on each blob use (reading or writing). - function _firstUse() - { - // BLOB opened - do nothing. - if (is_resource($this->blob)) return true; - - // Open or create blob. - if ($this->id !== null) { - $this->blob = @pg_lo_open($this->database->link, $this->id, 'rw'); - if ($this->blob === false) return $this->_setDbError('open'); - } else { - $this->id = @pg_lo_create($this->database->link); - $this->blob = @pg_lo_open($this->database->link, $this->id, 'w'); - if ($this->blob === false) return $this->_setDbError('create'); - } - return true; - } -} -?> \ No newline at end of file diff --git a/includes/libs/DbSimple/Zend/Cache.php b/includes/libs/DbSimple/Zend/Cache.php new file mode 100644 index 00000000..aff2e653 --- /dev/null +++ b/includes/libs/DbSimple/Zend/Cache.php @@ -0,0 +1,250 @@ +setBackend($backendObject); + return $frontendObject; + } + + /** + * Backend Constructor + * + * @param string $backend + * @param array $backendOptions + * @param boolean $customBackendNaming + * @param boolean $autoload + * @return Zend_Cache_Backend + */ + public static function _makeBackend($backend, $backendOptions, $customBackendNaming = false, $autoload = false) + { + if (!$customBackendNaming) { + $backend = self::_normalizeName($backend); + } + if (in_array($backend, Zend_Cache::$standardBackends)) { + // we use a standard backend + $backendClass = 'Zend_Cache_Backend_' . $backend; + // security controls are explicit + require_once str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php'; + } else { + // we use a custom backend + if (!preg_match('~^[\w\\\\]+$~D', $backend)) { + Zend_Cache::throwException("Invalid backend name [$backend]"); + } + if (!$customBackendNaming) { + // we use this boolean to avoid an API break + $backendClass = 'Zend_Cache_Backend_' . $backend; + } else { + $backendClass = $backend; + } + if (!$autoload) { + $file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php'; + if (!(self::_isReadable($file))) { + self::throwException("file $file not found in include_path"); + } + require_once $file; + } + } + return new $backendClass($backendOptions); + } + + /** + * Frontend Constructor + * + * @param string $frontend + * @param array $frontendOptions + * @param boolean $customFrontendNaming + * @param boolean $autoload + * @return Zend_Cache_Core|Zend_Cache_Frontend + */ + public static function _makeFrontend($frontend, $frontendOptions = array(), $customFrontendNaming = false, $autoload = false) + { + if (!$customFrontendNaming) { + $frontend = self::_normalizeName($frontend); + } + if (in_array($frontend, self::$standardFrontends)) { + // we use a standard frontend + // For perfs reasons, with frontend == 'Core', we can interact with the Core itself + $frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend; + // security controls are explicit + require_once str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php'; + } else { + // we use a custom frontend + if (!preg_match('~^[\w\\\\]+$~D', $frontend)) { + Zend_Cache::throwException("Invalid frontend name [$frontend]"); + } + if (!$customFrontendNaming) { + // we use this boolean to avoid an API break + $frontendClass = 'Zend_Cache_Frontend_' . $frontend; + } else { + $frontendClass = $frontend; + } + if (!$autoload) { + $file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php'; + if (!(self::_isReadable($file))) { + self::throwException("file $file not found in include_path"); + } + require_once $file; + } + } + return new $frontendClass($frontendOptions); + } + + /** + * Throw an exception + * + * Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic + * @param string $msg Message for the exception + * @throws Zend_Cache_Exception + */ + public static function throwException($msg, Exception $e = null) + { + // For perfs reasons, we use this dynamic inclusion + require_once 'Zend/Cache/Exception.php'; + throw new Zend_Cache_Exception($msg, 0, $e); + } + + /** + * Normalize frontend and backend names to allow multiple words TitleCased + * + * @param string $name Name to normalize + * @return string + */ + protected static function _normalizeName($name) + { + $name = ucfirst(strtolower($name)); + $name = str_replace(array('-', '_', '.'), ' ', $name); + $name = ucwords($name); + $name = str_replace(' ', '', $name); + if (stripos($name, 'ZendServer') === 0) { + $name = 'ZendServer_' . substr($name, strlen('ZendServer')); + } + + return $name; + } + + /** + * Returns TRUE if the $filename is readable, or FALSE otherwise. + * This function uses the PHP include_path, where PHP's is_readable() + * does not. + * + * Note : this method comes from Zend_Loader (see #ZF-2891 for details) + * + * @param string $filename + * @return boolean + */ + private static function _isReadable($filename) + { + if (!$fh = @fopen($filename, 'r', true)) { + return false; + } + @fclose($fh); + return true; + } + +} diff --git a/includes/libs/DbSimple/Zend/Cache/Backend/Interface.php b/includes/libs/DbSimple/Zend/Cache/Backend/Interface.php new file mode 100644 index 00000000..3f44e2e1 --- /dev/null +++ b/includes/libs/DbSimple/Zend/Cache/Backend/Interface.php @@ -0,0 +1,99 @@ + infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false); + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id); + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()); + +}