<?php
> /**
> * Memory caching.
// security - hide paths
> *
if (!defined('ADODB_DIR')) die();
> * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
> *
global $ADODB_INCLUDED_MEMCACHE;
> * @package ADOdb
$ADODB_INCLUDED_MEMCACHE = 1;
> * @link https://adodb.org Project's web site and documentation
> * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
global $ADODB_INCLUDED_CSV;
> *
if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
> * 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.
@version v5.21.0 2021-02-27
> * @license BSD-3-Clause
@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
> * @license LGPL-2.1-or-later
@copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
> *
Released under both BSD license and Lesser GPL library license.
> * @copyright 2000-2013 John Lim
Whenever there is any discrepancy between the two licenses,
> * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
the BSD license will take precedence. See License.txt.
> *
Set tabs to 4 for best viewing.
> * @noinspection PhpUnused
> */
< if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
<
< /*
> if (empty($ADODB_INCLUDED_CSV)) {
> include_once(ADODB_DIR . '/adodb-csvlib.inc.php');
> }
< @version v5.21.0 2021-02-27
< @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
< @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
< Released under both BSD license and Lesser GPL library license.
< Whenever there is any discrepancy between the two licenses,
< the BSD license will take precedence. See License.txt.
< Set tabs to 4 for best viewing.
> class ADODB_Cache_MemCache
> {
> /**
> * @var bool Prevents parent class calling non-existant function
> */
> public $createdir = false;
< Latest version is available at https://adodb.org/
> /**
> * @var array of hosts
> */
> private $hosts;
< Usage:
> /**
> * @var int Connection Port, uses default
> */
> private $port;
< $db = NewADOConnection($driver);
< $db->memCache = true; /// should we use memCache instead of caching in files
< $db->memCacheHost = array($ip1, $ip2, $ip3);
< $db->memCachePort = 11211; /// this is default memCache port
< $db->memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
< /// Note; compression is not supported w/the memcached library
> /**
> * @var bool memcache compression with zlib
> */
> private $compress;
< $db->Connect(...);
< $db->CacheExecute($sql);
> /**
> * @var array of options for memcached only
> */
> private $options;
< Notes; The memcache class is shared by all connections, is created during the first call to Connect/PConnect.
< We'll look for both the memcache library (https://pecl.php.net/package/memcache) and the memcached
< library (https://pecl.php.net/package/memcached). If both exist, the memcache library will be used.
> /**
> * @var bool Internal flag indicating successful connection
> */
> private $isConnected = false;
< Class instance is stored in $ADODB_CACHE
> /**
> * @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
// $library will be populated with the proper library on connect
> private $memcacheLibrary = false;
< class ADODB_Cache_MemCache {
< var $createdir = false; // create caching directory structure?
> /**
> * @var array New server feature controller lists available servers
> */
> private $serverControllers = array();
< // $library will be populated with the proper library on connect
< // and is used later when there are differences in specific calls
< // between memcache and memcached
< var $library = false;
> /**
> * @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;
< //-----------------------------
< // memcache specific variables
> /**
> * @var array Xrefs the library flag to the actual class name
> */
> private $libraries = array(
> self::MCLIB => 'Memcache',
> self::MCLIBD => 'Memcached'
> );
< var $hosts; // array of hosts
< var $port = 11211;
< var $compress = false; // memcache compression with zlib
> /**
> * @var int An indicator of which library we are using
> */
> private $libraryFlag;
< var $_connected = false;
< var $_memcache = false;
> /**
> * 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;
> }
< function __construct(&$obj)
> /**
> * Return true if the current library is Memcached.
> * @return bool
> */
> public function isLibMemcached(): bool
{
< $this->hosts = $obj->memCacheHost;
< $this->port = $obj->memCachePort;
< $this->compress = $obj->memCacheCompress;
> return $this->libraryFlag == self::MCLIBD;
}
< // implement as lazy connection. The connection only occurs on CacheExecute call
< function connect(&$err)
> /**
> * 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?
> // do we have memcache or memcached? see the note at adodb.org on memcache
if (class_exists('Memcache')) {
< $this->library='Memcache';
< $memcache = new MemCache;
> $this->libraryFlag = self::MCLIB;
} elseif (class_exists('Memcached')) {
< $this->library='Memcached';
< $memcache = new MemCached;
> $this->libraryFlag = self::MCLIBD;
} else {
$err = 'Neither the Memcache nor Memcached PECL extensions were found!';
return false;
}
< if (!is_array($this->hosts)) $this->hosts = array($this->hosts);
> $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 memcached
> if ($this->isLibMemcached()) {
> $this->options[Memcached::OPT_COMPRESSION] = $this->compress;
> }
>
> // Are there any options available for memcached
> if ($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 array
> if (!is_array($this->hosts)) {
> $this->hosts = array($this->hosts);
> }
>
> if (!is_array($this->hosts[0])) {
> // Old way, convert to controller
> foreach ($this->hosts as $ipAddress) {
> $connector = $this->serverControllerTemplate;
> $connector['host'] = $ipAddress;
> $connector['port'] = $this->port;
>
> $this->serverControllers[] = $connector;
> }
> } else {
> // New way, must validate port, etc
> foreach ($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->hosts as $host) {
< if (!@$memcache->addServer($host,$this->port)) {
< $failcnt += 1;
> 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->hosts)) {
> }
> if ($failcnt == sizeof($this->serverControllers)) {
$err = 'Can\'t connect to any memcache server';
return false;
}
< $this->_connected = true;
< $this->_memcache = $memcache;
>
> $this->memcacheLibrary = $memCache;
>
> // A valid memcache connection is available
> $this->isConnected = true;
return true;
}
< // returns true or false. true if successful save
< function writecache($filename, $contents, $debug, $secs2cache)
> /**
> * 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)
{
< if (!$this->_connected) {
$err = '';
< if (!$this->connect($err) && $debug) ADOConnection::outp($err);
> if (!$this->isConnected && $debug) {
> // Call to writeCache() before connect(), try to connect
> if (!$this->connect($err)) {
> ADOConnection::outp($err);
> }
> } else {
> if (!$this->isConnected) {
> $this->connect($err);
> }
> }
>
> if (!$this->memcacheLibrary) {
> return false;
}
< if (!$this->_memcache) return false;
$failed=false;
< switch ($this->library) {
< case 'Memcache':
< if (!$this->_memcache->set($filename, $contents, $this->compress ? MEMCACHE_COMPRESSED : 0, $secs2cache)) {
> switch ($this->libraryFlag) {
> case self::MCLIB:
> if (!$this->memcacheLibrary->set($filename, $contents, $this->compress ? MEMCACHE_COMPRESSED : 0,
> $secs2cache)) {
$failed=true;
}
break;
< case 'Memcached':
< if (!$this->_memcache->set($filename, $contents, $secs2cache)) {
> 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");
> if ($debug) {
> ADOConnection::outp(" Failed to save data at the memcache server!<br>\n");
> }
return false;
}
return true;
}
< // returns a recordset
< function readcache($filename, &$err, $secs2cache, $rsClass)
> /**
> * 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)
{
< $false = false;
< if (!$this->_connected) $this->connect($err);
< if (!$this->_memcache) return $false;
> if (!$this->isConnected) {
> $this->connect($err);
> }
> if (!$this->memcacheLibrary) {
> return false;
> }
< $rs = $this->_memcache->get($filename);
> $rs = $this->memcacheLibrary->get($filename);
if (!$rs) {
$err = 'Item with such key doesn\'t exist on the memcache server.';
< return $false;
> 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;
> return false;
}
< if ($rs->timeCreated == 0) return $rs; // apparently have been reports that timeCreated was set to 0 somewhere
> 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;
> return false;
}
break;
case 1:
if ((rand() & 3) == 0) {
$err = "Timeout 1";
< return $false;
> return false;
}
break;
default:
$err = "Timeout 0";
< return $false;
> return false;
}
}
return $rs;
}
< function flushall($debug=false)
> /**
> * 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->_connected) {
> if (!$this->isConnected) {
$err = '';
< if (!$this->connect($err) && $debug) ADOConnection::outp($err);
> if (!$this->connect($err) && $debug) {
> ADOConnection::outp($err);
> }
> }
> if (!$this->memcacheLibrary) {
> return false;
}
< if (!$this->_memcache) return false;
< $del = $this->_memcache->flush();
> $del = $this->memcacheLibrary->flush();
< if ($debug)
< if (!$del) ADOConnection::outp("flushall: failed!<br>\n");
< else ADOConnection::outp("flushall: succeeded!<br>\n");
> if ($debug) {
> if (!$del) {
> ADOConnection::outp("flushall: failed!<br>\n");
> } else {
> ADOConnection::outp("flushall: succeeded!<br>\n");
> }
> }
return $del;
}
< function flushcache($filename, $debug=false)
> /**
> * 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->_connected) {
> if (!$this->isConnected) {
$err = '';
< if (!$this->connect($err) && $debug) ADOConnection::outp($err);
> if (!$this->connect($err) && $debug) {
> ADOConnection::outp($err);
> }
> }
> if (!$this->memcacheLibrary) {
> return false;
}
< if (!$this->_memcache) return false;
< $del = $this->_memcache->delete($filename);
> $del = $this->memcacheLibrary->delete($filename);
< if ($debug)
< if (!$del) ADOConnection::outp("flushcache: $key entry doesn't exist on memcache server!<br>\n");
< else ADOConnection::outp("flushcache: $key entry flushed from memcache server!<br>\n");
> 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;
}
< // not used for memcache
< function createdir($dir, $hash)
< {
< return true;
< }
}