]> git.mxchange.org Git - friendica.git/blob - src/Core/Cache/Type/APCuCache.php
Move Cache to strategies
[friendica.git] / src / Core / Cache / Type / APCuCache.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Core\Cache\Type;
23
24 use Friendica\Core\Cache\Enum\Duration;
25 use Friendica\Core\Cache\Capability\ICanCacheInMemory;
26 use Friendica\Core\Cache\Exception\InvalidCacheDriverException;
27
28 /**
29  * APCu Cache.
30  */
31 class APCuCache extends AbstractCache implements ICanCacheInMemory
32 {
33         public static $NAME = 'apcu';
34
35         use CompareSetTrait;
36         use CompareDeleteTrait;
37
38         /**
39          * @throws InvalidCacheDriverException
40          */
41         public function __construct(string $hostname)
42         {
43                 if (!self::isAvailable()) {
44                         throw new InvalidCacheDriverException('APCu is not available.');
45                 }
46
47                 parent::__construct($hostname);
48         }
49
50         /**
51          * (@inheritdoc)
52          */
53         public function getAllKeys(?string $prefix = null): array
54         {
55                 $ns = $this->getCacheKey($prefix ?? '');
56                 $ns = preg_quote($ns, '/');
57
58                 if (class_exists('\APCIterator')) {
59                         $iterator = new \APCIterator('user', '/^' . $ns. '/', APC_ITER_KEY);
60                 } else {
61                         $iterator = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
62                 }
63
64                 $keys = [];
65                 foreach ($iterator as $item) {
66                         array_push($keys, $item['key']);
67                 }
68
69                 return $this->getOriginalKeys($keys);
70         }
71
72         /**
73          * (@inheritdoc)
74          */
75         public function get(string $key)
76         {
77                 $cacheKey = $this->getCacheKey($key);
78
79                 $cached = apcu_fetch($cacheKey, $success);
80                 if (!$success) {
81                         return null;
82                 }
83
84                 $value = unserialize($cached);
85
86                 // Only return a value if the serialized value is valid.
87                 // We also check if the db entry is a serialized
88                 // boolean 'false' value (which we want to return).
89                 if ($cached === serialize(false) || $value !== false) {
90                         return $value;
91                 }
92
93                 return null;
94         }
95
96         /**
97          * (@inheritdoc)
98          */
99         public function set(string $key, $value, int $ttl = Duration::FIVE_MINUTES): bool
100         {
101                 $cacheKey = $this->getCacheKey($key);
102
103                 $cached = serialize($value);
104
105                 if ($ttl > 0) {
106                         return apcu_store(
107                                 $cacheKey,
108                                 $cached,
109                                 $ttl
110                         );
111                 } else {
112                         return apcu_store(
113                                 $cacheKey,
114                                 $cached
115                         );
116                 }
117         }
118
119         /**
120          * (@inheritdoc)
121          */
122         public function delete(string $key): bool
123         {
124                 $cacheKey = $this->getCacheKey($key);
125                 return apcu_delete($cacheKey);
126         }
127
128         /**
129          * (@inheritdoc)
130          */
131         public function clear(bool $outdated = true): bool
132         {
133                 if ($outdated) {
134                         return true;
135                 } else {
136                         $prefix = $this->getPrefix();
137                         $prefix = preg_quote($prefix, '/');
138
139                         if (class_exists('\APCIterator')) {
140                                 $iterator = new \APCIterator('user', '/^' . $prefix . '/', APC_ITER_KEY);
141                         } else {
142                                 $iterator = new \APCUIterator('/^' . $prefix . '/', APC_ITER_KEY);
143                         }
144
145                         return apcu_delete($iterator);
146                 }
147         }
148
149         /**
150          * (@inheritdoc)
151          */
152         public function add(string $key, $value, int $ttl = Duration::FIVE_MINUTES): bool
153         {
154                 $cacheKey = $this->getCacheKey($key);
155                 $cached   = serialize($value);
156
157                 return apcu_add($cacheKey, $cached);
158         }
159
160         public static function isAvailable(): bool
161         {
162                 if (!extension_loaded('apcu')) {
163                         return false;
164                 } elseif (!ini_get('apc.enabled') && !ini_get('apc.enable_cli')) {
165                         return false;
166                 } elseif (
167                         version_compare(phpversion('apc') ?: '0.0.0', '4.0.6') === -1 &&
168                         version_compare(phpversion('apcu') ?: '0.0.0', '5.1.0') === -1
169                 ) {
170                         return false;
171                 }
172
173                 return true;
174         }
175 }