<?php
namespace Engine\Cache; class Disk implements \Engine\Cache\BaseInterface { protected $cachePath = ''; public function __construct() { $CFG = \Engine\Loader_Cfg::getInstance()->getGlobal(); $this->cachePath = realpath(MODULE_REL_PATH.$CFG['paths']['files']).'/'.$CFG['cache']['disk']['location']; } public function setPath($path) { \Engine\Dir::create($path); $this->cachePath = realpath($path).'/'; if (strlen($this->cachePath)<2) { throw new \Exception("Invalid cache path set"); } } public function getPath() { return $this->cachePath; } private function getFileDetails($key) { $return = []; $keyHash = md5($key); $keyDir = substr($keyHash, 0, 2); $return['fileLocation'] = $this->cachePath . $keyDir.'/'; $return['fileName'] = $keyHash; return $return; } public function set($key, $value, $expireTime=2592000) :void { if (!$key) { return ; } if ($value===null) { return ; } if (!is_int($expireTime) or $expireTime<0) { throw new \Exception( sprintf('Invalid format for `expireTime` when using cache class - it must be numeric, but the current value is `%s`', $expireTime) ); } $params = $this->getFileDetails($key); $expireTimestamp = TIMESTAMP + $expireTime; if (!is_dir($params['fileLocation'])) { if (@mkdir($params['fileLocation'], 0777, true)) { @chmod($params['fileLocation'], 0777); } } $serializedValue = serialize($value); if (strlen($serializedValue)>64*1024*1024) { \Log::getInstance()->warning('Disk cache class will not store values larger than 64MB. Maybe check why you need to cache such a large piece of information; cache key: '.$key); return ; } $oldmask = umask(000); file_put_contents($params['fileLocation'].$params['fileName'], $expireTimestamp.$serializedValue, LOCK_EX); umask($oldmask); } public function get($key) { if (!$key) { return null; } $params = $this->getFileDetails($key); if (!file_exists($params['fileLocation'].$params['fileName']) || !is_readable($params['fileLocation'].$params['fileName'])) { return null; } $f = fopen($params['fileLocation'].$params['fileName'], 'rb'); flock($f, LOCK_SH); $contents = fread($f, 64*1024*1024); flock($f, LOCK_UN); fclose($f); if (!$contents) { return null; } $expirationTimestamp = (int)substr($contents, 0, 10); if ($expirationTimestamp < TIMESTAMP) { unlink($params['fileLocation'].$params['fileName']); return null; } $value = @unserialize(substr($contents, 10)); if ($value===false) { return null; } return $value; } public function delete($key) :void { if (!$key) { return ; } $params = $this->getFileDetails($key); @unlink($params['fileLocation'].$params['fileName']); } public function flush() :bool { return \Engine\Dir::deleteContents($this->cachePath); } public function getInfo($key) { $return = []; $return['key'] = $key; $params = $this->getFileDetails($key); $fullFileName = $params['fileLocation'].$params['fileName']; if (file_exists($fullFileName) && is_readable($fullFileName)) { $return['fileExists'] = true; $return['fileLocation'] = $params['fileLocation']; $return['fileName'] = $params['fileName']; $f = fopen($return['fileLocation'].$return['fileName'], 'rb'); $contents = fread($f, 128); $expirationTimestamp = (int)substr($contents, 0, 10); $return['expirationTimestamp'] = $expirationTimestamp; $return['expired'] = ($expirationTimestamp < TIMESTAMP); } else { $return['fileExists'] = false; $return['fileLocation'] = $params['fileLocation']; $return['fileName'] = $params['fileName']; } return $return; } } 