|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* |
|
5
|
|
|
* This file is part of Phpfastcache. |
|
6
|
|
|
* |
|
7
|
|
|
* @license MIT License (MIT) |
|
8
|
|
|
* |
|
9
|
|
|
* For full copyright and license information, please see the docs/CREDITS.txt and LICENCE files. |
|
10
|
|
|
* |
|
11
|
|
|
* @author Georges.L (Geolim4) <[email protected]> |
|
12
|
|
|
* @author Contributors https://github.com/PHPSocialNetwork/phpfastcache/graphs/contributors |
|
13
|
|
|
*/ |
|
14
|
|
|
|
|
15
|
|
|
declare(strict_types=1); |
|
16
|
|
|
|
|
17
|
|
|
namespace Phpfastcache\Drivers\Memcached; |
|
18
|
|
|
|
|
19
|
|
|
use DateTime; |
|
20
|
|
|
use Memcached as MemcachedSoftware; |
|
21
|
|
|
use Phpfastcache\Cluster\AggregatablePoolInterface; |
|
22
|
|
|
use Phpfastcache\Config\ConfigurationOption; |
|
23
|
|
|
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface; |
|
24
|
|
|
use Phpfastcache\Core\Pool\TaggableCacheItemPoolTrait; |
|
25
|
|
|
use Phpfastcache\Core\Item\ExtendedCacheItemInterface; |
|
26
|
|
|
use Phpfastcache\Entities\DriverStatistic; |
|
27
|
|
|
use Phpfastcache\Event\EventManagerInterface; |
|
28
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheCoreException; |
|
29
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException; |
|
30
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheDriverConnectException; |
|
31
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheDriverException; |
|
32
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException; |
|
33
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheInvalidTypeException; |
|
34
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheIOException; |
|
35
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheLogicException; |
|
36
|
|
|
use Phpfastcache\Util\MemcacheDriverCollisionDetectorTrait; |
|
37
|
|
|
use Psr\Cache\CacheItemInterface; |
|
38
|
|
|
|
|
39
|
|
|
/** |
|
40
|
|
|
* @property MemcachedSoftware $instance |
|
41
|
|
|
* @method Config getConfig() |
|
42
|
|
|
*/ |
|
43
|
|
|
class Driver implements AggregatablePoolInterface |
|
44
|
|
|
{ |
|
45
|
|
|
use TaggableCacheItemPoolTrait { |
|
46
|
|
|
__construct as protected __parentConstruct; |
|
47
|
|
|
} |
|
48
|
|
|
use MemcacheDriverCollisionDetectorTrait; |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* Driver constructor. |
|
52
|
|
|
* @param ConfigurationOption $config |
|
53
|
|
|
* @param string $instanceId |
|
54
|
|
|
* @param EventManagerInterface $em |
|
55
|
|
|
* @throws PhpfastcacheDriverConnectException |
|
56
|
|
|
* @throws PhpfastcacheInvalidArgumentException |
|
57
|
|
|
* @throws PhpfastcacheCoreException |
|
58
|
|
|
* @throws PhpfastcacheDriverCheckException |
|
59
|
|
|
* @throws PhpfastcacheIOException |
|
60
|
|
|
*/ |
|
61
|
|
|
public function __construct(ConfigurationOption $config, string $instanceId, EventManagerInterface $em) |
|
62
|
|
|
{ |
|
63
|
|
|
self::checkCollision('Memcached'); |
|
64
|
|
|
$this->__parentConstruct($config, $instanceId, $em); |
|
65
|
|
|
} |
|
66
|
|
|
|
|
67
|
|
|
/** |
|
68
|
|
|
* @return bool |
|
69
|
|
|
*/ |
|
70
|
|
|
public function driverCheck(): bool |
|
71
|
|
|
{ |
|
72
|
|
|
return class_exists('Memcached'); |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
/** |
|
76
|
|
|
* @return DriverStatistic |
|
77
|
|
|
*/ |
|
78
|
|
|
public function getStats(): DriverStatistic |
|
79
|
|
|
{ |
|
80
|
|
|
$stats = current($this->instance->getStats()); |
|
81
|
|
|
$stats['uptime'] = $stats['uptime'] ?? 0; |
|
82
|
|
|
$stats['bytes'] = $stats['bytes'] ?? 0; |
|
83
|
|
|
$stats['version'] = $stats['version'] ?? $this->instance->getVersion(); |
|
84
|
|
|
|
|
85
|
|
|
$date = (new DateTime())->setTimestamp(time() - $stats['uptime']); |
|
86
|
|
|
|
|
87
|
|
|
return (new DriverStatistic()) |
|
|
|
|
|
|
88
|
|
|
->setData(implode(', ', array_keys($this->itemInstances))) |
|
89
|
|
|
->setInfo(sprintf("The memcache daemon v%s is up since %s.\n For more information see RawData.", $stats['version'], $date->format(DATE_RFC2822))) |
|
90
|
|
|
->setRawData($stats) |
|
91
|
|
|
->setSize((int)$stats['bytes']); |
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
|
/** |
|
95
|
|
|
* @return bool |
|
96
|
|
|
* @throws PhpfastcacheDriverException |
|
97
|
|
|
*/ |
|
98
|
|
|
protected function driverConnect(): bool |
|
99
|
|
|
{ |
|
100
|
|
|
$this->instance = new MemcachedSoftware(); |
|
101
|
|
|
$optPrefix = $this->getConfig()->getOptPrefix(); |
|
102
|
|
|
$this->instance->setOption(MemcachedSoftware::OPT_BINARY_PROTOCOL, true); |
|
103
|
|
|
|
|
104
|
|
|
if ($optPrefix) { |
|
105
|
|
|
$this->instance->setOption(MemcachedSoftware::OPT_PREFIX_KEY, $optPrefix); |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
foreach ($this->getConfig()->getServers() as $server) { |
|
109
|
|
|
$connected = false; |
|
110
|
|
|
/** |
|
111
|
|
|
* If path is provided we consider it as an UNIX Socket |
|
112
|
|
|
*/ |
|
113
|
|
|
if (!empty($server['path'])) { |
|
114
|
|
|
$connected = $this->instance->addServer($server['path'], 0); |
|
115
|
|
|
} elseif (!empty($server['host'])) { |
|
116
|
|
|
$connected = $this->instance->addServer($server['host'], $server['port']); |
|
117
|
|
|
} |
|
118
|
|
|
if (!empty($server['saslUser']) && !empty($server['saslPassword'])) { |
|
119
|
|
|
$this->instance->setSaslAuthData($server['saslUser'], $server['saslPassword']); |
|
120
|
|
|
} |
|
121
|
|
|
if (!$connected) { |
|
122
|
|
|
throw new PhpfastcacheDriverConnectException( |
|
123
|
|
|
sprintf( |
|
124
|
|
|
'Failed to connect to memcache host/path "%s".', |
|
125
|
|
|
$server['host'] ?: $server['path'], |
|
126
|
|
|
) |
|
127
|
|
|
); |
|
128
|
|
|
} |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
/** |
|
132
|
|
|
* Since Memcached does not throw |
|
133
|
|
|
* any error if not connected ... |
|
134
|
|
|
*/ |
|
135
|
|
|
$version = $this->instance->getVersion(); |
|
136
|
|
|
if (!$version || $this->instance->getResultCode() !== MemcachedSoftware::RES_SUCCESS) { |
|
|
|
|
|
|
137
|
|
|
throw new PhpfastcacheDriverException('Memcached seems to not be connected'); |
|
138
|
|
|
} |
|
139
|
|
|
return true; |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
|
|
/** |
|
143
|
|
|
* @param ExtendedCacheItemInterface $item |
|
144
|
|
|
* @return ?array<string, mixed> |
|
145
|
|
|
*/ |
|
146
|
|
|
protected function driverRead(ExtendedCacheItemInterface $item): ?array |
|
147
|
|
|
{ |
|
148
|
|
|
$val = $this->instance->get($item->getKey()); |
|
149
|
|
|
|
|
150
|
|
|
if (empty($val) || !\is_array($val)) { |
|
151
|
|
|
return null; |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
return $val; |
|
155
|
|
|
} |
|
156
|
|
|
|
|
157
|
|
|
/** |
|
158
|
|
|
* @param ExtendedCacheItemInterface ...$items |
|
159
|
|
|
* @return array<array<string, mixed>> |
|
160
|
|
|
*/ |
|
161
|
|
|
protected function driverReadMultiple(ExtendedCacheItemInterface ...$items): array |
|
162
|
|
|
{ |
|
163
|
|
|
$keys = $this->getKeys($items); |
|
164
|
|
|
|
|
165
|
|
|
$val = $this->instance->getMulti($keys); |
|
166
|
|
|
|
|
167
|
|
|
if (empty($val) || !\is_array($val)) { |
|
168
|
|
|
return []; |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
return $val; |
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
|
|
175
|
|
|
/** |
|
176
|
|
|
* @return array<string, mixed> |
|
177
|
|
|
* @throws PhpfastcacheInvalidArgumentException |
|
178
|
|
|
*/ |
|
179
|
|
|
protected function driverReadAllKeys(string $pattern = ''): iterable |
|
180
|
|
|
{ |
|
181
|
|
|
if ($pattern !== '') { |
|
182
|
|
|
$this->throwUnsupportedDriverReadAllPattern('https://www.php.net/manual/en/memcached.getallkeys.php'); |
|
183
|
|
|
} |
|
184
|
|
|
$keys = $this->instance->getAllKeys(); |
|
185
|
|
|
|
|
186
|
|
|
if (is_iterable($keys)) { |
|
187
|
|
|
return $keys; |
|
188
|
|
|
} else { |
|
189
|
|
|
return []; |
|
190
|
|
|
} |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
/** |
|
194
|
|
|
* @param ExtendedCacheItemInterface $item |
|
195
|
|
|
* @return bool |
|
196
|
|
|
* @throws PhpfastcacheInvalidArgumentException |
|
197
|
|
|
* @throws PhpfastcacheLogicException |
|
198
|
|
|
*/ |
|
199
|
|
|
protected function driverWrite(ExtendedCacheItemInterface $item): bool |
|
200
|
|
|
{ |
|
201
|
|
|
|
|
202
|
|
|
$ttl = $item->getExpirationDate()->getTimestamp() - time(); |
|
203
|
|
|
|
|
204
|
|
|
// Memcache will only allow a expiration timer less than 2592000 seconds, |
|
205
|
|
|
// otherwise, it will assume you're giving it a UNIX timestamp. |
|
206
|
|
|
if ($ttl > 2592000) { |
|
207
|
|
|
$ttl = time() + $ttl; |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
return $this->instance->set($item->getKey(), $this->driverPreWrap($item), $ttl); |
|
211
|
|
|
} |
|
212
|
|
|
|
|
213
|
|
|
/** |
|
214
|
|
|
* @param string $key |
|
215
|
|
|
* @param string $encodedKey |
|
216
|
|
|
* @return bool |
|
217
|
|
|
*/ |
|
218
|
|
|
protected function driverDelete(string $key, string $encodedKey): bool |
|
219
|
|
|
{ |
|
220
|
|
|
return $this->instance->delete($key); |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
/** |
|
224
|
|
|
* @return bool |
|
225
|
|
|
*/ |
|
226
|
|
|
protected function driverClear(): bool |
|
227
|
|
|
{ |
|
228
|
|
|
return $this->instance->flush(); |
|
229
|
|
|
} |
|
230
|
|
|
} |
|
231
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.