00001 <?
00017 class CacheBot
00018 {
00022 private static $bot = null;
00023
00027 private function __construct()
00028 {
00029 }
00030
00036 public static function getBot()
00037 {
00038
00039 if (self::$bot instanceOf EasyCache)
00040 return self::$bot;
00041
00042 else
00043 {
00044 self::setBot(new NoCache());
00045 return self::getBot();
00046 }
00047 }
00048
00054 public static function setBot($bot, $prefix = '')
00055 {
00056 if ($bot instanceOf EasyCache)
00057 self::$bot = $bot;
00058 else
00059 throw new Exception('Cachebots must be a derivitive of EasyCache');
00060 }
00061
00072 public static function get($key, $life = null)
00073 {
00074
00075 if ($life !== null)
00076 {
00077 $oldLife = EasyCache::$life;
00078 EasyCache::$life = (int)$life;
00079 }
00080
00081 $rval = self::$bot->get($key);
00082
00083
00084 if (isset($oldLife))
00085 EasyCache::$life = $oldLife;
00086
00087 return $rval;
00088 }
00089
00098 public static function set($key, $data, $life = null)
00099 {
00100
00101 if ($life !== null)
00102 {
00103 $oldLife = EasyCache::$life;
00104 EasyCache::$life = (int)$life;
00105 }
00106
00107
00108 $rval = self::$bot->set($key, $data);
00109
00110
00111 if (isset($oldLife))
00112 EasyCache::$life = $oldLife;
00113
00114
00115 return $rval;
00116 }
00117
00122 public static function delete($key)
00123 {
00124 return self::$bot->delete($key);
00125 }
00126
00131 public static function flush()
00132 {
00133 return self::$bot->flush();
00134 }
00135 }
00136
00140 abstract class EasyCache
00141 {
00145 public static $life = 3600;
00146
00150 public static $hits = 0;
00151
00155 private static $keys = array();
00156
00162 public function __construct($life = null)
00163 {
00164 if ($life)
00165 self::$life = (int)$life;
00166 }
00167
00178 abstract public function get($key);
00179
00188 abstract public function set($key, $data);
00189
00195 abstract public function delete($key);
00196
00200 abstract public function flush();
00201
00209 public static function markCacheHit($key, $type = 'get')
00210 {
00211
00212 self::$hits++;
00213
00214
00215 if (Config::get("bj_track_cache"))
00216 {
00217 self::$keys['keys'][] = $key;
00218 self::$keys['type'][] = $type;
00219 }
00220 }
00221
00227 public static function drawCacheStats()
00228 {
00229 global $me;
00230
00231 echo "<div class=\"cacheHits\">";
00232 foreach (self::$keys['keys'] AS $index => $key)
00233 {
00234 if (is_array($key))
00235 {
00236 $links = array();
00237 foreach ($key AS $val)
00238 $links[] = $me->getLink("admin.viewcache?val=" . base64_encode($val), $val);
00239
00240 echo "<p>Get Keyset:" . implode(", ", $links) . "</p>";
00241 }
00242 else
00243 echo "<p>" . ucfirst(self::$keys['type'][$index]) . ": " . $me->getLink("admin.viewcache?key=" . base64_encode($key), $key) . "</p>\n";
00244 }
00245 echo "</div>";
00246 }
00247 }
00248
00257 class EasyMemCache extends EasyCache
00258 {
00259 public $mc;
00260
00267 public function __construct($servers = 'localhost:112211', $life = null)
00268 {
00269
00270 if (!class_exists('Memcache'))
00271 throw new Exception('Memcache is not installed in PHP.');
00272
00273
00274 parent::__construct($life);
00275
00276
00277 $this->mc = new Memcache;
00278
00279
00280 if (is_string($servers))
00281 $servers = array($servers);
00282
00283
00284 if (count($servers))
00285 foreach ($servers AS $server)
00286 if (preg_match('/^(.*):([0-9]*)$/', $server, $matches))
00287 $this->mc->addServer($matches[1], $matches[2]);
00288 else
00289 throw new Exception('Weird servers passed to EasyMemCache.');
00290 }
00291
00292 public function get($key)
00293 {
00294 self::markCacheHit($key, 'get');
00295
00296
00297 if (is_array($key))
00298 {
00299 $ret = array();
00300
00301
00302 if (count($key))
00303 {
00304
00305 foreach ($key AS $id)
00306 $ret[$id] = false;
00307
00308
00309 $data = $this->mc->get($key);
00310
00311
00312 foreach ($data AS $index => $val)
00313 $ret[$index] = $val;
00314 }
00315
00316 return $ret;
00317 }
00318
00319 else
00320 return $this->mc->get($key);
00321 }
00322
00323 public function set($key, $data)
00324 {
00325 self::markCacheHit($key, 'set');
00326
00327 return $this->mc->set($key, $data, MEMCACHE_COMPRESSED, self::$life);
00328 }
00329
00330 public function delete($key)
00331 {
00332 self::markCacheHit($key, 'delete');
00333
00334 return $this->mc->delete($key);
00335 }
00336
00337 public function flush()
00338 {
00339 $this->mc->flush();
00340 }
00341 }
00342
00350 class EasyFileCache extends EasyCache
00351 {
00352 private $path;
00353
00361 public function __construct($path = "/tmp/EasyCache/", $life = null)
00362 {
00363 parent::__construct($life);
00364
00365 $this->path = $path;
00366
00367
00368 if (!is_dir($this->path))
00369 mkdir($this->path, 0777, true);
00370 }
00371
00375 public function get($key)
00376 {
00377
00378 if (is_array($key))
00379 {
00380 $ret = array();
00381
00382
00383 if (count($key))
00384 foreach ($key AS $single)
00385 $ret[$single] = $this->get($single);
00386
00387 return $ret;
00388 }
00389
00390 else
00391 {
00392
00393 self::markCacheHit($key, 'get');
00394
00395
00396 if ($this->isCached($key))
00397 {
00398 $data = file_get_contents($this->getCachePath($key));
00399 return unserialize($data);
00400 }
00401 else
00402 return null;
00403 }
00404 }
00405
00414 public function set($key, $data)
00415 {
00416 self::markCacheHit($key, 'set');
00417
00418 file_put_contents($this->getCachePath($key), serialize($data));
00419 }
00420
00426 public function delete($key)
00427 {
00428 self::markCacheHit($key, 'delete');
00429
00430 $file = $this->getCachePath($key);
00431
00432 if (file_exists($file))
00433 unlink($file);
00434 }
00435
00436 public function flush()
00437 {
00438
00439 $cmd = "find $this->path -type f | xargs rm";
00440 Util::shellExec($cmd);
00441 }
00442
00450 protected function isCached($key)
00451 {
00452 $file = $this->getCachePath($key);
00453
00454
00455 if (file_exists($file))
00456 {
00457
00458 $minAge = time() - self::$life;
00459 if (filemtime($file) >= $minAge)
00460 return true;
00461
00462 else
00463 $this->delete($key);
00464 }
00465
00466 return false;
00467 }
00468
00474 protected function getCachePath($key)
00475 {
00476 return $this->path . sha1($key);
00477 }
00478 }
00479
00487 class EasyDBCache extends EasyCache
00488 {
00489 private $table;
00490
00497 public function __construct($table = "easy_cache", $life = null)
00498 {
00499 parent::__construct($life);
00500
00501 $this->table = $table;
00502
00503
00504
00505
00506 }
00507
00508 protected function createTable()
00509 {
00510 dbQuery("
00511 CREATE TABLE $this->table
00512 (
00513 `id` varchar(255) default '' not null,
00514 `data` mediumtext default '' not null,
00515 `expire_date` datetime not null,
00516 KEY(id)
00517 ) ENGINE=InnoDB
00518 ");
00519 }
00520
00524 public function get($key)
00525 {
00526 self::markCacheHit($key, 'get');
00527
00528
00529 if (is_array($key))
00530 {
00531
00532 $rval = array();
00533
00534
00535 if (count($key))
00536 {
00537
00538 foreach ($key AS $id)
00539 $rval[$id] = false;
00540
00541
00542 $rs = dbQuery("
00543 SELECT ec.*, ec.expire_date <= NOW() AS expired
00544 FROM $this->table ec
00545 WHERE ec.id IN ('" . implode("', '", $key) . "')
00546 ");
00547
00548
00549 while ($ar = dbFetchAssoc($rs))
00550 {
00551
00552 $id = $ar['id'];
00553
00554
00555 if ((int)$ar['expired'])
00556 $this->delete($id);
00557
00558 else
00559 $rval[$id] = unserialize($ar['data']);
00560 }
00561 }
00562
00563
00564 return $rval;
00565 }
00566 $ar = dbFetchAssoc(dbQuery("
00567 SELECT ec.*, ec.expire_date <= NOW() AS expired
00568 FROM $this->table ec
00569 WHERE id = '$key'
00570 "));
00571
00572 if (is_array($ar))
00573 {
00574
00575 if ((int)$ar['expired'])
00576 $this->delete($key);
00577 else
00578 return unserialize($ar['data']);
00579 }
00580
00581
00582 return null;
00583 }
00584
00593 public function set($key, $data)
00594 {
00595 self::markCacheHit($key, 'set');
00596
00597
00598 $this->delete($key);
00599
00600
00601 $data = dbEscape(serialize($data));
00602
00603
00604 dbExecute("
00605 INSERT INTO $this->table
00606 (id, data, expire_date)
00607 VALUES
00608 ('$key', '$data', DATE_ADD(NOW(), INTERVAL " . self::$life . " SECOND))
00609 ");
00610 }
00611
00617 public function delete($key)
00618 {
00619 self::markCacheHit($key, 'delete');
00620
00621 dbExecute("
00622 DELETE FROM $this->table
00623 WHERE id = '$key'
00624 ");
00625 }
00626
00627 public function flush()
00628 {
00629 dbExecute("
00630 DELETE FROM $this->table
00631 ");
00632 }
00633 }
00634
00640 class NoCache extends EasyCache
00641 {
00642 public function get($key)
00643 {
00644 self::markCacheHit($key, 'get');
00645 return null;
00646 }
00647
00648 public function set($key, $data)
00649 {
00650 self::markCacheHit($key, 'set');
00651 return true;
00652 }
00653
00654 public function delete($key)
00655 {
00656 self::markCacheHit($key, 'delete');
00657 return true;
00658 }
00659
00660 public function flush()
00661 {
00662 return true;
00663 }
00664 }
00665
00667 ?>