See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 /** 3 * Memory caching. 4 * 5 * This file is part of ADOdb, a Database Abstraction Layer library for PHP. 6 * 7 * @package ADOdb 8 * @link https://adodb.org Project's web site and documentation 9 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker 10 * 11 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause 12 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option, 13 * any later version. This means you can use it in proprietary products. 14 * See the LICENSE.md file distributed with this source code for details. 15 * @license BSD-3-Clause 16 * @license LGPL-2.1-or-later 17 * 18 * @copyright 2000-2013 John Lim 19 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community 20 * 21 * @noinspection PhpUnused 22 */ 23 24 // security - hide paths 25 if (!defined('ADODB_DIR')) die(); 26 27 global $ADODB_INCLUDED_MEMCACHE; 28 $ADODB_INCLUDED_MEMCACHE = 1; 29 30 global $ADODB_INCLUDED_CSV; 31 if (empty($ADODB_INCLUDED_CSV)) { 32 include_once (ADODB_DIR . '/adodb-csvlib.inc.php'); 33 } 34 35 class ADODB_Cache_MemCache 36 { 37 /** 38 * @var bool Prevents parent class calling non-existant function 39 */ 40 public $createdir = false; 41 42 /** 43 * @var array of hosts 44 */ 45 private $hosts; 46 47 /** 48 * @var int Connection Port, uses default 49 */ 50 private $port; 51 52 /** 53 * @var bool memcache compression with zlib 54 */ 55 private $compress; 56 57 /** 58 * @var array of options for memcached only 59 */ 60 private $options; 61 62 /** 63 * @var bool Internal flag indicating successful connection 64 */ 65 private $isConnected = false; 66 67 /** 68 * @var Memcache|Memcached Handle for the Memcache library 69 * 70 * Populated with the proper library on connect, used later when 71 * there are differences in specific calls between memcache and memcached 72 */ 73 private $memcacheLibrary = false; 74 75 /** 76 * @var array New server feature controller lists available servers 77 */ 78 private $serverControllers = array(); 79 80 /** 81 * @var array New server feature template uses granular server controller 82 */ 83 private $serverControllerTemplate = array( 84 'host' => '', 85 'port' => 11211, 86 'weight' => 0, 87 ); 88 89 /** 90 * An integer index into the libraries 91 * @see $libraries 92 */ 93 const MCLIB = 1; 94 const MCLIBD = 2; 95 96 /** 97 * @var array Xrefs the library flag to the actual class name 98 */ 99 private $libraries = array( 100 self::MCLIB => 'Memcache', 101 self::MCLIBD => 'Memcached' 102 ); 103 104 /** 105 * @var int An indicator of which library we are using 106 */ 107 private $libraryFlag; 108 109 /** 110 * Class Constructor. 111 * 112 * @param ADOConnection $db 113 */ 114 public function __construct($db) 115 { 116 $this->hosts = $db->memCacheHost; 117 $this->port = $this->serverControllerTemplate['port'] = $db->memCachePort; 118 $this->compress = $db->memCacheCompress; 119 $this->options = $db->memCacheOptions; 120 } 121 122 /** 123 * Return true if the current library is Memcached. 124 * @return bool 125 */ 126 public function isLibMemcached(): bool 127 { 128 return $this->libraryFlag == self::MCLIBD; 129 } 130 131 /** 132 * Lazy connection. 133 * 134 * The connection only occurs on CacheExecute call. 135 * 136 * @param string $err 137 * 138 * @return bool success of connecting to a server 139 */ 140 public function connect(&$err) 141 { 142 // do we have memcache or memcached? see the note at adodb.org on memcache 143 if (class_exists('Memcache')) { 144 $this->libraryFlag = self::MCLIB; 145 } elseif (class_exists('Memcached')) { 146 $this->libraryFlag = self::MCLIBD; 147 } else { 148 $err = 'Neither the Memcache nor Memcached PECL extensions were found!'; 149 return false; 150 } 151 152 $usedLibrary = $this->libraries[$this->libraryFlag]; 153 154 /** @var Memcache|Memcached $memCache */ 155 $memCache = new $usedLibrary; 156 if (!$memCache) { 157 $err = 'Memcache library failed to initialize'; 158 return false; 159 } 160 161 // Convert simple compression flag for memcached 162 if ($this->isLibMemcached()) { 163 $this->options[Memcached::OPT_COMPRESSION] = $this->compress; 164 } 165 166 // Are there any options available for memcached 167 if ($this->isLibMemcached() && count($this->options) > 0) { 168 $optionSuccess = $memCache->setOptions($this->options); 169 if (!$optionSuccess) { 170 $err = 'Invalid option parameters passed to Memcached'; 171 return false; 172 } 173 } 174 175 // Have we passed a controller array 176 if (!is_array($this->hosts)) { 177 $this->hosts = array($this->hosts); 178 } 179 180 if (!is_array($this->hosts[0])) { 181 // Old way, convert to controller 182 foreach ($this->hosts as $ipAddress) { 183 $connector = $this->serverControllerTemplate; 184 $connector['host'] = $ipAddress; 185 $connector['port'] = $this->port; 186 187 $this->serverControllers[] = $connector; 188 } 189 } else { 190 // New way, must validate port, etc 191 foreach ($this->hosts as $controller) { 192 $connector = array_merge($this->serverControllerTemplate, $controller); 193 if ($this->isLibMemcached()) { 194 $connector['weight'] = (int)$connector['weight']; 195 } else { 196 // Cannot use weight in memcache, simply discard 197 $connector['weight'] = 0; 198 } 199 200 $this->serverControllers[] = $connector; 201 } 202 } 203 204 // Checks for existing connections ( but only for memcached ) 205 if ($this->isLibMemcached() && !empty($memCache->getServerList())) { 206 // Use the existing configuration 207 $this->isConnected = true; 208 $this->memcacheLibrary = $memCache; 209 return true; 210 } 211 212 $failcnt = 0; 213 foreach ($this->serverControllers as $controller) { 214 if ($this->isLibMemcached()) { 215 if (!@$memCache->addServer($controller['host'], $controller['port'], $controller['weight'])) { 216 $failcnt++; 217 } 218 } else { 219 if (!@$memCache->addServer($controller['host'], $controller['port'])) { 220 $failcnt++; 221 } 222 } 223 } 224 if ($failcnt == sizeof($this->serverControllers)) { 225 $err = 'Can\'t connect to any memcache server'; 226 return false; 227 } 228 229 $this->memcacheLibrary = $memCache; 230 231 // A valid memcache connection is available 232 $this->isConnected = true; 233 return true; 234 } 235 236 /** 237 * Writes a cached query to the server 238 * 239 * @param string $filename The MD5 of the query to cache 240 * @param string $contents The query results 241 * @param bool $debug 242 * @param int $secs2cache 243 * 244 * @return bool true or false. true if successful save 245 */ 246 public function writeCache($filename, $contents, $debug, $secs2cache) 247 { 248 $err = ''; 249 if (!$this->isConnected && $debug) { 250 // Call to writeCache() before connect(), try to connect 251 if (!$this->connect($err)) { 252 ADOConnection::outp($err); 253 } 254 } else { 255 if (!$this->isConnected) { 256 $this->connect($err); 257 } 258 } 259 260 if (!$this->memcacheLibrary) { 261 return false; 262 } 263 264 $failed = false; 265 switch ($this->libraryFlag) { 266 case self::MCLIB: 267 if (!$this->memcacheLibrary->set($filename, $contents, $this->compress ? MEMCACHE_COMPRESSED : 0, 268 $secs2cache)) { 269 $failed = true; 270 } 271 break; 272 case self::MCLIBD: 273 if (!$this->memcacheLibrary->set($filename, $contents, $secs2cache)) { 274 $failed = true; 275 } 276 break; 277 default: 278 $failed = true; 279 break; 280 } 281 282 if ($failed) { 283 if ($debug) { 284 ADOConnection::outp(" Failed to save data at the memcache server!<br>\n"); 285 } 286 return false; 287 } 288 289 return true; 290 } 291 292 /** 293 * Reads a cached query from the server. 294 * 295 * @param string $filename The MD5 of the query to read 296 * @param string $err The query results 297 * @param int $secs2cache 298 * @param object $rsClass **UNUSED** 299 * 300 * @return object|bool record or false. 301 * 302 * @noinspection PhpUnusedParameterInspection 303 */ 304 public function readCache($filename, &$err, $secs2cache, $rsClass) 305 { 306 if (!$this->isConnected) { 307 $this->connect($err); 308 } 309 if (!$this->memcacheLibrary) { 310 return false; 311 } 312 313 $rs = $this->memcacheLibrary->get($filename); 314 if (!$rs) { 315 $err = 'Item with such key doesn\'t exist on the memcache server.'; 316 return false; 317 } 318 319 // hack, should actually use _csv2rs 320 $rs = explode("\n", $rs); 321 unset($rs[0]); 322 $rs = join("\n", $rs); 323 $rs = unserialize($rs); 324 if (!is_object($rs)) { 325 $err = 'Unable to unserialize $rs'; 326 return false; 327 } 328 if ($rs->timeCreated == 0) { 329 return $rs; 330 } // apparently have been reports that timeCreated was set to 0 somewhere 331 332 $tdiff = intval($rs->timeCreated + $secs2cache - time()); 333 if ($tdiff <= 2) { 334 switch ($tdiff) { 335 case 2: 336 if ((rand() & 15) == 0) { 337 $err = "Timeout 2"; 338 return false; 339 } 340 break; 341 case 1: 342 if ((rand() & 3) == 0) { 343 $err = "Timeout 1"; 344 return false; 345 } 346 break; 347 default: 348 $err = "Timeout 0"; 349 return false; 350 } 351 } 352 return $rs; 353 } 354 355 /** 356 * Flushes all of the stored memcache data 357 * 358 * @param bool $debug 359 * 360 * @return bool The response from the memcache server 361 */ 362 public function flushAll($debug = false) 363 { 364 if (!$this->isConnected) { 365 $err = ''; 366 if (!$this->connect($err) && $debug) { 367 ADOConnection::outp($err); 368 } 369 } 370 if (!$this->memcacheLibrary) { 371 return false; 372 } 373 374 $del = $this->memcacheLibrary->flush(); 375 376 if ($debug) { 377 if (!$del) { 378 ADOConnection::outp("flushall: failed!<br>\n"); 379 } else { 380 ADOConnection::outp("flushall: succeeded!<br>\n"); 381 } 382 } 383 384 return $del; 385 } 386 387 /** 388 * Flushes the contents of a specified query 389 * 390 * @param string $filename The MD5 of the query to flush 391 * @param bool $debug 392 * 393 * @return bool The response from the memcache server 394 */ 395 public function flushCache($filename, $debug = false) 396 { 397 if (!$this->isConnected) { 398 $err = ''; 399 if (!$this->connect($err) && $debug) { 400 ADOConnection::outp($err); 401 } 402 } 403 if (!$this->memcacheLibrary) { 404 return false; 405 } 406 407 $del = $this->memcacheLibrary->delete($filename); 408 409 if ($debug) { 410 if (!$del) { 411 ADOConnection::outp("flushcache: $filename entry doesn't exist on memcache server!<br>\n"); 412 } else { 413 ADOConnection::outp("flushcache: $filename entry flushed from memcache server!<br>\n"); 414 } 415 } 416 417 return $del; 418 } 419 420 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body