Created
April 24, 2016 08:00
-
-
Save smallslime/d5847c30ec177f46c573f38532305ec7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace QMTV\System; | |
/** | |
* Class FileCache | |
* | |
* @author liuzhen | |
*/ | |
class FileCache | |
{ | |
protected $sCachePath; | |
protected $mCBKey2File; | |
/** | |
* @param string $sCacheDir | |
* @param int $iCreateMode | |
* @param mixed $mCBKey2File | |
* | |
* @throws \RuntimeException | |
*/ | |
public function __construct($sCacheDir, $iCreateMode = 0777, $mCBKey2File = null) | |
{ | |
$this->sCachePath = rtrim($sCacheDir, '/') . '/'; | |
if (!file_exists($this->sCachePath)) { | |
if (!@mkdir($this->sCachePath, $iCreateMode, true)) { | |
throw new \RuntimeException("[CACHE] ; Create dir[$sCacheDir] failed"); | |
} | |
} | |
$this->mCBKey2File = $mCBKey2File; | |
} | |
/** | |
* @param string $sKey | |
* | |
* @return array [<mixed>data, <bool>has_out_date, <string>file_path] | |
*/ | |
public function get($sKey) | |
{ | |
return $this->getWithDetailInfo($sKey)[0]; | |
} | |
public function getWithDetailInfo($sKey) | |
{ | |
$sFile = $this->getFilePath($sKey); | |
if (!file_exists($sFile)) { | |
return [null, 0, true, $sFile]; | |
} | |
$aData = file($sFile); | |
if (count($aData) !== 2) { | |
return [null, 0, true, $sFile]; | |
} | |
$iExpireAT = (int)$aData[0]; | |
return [json_decode($aData[1]), $iExpireAT, time() - $iExpireAT > 0, $sFile]; | |
} | |
/** | |
* @param string $sKey | |
* @param mixed $mValue | |
* @param int $iExpire | |
* | |
* @return bool | |
*/ | |
public function set($sKey, $mValue, $iExpire) | |
{ | |
$sFile = $this->getFilePath($sKey); | |
return (bool)file_put_contents($sFile, sprintf("%d\n%s", time() + $iExpire, json_encode($mValue)), LOCK_EX); | |
} | |
/** | |
* @param $sKey | |
* | |
* @return bool | |
*/ | |
public function delete($sKey) | |
{ | |
$sFile = $this->sCachePath . md5($sKey); | |
return file_exists($sFile) ? unlink($sFile) : true; | |
} | |
/** | |
* @return bool | |
*/ | |
public function flush() | |
{ | |
$rDir = opendir($this->sCachePath); | |
while (($sFile = readdir($rDir)) !== false) { | |
if (ltrim($sFile, '.') !== '') { | |
unlink($this->sCachePath . $sFile); | |
} | |
} | |
closedir($rDir); | |
return true; | |
} | |
protected function getFilePath($sKey) | |
{ | |
return $this->sCachePath . ($this->mCBKey2File === null ? md5($sKey) : call_user_func($this->mCBKey2File, | |
$sKey)); | |
} | |
public static function getAndSetFromFileCache( | |
FileCache $FileCache, | |
$sKey, | |
$iExpire, | |
$iExpireEffect, | |
$mCB, | |
$aParam = [] | |
) { | |
list($mData, $iExpireAt, $bHasOutDate, $sFile) = $FileCache->getWithDetailInfo($sKey); | |
# 未过期 | |
if (!$bHasOutDate) { | |
return $mData; | |
} | |
# 已过期 | |
$sLockFile = $sFile . '.lock'; | |
$rF = fopen($sLockFile, 'w'); | |
# 未拿到锁 | |
if (!flock($rF, LOCK_EX | LOCK_NB)) { | |
if ($iExpireAt == 0 || $iExpireAt + $iExpireEffect < time()) { | |
# 过期不可用($iExpireAt + $this->iExpireEffect < time()) / 不存在($iExpireAt == 0) 返回空 | |
$FileCache->delete($sKey); | |
return null; | |
} else { | |
# 过期可用 返回 old 数据 | |
return $mData; | |
} | |
} | |
# 拿到锁, 取数据更新 | |
$mData = call_user_func_array($mCB, $aParam); | |
if ($mData !== null) { | |
$FileCache->set($sKey, $mData, $iExpire); | |
} | |
flock($rF, LOCK_UN); | |
fclose($rF); | |
return $mData; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment