dataDir = "/tmp/"; $this->dataTempDir = "objectcache"; $this->hash = "objectbase"; $this->dieOnError = 1; $this->debug = 1; $this->servers = array( array("host"=>'memcache',"port"=>'113211'), ); $this->debugMessage =""; if(isset($options['dataDir'])) $this->dataDir = $options['dataDir']; if(isset($options['hash'])) $this->hash = $options['hash']; if(isset($options['servers'])) $this->servers = $options['servers']; if(isset($options['dieOnError'])) $this->dieOnError = $options['dieOnError']; if(isset($options['debug'])) $this->debug = $options['debug']; $this->setDebugMessage("testing memcache servers"); if (count($this->servers)>=1){ $m = new MemcachedAggregator($this->servers); if ($m->status) { $this->memcache = $m; $this->cachingType = 1; $this->setDebugMessage("using memcache servers"); } else $this->cachingType = 0; }else $this->cachingType = 0; if (!($this->cachingType)){ $this->setDebugMessage("testing disk cache"); $this->dataDir = $this->dataDir.$this->dataTempDir."/"; if(is_dir($this->dataDir)){ if ($this->is__writable($this->dataDir)){ $this->setDebugMessage("using diskcache"); $this->cachingType =2; }else $this->cachingType = 0; }else { $this->setDebugMessage($this->dataDir . " is not writable or doesn't exist'"); if ( mkdir($this->dataDir)){ $this->setDebugMessage($this->dataDir . " created and rocking"); $this->cachingType =2; }else $this->cachingType = 0; } } if ($this->cachingType <1) $this->setError("Cowardly refusing to cache to nowhere!\r\nPlease ensure that either memcache is running on ".print_r($this->servers,1)."or that your cache dir ".$this->dataDir." is writable"); } private function is__writable($path) { //will work in despite of Windows ACLs bug //NOTE: use a trailing slash for folders!!! //see http://bugs.php.net/bug.php?id=27609 //see http://bugs.php.net/bug.php?id=30931 // from http://us2.php.net/manual/en/function.is-writable.php#73596 if ($path{strlen($path)-1}=='/') // recursively return a temporary file path return $this->is__writable($path.uniqid(mt_rand()).'.tmp'); else if (is_dir($path)) return $this->is__writable($path.'/'.uniqid(mt_rand()).'.tmp'); // check tmp file for read/write capabilities $rm = file_exists($path); $f = @fopen($path, 'a'); if ($f===false) return false; fclose($f); if (!$rm) unlink($path); return true; } private function setError($message){ $this->errorStatus =1; $this->errorMessage = $message; $this->setDebugMessage($this->errorMessage); if ($this->dieOnError) die($this->errorMessage); return 0; } private function hashedKey($_key) { $hashedkey = md5($this->hash.$_key); return $hashedkey; } /** * Removes the directory and all its contents. * * @param string the directory name to remove * @param boolean whether to just empty the given directory, without deleting the given directory. * @return boolean True/False whether the directory was deleted. * * http://us2.php.net/manual/en/function.rmdir.php#72598 */ private function deleteDirectory($dirname,$only_empty=false) { if (!is_dir($dirname)) return false; $dscan = array(realpath($dirname)); $darr = array(); while (!empty($dscan)) { $dcur = array_pop($dscan); $darr[] = $dcur; if ($d=opendir($dcur)) { while ($f=readdir($d)) { if ($f=='.' || $f=='..') continue; $f=$dcur.'/'.$f; if (is_dir($f)) $dscan[] = $f; else unlink($f); } closedir($d); } } $i_until = ($only_empty)? 1 : 0; for ($i=count($darr)-1; $i>=$i_until; $i--) { $msg = "\nDeleting '".$darr[$i]."' ... "; if (rmdir($darr[$i])) $msg = "ok"; else $msg = "FAIL"; $this->setDebugMessage($msg); } return (($only_empty)? (count(scandir)<=2) : (!is_dir($dirname))); } private function writeFile($_key, $_data){ $objectdir = $this->dataDir.substr($_key,0,5); if(!is_dir($objectdir)){ $this->setDebugMessage($objectdir. " is a new dir"); mkdir($objectdir); } $filename = $objectdir."/". $_key; if (!$handle = fopen($filename, 'w')) { return $this->setError("Cannot open file ($filename)"); } if (fwrite($handle, $_data) === FALSE) { return $this->setError("Cannot write to file ($filename)"); } fclose($handle); return 1; } // private function getDiskObject($_key){ $this->setDebugMessage("getting cached object using diskcache"); $hashedkey = $this->hashedKey($_key); $objectdir = $this->dataDir.substr($hashedkey,0,5); $filename = $objectdir."/". $hashedkey; $this->setDebugMessage("getting cached object from ".$filename); if (file_exists($filename)){ $readcontent = file_get_contents($filename); $storedobject = unserialize($readcontent); $now = mktime(); $this->setDebugMessage("cached object is ". (mktime()-$storedobject["startdate"]) . " seconds behind. TTL: ".($storedobject["expire"]-(mktime()-$storedobject["startdate"]))); if ((mktime()-$storedobject["startdate"])<$storedobject["expire"]) { return $storedobject["data"]; }else{ $this->deleteDiskObject($_key); return false; } }return false; } private function getMemObject($_key) { $hashedkey = $this->hashedKey($_key); $this->setDebugMessage("getting cached object using memcache"); $object = $this->memcache->get($hashedkey); return $object; } private function setDiskObject($_key,$_data,$_expire,$_startDate=0) { $this->setDebugMessage("caching object using diskcache"); $hashedkey = $this->hashedKey($_key); if ($_startDate==0) $startdate = mktime(); else $startdate=$_startDate; $storedobject = array("data"=>$_data, "expire"=>$_expire,"startdate"=>$startdate); $data = serialize($storedobject); if ($this->writefile($hashedkey,$data)){ $this->setDebugMessage("write to disk cache successful"); $success =1; }else $success =0; return $success; } private function setMemObject($_key,$_data,$_compress,$_expire) { $hashedkey = $this->hashedKey($_key); $success = $this->memcache->set($hashedkey, $_data, $_compress, $_expire) or $this->setError("Could not save data to memcache"); $this->setDebugMessage("caching object using memcache"); return $success; } private function deleteMemObject($_key) { $hashedkey = $this->hashedKey($_key); $success = $this->memcache->delete($hashedkey); return $success; } private function deleteDiskObject($_key) { $hashedkey = $this->hashedKey($_key); $objectdir = $this->dataDir.substr($hashedkey,0,5); $filename = $objectdir."/". $hashedkey; if (file_exists($filename)){ unlink($filename); }else return true; } private function setDebugMessage($_message) { if ($this->debug) $this->debugMessage[] = array("date"=>date("r"),"message"=>$_message); } private function flushMemObjects() { $this->setDebugMessage("flushing objects using memcache"); $success = $this->memcache->flush(); return $success; } private function flushDiskObjects() { $this->setDebugMessage("flushing objects using diskcache"); $success = $this->deleteDirectory($this->dataDir); return $success; } private function replaceDiskObject($_key,$_data,$_expire) { $this->setDebugMessage("replacing ".$_key." object using diskcache"); $hashedkey = $this->hashedKey($_key); $objectdir = $this->dataDir.substr($hashedkey,0,5); $filename = $objectdir."/". $hashedkey; $this->setDebugMessage("getting cached object from ".$filename); if (file_exists($filename)){ $readcontent = file_get_contents($filename); $storedobject = unserialize($readcontent); $now = mktime(); $this->setDebugMessage("cached object is ". (mktime()-$storedobject["startdate"]) . " seconds behind. TTL: ".($storedobject["expire"]-(mktime()-$storedobject["startdate"]))); if ((mktime()-$storedobject["startdate"])<$storedobject["expire"]) { if ($_expire==0)$_expire = ($storedobject["expire"]-(mktime()-$storedobject["startdate"])); $success =$this->setDiskObject($_key,$_data,$_expire,$storedobject["startdate"]); return $success; }else{ $this->deleteDiskObject($_key); return false; } } } private function replaceMemObject($_key,$_data,$_compress,$_expire) { $hashedkey = $this->hashedKey($_key); $success = $this->memcache->replace($hashedkey, $_data, $_compress, $_expire) or $this->setError("Could not save data to memcache"); $this->setDebugMessage("replacing ".$_key." object using memcache"); return $success; } /** * Public functions */ public function errorHandler(){ return $this->errorMessage; } public function debugHandler(){ return $this->debugMessage; } /** * set * * Note: Remember that resource variables (i.e. file and connection descriptors) cannot be stored in the cache, because they cannot be adequately represented in serialized state. */ public function set( $_key, $_data, $_compress=0, $_expire= 2592000 ) { $this->setDebugMessage("data:".print_r($_data,1)); if ($this->cachingType==1){ $success = $this->setMemObject($_key,$_data,$_compress,$_expire); }else if ($this->cachingType==2){ $success = $this->setDiskObject($_key,$_data, $_expire); // store object } return $success; } public function get( $_key) { if ($this->cachingType==1){ $object = $this->getMemObject($_key); }else if ($this->cachingType==2){ $object = $this->getDiskObject($_key); } return $object; } public function delete( $_key) { if ($this->cachingType==1){ $success = $this->deleteMemObject($_key); }else if ($this->cachingType==2){ $success = $this->deleteDiskObject($_key); } return $success; } public function flush() { if ($this->cachingType==1){ $success = $this->flushMemObjects(); }else if ($this->cachingType==2){ $success = $this->flushDiskObjects(); } return $success; } public function replace( $_key, $_data, $_compress=0, $_expire= 0 ) { $this->setDebugMessage("replace ".$_key." with data:".print_r($_data,1)); if ($this->cachingType==1){ $success = $this->replaceMemObject($_key,$_data,$_compress,$_expire); }else if ($this->cachingType==2){ $success = $this->replaceDiskObject($_key,$_data, $_expire); // store object } return $success; } } ?>