*XU(|@ UXU P0TXU0`YXU XUrXU>RXU>hVAVA}AP?P?hVAVA}AP?P?P? Q?XU  }A|APQ?Q?`7A7AQ}AQ?0>>@3>@в>>@p5>@(>8>@3h>@>>>>>P>>P>XU@P\dXUP\RaXU@0\pЮXU@P\t9XU\<PXUP\XU@]dXUX]RaXUp]p9XU]<PXU`] XUP_M`XUp_NXUpp `/XU `+@XU@`EЮXUPP`tЮXU@``t9XU0`<`XU0@`pXU`*PXU`pP`QaXUP`p9XU``<`XU`@` XU@`BXUPbpXUPpcXUPct@XU eE@XU0gEЮXU@PgtЮXU0`gt9XUg<XUPg2`XU`gB9XUe<xXUgGXUeHXUkHXUlH@XUmEЮXUPmtЮXU`mt9XUm<vXU`mH@XUPnEЮXU`PntЮXUP`nt9XUn<vXU nHXUpo XUoHXU`ot5XUb<pXU_*:XU_RXUps>ZAXA(AA  PZAXA(AAAAA`5A0A0A  P^AP^A A(A(}AAA`5A 0AAIA8|AP|A A袽AhuAAA`5AtA0A@AAA`5AsA0AhA?A|AP|A8AU * =HʐA8uAAAX=AA`5AV 0A%AIA8|A return \is_object($data) || \is_array($data); } /** * write meta data to journal - for use of cache tags * * @param string|string[] $tags * @param string|int $cacheID - not prefixed * @return bool */ public function writeJournal($tags, $cacheID): bool { if ($this->journal === null) { $this->getJournal(); } $this->journalHasChanged = true; if (\is_string($tags)) { $tags = [$tags]; } foreach ($tags as $tag) { if (isset($this->journal[$tag])) { if (!\in_array($cacheID, $this->journal[$tag], true)) { $this->journal[$tag][] = $cacheID; } } else { $journalEntry = []; $journalEntry[] = $cacheID; $this->journal[$tag] = $journalEntry; } } return true; } /** * @inheritdoc */ public function getKeysByTag($tags): array { // load journal from extra cache $this->getJournal(); if (\is_string($tags)) { return $this->journal[$tags] ?? []; } if (\is_array($tags)) { $res = []; foreach ($tags as $tag) { if (isset($this->journal[$tag])) { foreach ($this->journal[$tag] as $cacheID) { $res[] = $cacheID; } } } // remove duplicate keys from array and return it return \array_unique($res); } return []; } /** * @inheritdoc */ public function keyExists($key): bool { return false; } /** * @inheritdoc */ public function setCacheTag($tags, $cacheID): bool { return $this->writeJournal($tags, $cacheID); } /** * @inheritdoc */ public function flushTags($tags): int { $deleted = 0; foreach ($this->getKeysByTag($tags) as $_id) { $res = $this->flush($_id); $this->clearCacheTags($_id); if ($res === true) { ++$deleted; } } return $deleted; } /** * clean up journal after deleting cache entries * * @param string[]|string $tags * @return bool */ public function clearCacheTags($tags): bool { if (\is_array($tags)) { foreach ($tags as $tag) { $this->clearCacheTags($tag); } } $this->getJournal(); // avoid infinite loops if ($tags !== $this->journalID && $this->journal !== false) { //load meta data foreach ($this->journal as $tagName => $value) { // search for key in meta values if (($index = \array_search($tags, $value, true)) !== false) { unset($this->journal[$tagName][$index]); if (\count($this->journal[$tagName]) === 0) { // remove empty tag nodes unset($this->journal[$tagName]); } } } // write back journal $this->journalHasChanged = true; return true; } return false; } /** * load journal * * @return array>|array{} */ public function getJournal(): array { if ($this->journal === null) { $this->journal = ($j = $this->load($this->journalID)) !== false ? ($j ?? []) : []; } return $this->journal; } /** * adds prefixes to array of cache IDs * * @param array $array * @return array */ protected function prefixArray(array $array): array { $newKeyArray = []; foreach ($array as $_key => $_val) { $newKey = $this->options['prefix'] . $_key; $newKeyArray[$newKey] = $_val; } return $newKeyArray; } /** * removes prefixes from result array of cached keys/values * * @param string[] $array * @return string[] */ protected function dePrefixArray(array $array): array { $newKeyArray = []; foreach ($array as $_key => $_val) { $newKey = \str_replace($this->options['prefix'], '', $_key); $newKeyArray[$newKey] = $_val; } return $newKeyArray; } /** * more readable output for uptime stats * * @param int|string $seconds * @return string */ protected function secondsToTime($seconds): string { $dtF = new DateTime('@0'); $dtT = new DateTime('@' . $seconds); return $dtF->diff($dtT)->format( '%a ' . \__('days') . ', %h' . \__('hours') . ', %i ' . \__('minutes') . ', %s ' . \__('seconds') ); } /** * @inheritdoc */ public function isInitialized(): bool { return $this->isInitialized; } /** * @param bool $initialized * @return void */ public function setIsInitialized(bool $initialized): void { $this->isInitialized = $initialized; } /** * @inheritdoc */ public function getError(): string { return $this->error; } /** * @inheritdoc */ public function setError(string $error): void { $this->error = $error; } /** * @return array{activated: bool, method: string, redis_port: int, redis_pass: string|null, * redis_host: string, redis_db: int, redis_persistent: bool, memcache_port: int, * memcache_host: string, prefix: string, lifetime: int, collect_stats: bool, debug: bool, * debug_method: string, cache_dir: string, file_extension: string, page_cache: bool, * types_disabled: string[], redis_user: string|null, rediscluster_hosts: string, * rediscluster_strategy: string, compile_check: bool} */ public function getOptions(): array { return $this->options; } /** * @param array{activated: bool, method: string, redis_port: int, redis_pass: string|null, * redis_host: string, redis_db: int, redis_persistent: bool, memcache_port: int, * memcache_host: string, prefix: string, lifetime: int, collect_stats: bool, debug: bool, * debug_method: string, cache_dir: string, file_extension: string, page_cache: bool, * types_disabled: string[], redis_user: string|null, rediscluster_hosts: string, * rediscluster_strategy: string, compile_check: bool} $options */ public function setOptions(array $options): void { $this->options = $options; } }