From b1f1c108783a7d9fb3b4e9eaa80053f0d52425bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Espi=C3=A9?= Date: Mon, 2 Oct 2017 07:30:41 +0000 Subject: [PATCH] APC emulation using files when APC or APCu is not installed. SVN:trunk[4954] --- core/apc-compat.php | 6 ++ core/apc-emulation.php | 221 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 core/apc-emulation.php diff --git a/core/apc-compat.php b/core/apc-compat.php index 00f8ff991..0566d04e0 100644 --- a/core/apc-compat.php +++ b/core/apc-compat.php @@ -89,4 +89,10 @@ function apc_cache_info_compat() $aCacheUserData = @apc_cache_info('user'); } return $aCacheUserData; +} + +// Cache emulation +if (!function_exists('apc_store')) +{ + require_once(APPROOT.'core/apc-emulation.php'); } \ No newline at end of file diff --git a/core/apc-emulation.php b/core/apc-emulation.php new file mode 100644 index 000000000..409b16ea4 --- /dev/null +++ b/core/apc-emulation.php @@ -0,0 +1,221 @@ + +// + +/** + * Date: 27/09/2017 + */ + + +/** + * @param array|string $key + * @param $var + * @param int $ttl + * @return array|bool + */ +function apc_store($key, $var = NULL, $ttl = 0) +{ + if (is_array($key)) + { + $aResult = array(); + foreach($key as $sKey => $value) + { + $aResult[] = apc_emul_store_unit($sKey, $value, $ttl); + } + return $aResult; + } + return apc_emul_store_unit($key, $var, $ttl); +} + +/** + * @param string $sKey + * @param $value + * @param int $iTTL time to live + * @return bool + */ +function apc_emul_store_unit($sKey, $value, $iTTL) +{ + if ($iTTL > 0) + { + // hint for ttl management + $sKey = '-'.$sKey; + } + + $sFilename = apc_emul_get_cache_filename($sKey); + // try to create the folder + $sDirname = dirname($sFilename); + if (!file_exists($sDirname)) + { + if (!@mkdir($sDirname, 0755, true)) + { + return false; + } + } + $bRes = !(@file_put_contents($sFilename, serialize($value), LOCK_EX) === false); + apc_emul_manage_ttl(); + return $bRes; +} + +/** + * @param $key string|array + * @return mixed + */ +function apc_fetch($key) +{ + if (is_array($key)) + { + $aResult = array(); + foreach($key as $sKey) + { + $aResult[$sKey] = apc_emul_fetch_unit($sKey); + } + return $aResult; + } + return apc_emul_fetch_unit($key); +} + +function apc_emul_fetch_unit($sKey) +{ + // Try the 'TTLed' version + $sValue = apc_emul_readcache_locked(apc_emul_get_cache_filename('-'.$sKey)); + if ($sValue === false) + { + $sValue = apc_emul_readcache_locked(apc_emul_get_cache_filename($sKey)); + if ($sValue === false) + { + return false; + } + } + $oRes = @unserialize($sValue); + return $oRes; +} + +function apc_emul_readcache_locked($sFilename) +{ + $file = @fopen($sFilename, 'r'); + if ($file === false) + { + return false; + } + flock($file, LOCK_SH); + $sContent = @fread($file, @filesize($sFilename)); + flock($file, LOCK_UN); + fclose($file); + return $sContent; +} + +/** + * @param string $cache_type + * @return bool + */ +function apc_clear_cache($cache_type = '') +{ + $sRootCacheDir = apc_emul_get_cache_filename(''); + apc_emul_delete_entry($sRootCacheDir); + return true; +} + +function apc_emul_delete_entry($sCache) +{ + if (is_dir($sCache)) + { + $aFiles = array_diff(scandir($sCache), array('.', '..')); + foreach($aFiles as $sFile) + { + $sSubFile = $sCache.'/'.$sFile; + if (!apc_emul_delete_entry($sSubFile)) + { + return false; + } + } + if (!@rmdir($sCache)) + { + return false; + } + } + else + { + if (!@unlink($sCache)) + { + return false; + } + } + return true; +} + +/** + * @param $key + * @return bool|string[] + */ +function apc_delete($key) +{ + return apc_emul_delete_entry(apc_emul_get_cache_filename($key)); +} + + +function apc_emul_get_cache_filename($sKey) +{ + $sPath = str_replace(array(' ', '/', '\\', '.'), '-', $sKey); + return utils::GetCachePath().'apc-emul/'.$sPath; +} + + +function apc_emul_manage_ttl() +{ + // Check only once per request + static $bAlreadyChecked = false; + if ($bAlreadyChecked) + { + return; + } + $sRootCacheDir = apc_emul_get_cache_filename(''); + apc_emul_manage_ttl_dir($sRootCacheDir); + $bAlreadyChecked = true; +} + +function apc_emul_manage_ttl_dir($sCheck) +{ + $iTTL = MetaModel::GetConfig()->Get('apc_cache.query_ttl'); + // Garbage collection + $aFiles = array_diff(@scandir($sCheck), array('.', '..')); + foreach($aFiles as $sFile) + { + $sSubFile = $sCheck.'/'.$sFile; + if (is_dir($sSubFile)) + { + apc_emul_manage_ttl_dir($sSubFile); + } + else + { + apc_emul_check_ttl_file($sSubFile, $iTTL); + } + } +} + +function apc_emul_check_ttl_file($sFilename, $iTTL) +{ + $iCurTime = time(); + if (strpos(basename($sFilename), '-') === 0) + { + $iLimitTime = @fileatime($sFilename) + $iTTL + rand(-$iTTL / 10, $iTTL / 10); + if ($iLimitTime < $iCurTime) + { + @unlink($sFilename); + } + } +}