Source of file CacheManager.php
Size: 14,908 Bytes - Last Modified: 2020-10-24T02:46:31+00:00
/home/travis/build/NextDom/nextdom-core/src/Managers/CacheManager.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 | <?php /* * This file is part of the NextDom software (https://github.com/NextDom or http://nextdom.github.io). * Copyright (c) 2018 NextDom. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* This file is part of Jeedom. * * Jeedom is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jeedom is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jeedom. If not, see <http://www.gnu.org/licenses/>. */ namespace NextDom\Managers; use NextDom\Com\ComShell; use NextDom\Enums\CacheEngine; use NextDom\Enums\CacheKey; use NextDom\Enums\DateFormat; use NextDom\Enums\NextDomFile; use NextDom\Enums\NextDomObj; use NextDom\Helpers\FileSystemHelper; use NextDom\Helpers\NextDomHelper; use NextDom\Helpers\SystemHelper; use NextDom\Model\Entity\Cache; /** * Class CacheManager * @package NextDom\Managers */ class CacheManager { private static $cacheSystem = null; /** * Store object in cache * * @param string $key Key * @param mixed $value Value * @param int $lifetime Lifetime * @param mixed $options Options * * @return bool * @throws \Exception */ public static function set($key, $value, $lifetime = 0, $options = null) { if ($lifetime < 0) { $lifetime = 0; } $cacheItem = new Cache(); $cacheItem->setKey($key) ->setValue($value) ->setLifetime($lifetime); if ($options != null) { $cacheItem->setOptionsFromJson($options); } return $cacheItem->save(); } /** * Get some stats about the cache system * * @param bool $details True for more informations * * @return array|null * @throws \Exception */ public static function stats($details = false) { $result = self::getCache()->getStats(); $result['count'] = __('Inconnu'); $engine = ConfigManager::byKey(CacheKey::CACHE_ENGINE); if ($engine == CacheEngine::FILESYSTEM) { $result['count'] = 0; foreach (FileSystemHelper::ls(self::getFolder()) as $folder) { foreach (FileSystemHelper::ls(self::getFolder() . '/' . $folder) as $file) { if (strpos($file, 'swap') !== false) { continue; } $result['count']++; } } } elseif ($engine == CacheEngine::REDIS) { $result['count'] = self::$cacheSystem->getRedis()->dbSize(); } if ($details) { $re = '/s:\d*:(.*?);s:\d*:"(.*?)";s/'; $result = []; foreach (FileSystemHelper::ls(self::getFolder()) as $folder) { foreach (FileSystemHelper::ls(self::getFolder() . '/' . $folder) as $file) { $path = self::getFolder() . '/' . $folder . '/' . $file; $str = (string)str_replace("\n", '', file_get_contents($path)); preg_match_all($re, $str, $matches); if (!isset($matches[2]) || !isset($matches[2][0]) || trim($matches[2][0]) == '') { continue; } $result[] = $matches[2][0]; } } $result['details'] = $result; } return $result; } /** * Get doctrine cache * * @param string $targetFolder Target folder * * @return \Doctrine\Common\Cache\FilesystemCache * * @throws \Exception */ public static function getDoctrineCache(string $targetFolder = '') { if ($targetFolder === '') { $targetFolder = self::getFolder(); } return new \Doctrine\Common\Cache\FilesystemCache($targetFolder); } /** * Get cache system * * @return \Doctrine\Common\Cache\FilesystemCache|\Doctrine\Common\Cache\MemcachedCache|\Doctrine\Common\Cache\RedisCache|null Cache system * @throws \Exception */ public static function getCache() { if (self::$cacheSystem !== null) { return self::$cacheSystem; } $engine = ConfigManager::byKey(CacheKey::CACHE_ENGINE); if ($engine == CacheEngine::MEMCACHED && !class_exists('memcached')) { $engine = CacheEngine::FILESYSTEM; ConfigManager::save(CacheKey::CACHE_ENGINE, CacheEngine::FILESYSTEM); } if ($engine == CacheEngine::REDIS && !class_exists('redis')) { $engine = CacheEngine::FILESYSTEM; ConfigManager::save(CacheKey::CACHE_ENGINE, CacheEngine::FILESYSTEM); } switch ($engine) { case CacheEngine::FILESYSTEM: case CacheEngine::PHPFILE: default: self::$cacheSystem = self::getDoctrineCache(); break; case CacheEngine::MEMCACHED: $memcached = new \Memcached(); $memcached->addServer(ConfigManager::byKey('cache::memcacheaddr'), ConfigManager::byKey('cache::memcacheport')); self::$cacheSystem = new \Doctrine\Common\Cache\MemcachedCache(); self::$cacheSystem->setMemcached($memcached); break; case CacheEngine::REDIS: $redis = new \Redis(); $redis->connect(ConfigManager::byKey('cache::redisaddr'), ConfigManager::byKey('cache::redisport')); self::$cacheSystem = new \Doctrine\Common\Cache\RedisCache(); self::$cacheSystem->setRedis($redis); break; } return self::$cacheSystem; } /** * Get the folder where the cache is stored * * @return string Cache folder * @throws \Exception */ public static function getFolder(): string { $return = NextDomHelper::getTmpFolder('cache'); if (!file_exists($return)) { mkdir($return, 0775); } return $return; } /** * Test if object exists * * @param string $key Key * * @return bool True if object exists * * @deprecated Use exists * @throws \Exception */ public static function exist($key) { @trigger_error('This method is deprecated', E_USER_DEPRECATED); return self::exists($key); } /** * Test if object exists * * @param string $key Key * * @return bool True if object exists * @throws \Exception */ public static function exists($key) { return is_object(self::getCache()->fetch($key)); } /** * Clear cache */ public static function flush() { self::getCache()->deleteAll(); shell_exec('rm -rf ' . self::getFolder() . ' 2>&1 > /dev/null'); } /** * @TODO: Ouahhh * @return array */ public static function search(): array { return []; } /** * Persist cache system */ public static function persist() { switch (ConfigManager::byKey(CacheKey::CACHE_ENGINE)) { case CacheEngine::FILESYSTEM: $cacheDir = self::getFolder(); break; case CacheEngine::PHPFILE: $cacheDir = self::getFolder(); break; default: return; } try { $cacheFile = self::getArchivePath(); $rmCmd = sprintf("rm -rf %s", $cacheFile); $tarCmd = sprintf("cd %s; tar cfz %s * 2>&1 > /dev/null", $cacheDir, $cacheFile); $chmodCmd = sprintf("chmod 664 %s", $cacheFile); $chownCmd = sprintf("chown %s:%s %s", SystemHelper::getWWWUid(), SystemHelper::getWWWGid(), $cacheFile); ComShell::execute($rmCmd); ComShell::execute($tarCmd); ComShell::execute($chmodCmd); ComShell::execute($chownCmd); } catch (\Exception $e) { } } /** * @return string */ public static function getArchivePath() { return NEXTDOM_DATA . '/' . NextDomFile::CACHE_TAR_GZ; } /** * Test if cache already exists * * @return bool True if file cache.tar.gz * @throws \Exception */ public static function isPersistOk(): bool { $cacheEngine = ConfigManager::byKey(CacheKey::CACHE_ENGINE); if ($cacheEngine == CacheEngine::PHPFILE || $cacheEngine == CacheEngine::FILESYSTEM) { $filename = self::getArchivePath(); if (!file_exists($filename) || filemtime($filename) < strtotime('-35min')) { return false; } } return true; } /** * Restore persisted cache */ public static function restore() { $cacheDir = ''; $cacheEngine = ConfigManager::byKey(CacheKey::CACHE_ENGINE); if ($cacheEngine == CacheEngine::PHPFILE || $cacheEngine == CacheEngine::FILESYSTEM) { $cacheDir = self::getFolder(); } if (!file_exists(self::getArchivePath())) { return false; } SystemHelper::vsystem("rm -rf %s", $cacheDir); SystemHelper::vsystem("mkdir %s", $cacheDir); SystemHelper::vsystem("tar xzf %s -C %s", self::getArchivePath(), $cacheDir); return true; } /** * Remove old and unused item stored in cache * * @throws \Exception */ public static function clean() { if (ConfigManager::byKey(CacheKey::CACHE_ENGINE) != 'FilesystemCache') { return; } $re = '/s:\d*:(.*?);s:\d*:"(.*?)";s/'; $result = []; foreach (FileSystemHelper::ls(self::getFolder()) as $folder) { foreach (FileSystemHelper::ls(self::getFolder() . '/' . $folder) as $file) { $path = self::getFolder() . '/' . $folder . '/' . $file; if (strpos($file, 'swap') !== false) { unlink($path); continue; } $str = (string)str_replace("\n", '', file_get_contents($path)); preg_match_all($re, $str, $matches); if (!isset($matches[2]) || !isset($matches[2][0]) || trim($matches[2][0]) == '') { continue; } $result[] = $matches[2][0]; } } $cleanCache = [ 'cmdCacheAttr' => NextDomObj::CMD, 'cmd' => NextDomObj::CMD, 'eqLogicCacheAttr' => NextDomObj::EQLOGIC, 'eqLogicStatusAttr' => NextDomObj::EQLOGIC, 'scenarioCacheAttr' => NextDomObj::SCENARIO, 'cronCacheAttr' => NextDomObj::CRON, 'cron' => NextDomObj::CRON, ]; foreach ($result as $key) { $matches = null; if (preg_match_all('/(::lastCommunication|::state|::numberTryWithoutSuccess)/', $key) == 1) { self::delete($key); continue; } foreach ($cleanCache as $kClean => $value) { if (strpos($key, $kClean) !== false) { $id = str_replace($kClean, '', $key); if (!is_numeric($id)) { continue; } $resultObject = $value::byId($id); if (!is_object($resultObject)) { self::delete($key); } } } preg_match_all('/(?:widgetHtml|camera)(\d+)(.*?)/', $key, $matches); if (isset($matches[1]) && isset($matches[1][0])) { $resultObject = EqLogicManager::byId($matches[1][0]); if (!is_object($resultObject)) { self::delete($key); } } preg_match_all('/scenarioHtml(.*?)(\d*)/', $key, $matches); if (isset($matches[1]) && isset($matches[1][0])) { $resultObject = ScenarioManager::byId($matches[1][0]); if (!is_object($resultObject)) { self::delete($key); } } $withoutPrefix = preg_replace('/widgetHtmldashboard|widgetHtmldplan|widgetHtml|cmd/', '', $key); if (is_numeric($withoutPrefix)) { self::delete($key); } preg_match_all('/(?:dependancy|dependency)(.*)/', $key, $matches); if (isset($matches[1]) && isset($matches[1][0])) { try { $plugin = PluginManager::byId($matches[1][0]); if (!is_object($plugin)) { self::delete($key); } } catch (\Exception $e) { self::delete($key); } } } } /** * Delete stored object in cache * * @param $key * @throws \Exception */ public static function delete($key) { $cacheItem = self::byKey($key); if (is_object($cacheItem)) { $cacheItem->remove(); } } /** * Get stored object by key * * @param string $key Key * @return mixed Stored object or null if not exists * @throws \Exception */ public static function byKey($key) { $cache = self::getCache()->fetch($key); if (!is_object($cache)) { $cache = new Cache(); $cache->setKey($key) ->setDatetime(date(DateFormat::FULL)); } return $cache; } public static function flushWidget() { foreach (EqLogicManager::all() as $eqLogic) { try { $eqLogic->emptyCacheWidget(); } catch (Exception $e) { } } foreach (ScenarioManager::all() as $scenario) { try { $scenario->emptyCacheWidget(); } catch (Exception $e) { } } } } |