AutorÃa | Ultima modificación | Ver Log |
<?php/*** Memory caching.** This file is part of ADOdb, a Database Abstraction Layer library for PHP.** @package ADOdb* @link https://adodb.org Project's web site and documentation* @link https://github.com/ADOdb/ADOdb Source code and issue tracker** The ADOdb Library is dual-licensed, released under both the BSD 3-Clause* and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,* any later version. This means you can use it in proprietary products.* See the LICENSE.md file distributed with this source code for details.* @license BSD-3-Clause* @license LGPL-2.1-or-later** @copyright 2000-2013 John Lim* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community** @noinspection PhpUnused*/// security - hide pathsif (!defined('ADODB_DIR')) die();global $ADODB_INCLUDED_MEMCACHE;$ADODB_INCLUDED_MEMCACHE = 1;global $ADODB_INCLUDED_CSV;if (empty($ADODB_INCLUDED_CSV)) {include_once(ADODB_DIR . '/adodb-csvlib.inc.php');}class ADODB_Cache_MemCache{/*** @var bool Prevents parent class calling non-existant function*/public $createdir = false;/*** @var array of hosts*/private $hosts;/*** @var int Connection Port, uses default*/private $port;/*** @var bool memcache compression with zlib*/private $compress;/*** @var array of options for memcached only*/private $options;/*** @var bool Internal flag indicating successful connection*/private $isConnected = false;/*** @var Memcache|Memcached Handle for the Memcache library** Populated with the proper library on connect, used later when* there are differences in specific calls between memcache and memcached*/private $memcacheLibrary = false;/*** @var array New server feature controller lists available servers*/private $serverControllers = array();/*** @var array New server feature template uses granular server controller*/private $serverControllerTemplate = array('host' => '','port' => 11211,'weight' => 0,);/*** An integer index into the libraries* @see $libraries*/const MCLIB = 1;const MCLIBD = 2;/*** @var array Xrefs the library flag to the actual class name*/private $libraries = array(self::MCLIB => 'Memcache',self::MCLIBD => 'Memcached');/*** @var int An indicator of which library we are using*/private $libraryFlag;/*** Class Constructor.** @param ADOConnection $db*/public function __construct($db){$this->hosts = $db->memCacheHost;$this->port = $this->serverControllerTemplate['port'] = $db->memCachePort;$this->compress = $db->memCacheCompress;$this->options = $db->memCacheOptions;}/*** Return true if the current library is Memcached.* @return bool*/public function isLibMemcached(): bool{return $this->libraryFlag == self::MCLIBD;}/*** Lazy connection.** The connection only occurs on CacheExecute call.** @param string $err** @return bool success of connecting to a server*/public function connect(&$err){// do we have memcache or memcached? see the note at adodb.org on memcacheif (class_exists('Memcache')) {$this->libraryFlag = self::MCLIB;} elseif (class_exists('Memcached')) {$this->libraryFlag = self::MCLIBD;} else {$err = 'Neither the Memcache nor Memcached PECL extensions were found!';return false;}$usedLibrary = $this->libraries[$this->libraryFlag];/** @var Memcache|Memcached $memCache */$memCache = new $usedLibrary;if (!$memCache) {$err = 'Memcache library failed to initialize';return false;}// Convert simple compression flag for memcachedif ($this->isLibMemcached()) {$this->options[Memcached::OPT_COMPRESSION] = $this->compress;}// Are there any options available for memcachedif ($this->isLibMemcached() && count($this->options) > 0) {$optionSuccess = $memCache->setOptions($this->options);if (!$optionSuccess) {$err = 'Invalid option parameters passed to Memcached';return false;}}// Have we passed a controller arrayif (!is_array($this->hosts)) {$this->hosts = array($this->hosts);}if (!is_array($this->hosts[0])) {// Old way, convert to controllerforeach ($this->hosts as $ipAddress) {$connector = $this->serverControllerTemplate;$connector['host'] = $ipAddress;$connector['port'] = $this->port;$this->serverControllers[] = $connector;}} else {// New way, must validate port, etcforeach ($this->hosts as $controller) {$connector = array_merge($this->serverControllerTemplate, $controller);if ($this->isLibMemcached()) {$connector['weight'] = (int)$connector['weight'];} else {// Cannot use weight in memcache, simply discard$connector['weight'] = 0;}$this->serverControllers[] = $connector;}}// Checks for existing connections ( but only for memcached )if ($this->isLibMemcached() && !empty($memCache->getServerList())) {// Use the existing configuration$this->isConnected = true;$this->memcacheLibrary = $memCache;return true;}$failcnt = 0;foreach ($this->serverControllers as $controller) {if ($this->isLibMemcached()) {if (!@$memCache->addServer($controller['host'], $controller['port'], $controller['weight'])) {$failcnt++;}} else {if (!@$memCache->addServer($controller['host'], $controller['port'])) {$failcnt++;}}}if ($failcnt == sizeof($this->serverControllers)) {$err = 'Can\'t connect to any memcache server';return false;}$this->memcacheLibrary = $memCache;// A valid memcache connection is available$this->isConnected = true;return true;}/*** Writes a cached query to the server** @param string $filename The MD5 of the query to cache* @param string $contents The query results* @param bool $debug* @param int $secs2cache** @return bool true or false. true if successful save*/public function writeCache($filename, $contents, $debug, $secs2cache){$err = '';if (!$this->isConnected && $debug) {// Call to writeCache() before connect(), try to connectif (!$this->connect($err)) {ADOConnection::outp($err);}} else {if (!$this->isConnected) {$this->connect($err);}}if (!$this->memcacheLibrary) {return false;}$failed = false;switch ($this->libraryFlag) {case self::MCLIB:if (!$this->memcacheLibrary->set($filename, $contents, $this->compress ? MEMCACHE_COMPRESSED : 0,$secs2cache)) {$failed = true;}break;case self::MCLIBD:if (!$this->memcacheLibrary->set($filename, $contents, $secs2cache)) {$failed = true;}break;default:$failed = true;break;}if ($failed) {if ($debug) {ADOConnection::outp(" Failed to save data at the memcache server!<br>\n");}return false;}return true;}/*** Reads a cached query from the server.** @param string $filename The MD5 of the query to read* @param string $err The query results* @param int $secs2cache* @param object $rsClass **UNUSED**** @return object|bool record or false.** @noinspection PhpUnusedParameterInspection*/public function readCache($filename, &$err, $secs2cache, $rsClass){if (!$this->isConnected) {$this->connect($err);}if (!$this->memcacheLibrary) {return false;}$rs = $this->memcacheLibrary->get($filename);if (!$rs) {$err = 'Item with such key doesn\'t exist on the memcache server.';return false;}// hack, should actually use _csv2rs$rs = explode("\n", $rs);unset($rs[0]);$rs = join("\n", $rs);$rs = unserialize($rs);if (!is_object($rs)) {$err = 'Unable to unserialize $rs';return false;}if ($rs->timeCreated == 0) {return $rs;} // apparently have been reports that timeCreated was set to 0 somewhere$tdiff = intval($rs->timeCreated + $secs2cache - time());if ($tdiff <= 2) {switch ($tdiff) {case 2:if ((rand() & 15) == 0) {$err = "Timeout 2";return false;}break;case 1:if ((rand() & 3) == 0) {$err = "Timeout 1";return false;}break;default:$err = "Timeout 0";return false;}}return $rs;}/*** Flushes all of the stored memcache data** @param bool $debug** @return bool The response from the memcache server*/public function flushAll($debug = false){if (!$this->isConnected) {$err = '';if (!$this->connect($err) && $debug) {ADOConnection::outp($err);}}if (!$this->memcacheLibrary) {return false;}$del = $this->memcacheLibrary->flush();if ($debug) {if (!$del) {ADOConnection::outp("flushall: failed!<br>\n");} else {ADOConnection::outp("flushall: succeeded!<br>\n");}}return $del;}/*** Flushes the contents of a specified query** @param string $filename The MD5 of the query to flush* @param bool $debug** @return bool The response from the memcache server*/public function flushCache($filename, $debug = false){if (!$this->isConnected) {$err = '';if (!$this->connect($err) && $debug) {ADOConnection::outp($err);}}if (!$this->memcacheLibrary) {return false;}$del = $this->memcacheLibrary->delete($filename);if ($debug) {if (!$del) {ADOConnection::outp("flushcache: $filename entry doesn't exist on memcache server!<br>\n");} else {ADOConnection::outp("flushcache: $filename entry flushed from memcache server!<br>\n");}}return $del;}}