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 Exception; |
21
|
|
|
use Memcached as MemcachedSoftware; |
22
|
|
|
use Phpfastcache\Cluster\AggregatablePoolInterface; |
23
|
|
|
use Phpfastcache\Config\ConfigurationOption; |
24
|
|
|
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface; |
25
|
|
|
use Phpfastcache\Core\Pool\TaggableCacheItemPoolTrait; |
26
|
|
|
use Phpfastcache\Core\Item\ExtendedCacheItemInterface; |
27
|
|
|
use Phpfastcache\Entities\DriverStatistic; |
28
|
|
|
use Phpfastcache\Event\EventManagerInterface; |
29
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheCoreException; |
30
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException; |
31
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheDriverConnectException; |
32
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheDriverException; |
33
|
|
|
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException; |
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 ExtendedCacheItemPoolInterface, 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 null|array |
145
|
|
|
*/ |
146
|
|
|
protected function driverRead(ExtendedCacheItemInterface $item): ?array |
147
|
|
|
{ |
148
|
|
|
$val = $this->instance->get($item->getKey()); |
149
|
|
|
|
150
|
|
|
if ($val === false) { |
151
|
|
|
return null; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
return $val; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* @param ExtendedCacheItemInterface $item |
159
|
|
|
* @return bool |
160
|
|
|
* @throws PhpfastcacheInvalidArgumentException |
161
|
|
|
* @throws PhpfastcacheLogicException |
162
|
|
|
*/ |
163
|
|
|
protected function driverWrite(ExtendedCacheItemInterface $item): bool |
164
|
|
|
{ |
165
|
|
|
$this->assertCacheItemType($item, Item::class); |
166
|
|
|
|
167
|
|
|
$ttl = $item->getExpirationDate()->getTimestamp() - time(); |
168
|
|
|
|
169
|
|
|
// Memcache will only allow a expiration timer less than 2592000 seconds, |
170
|
|
|
// otherwise, it will assume you're giving it a UNIX timestamp. |
171
|
|
|
if ($ttl > 2592000) { |
172
|
|
|
$ttl = time() + $ttl; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
return $this->instance->set($item->getKey(), $this->driverPreWrap($item), $ttl); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* @param ExtendedCacheItemInterface $item |
180
|
|
|
* @return bool |
181
|
|
|
* @throws PhpfastcacheInvalidArgumentException |
182
|
|
|
*/ |
183
|
|
|
protected function driverDelete(ExtendedCacheItemInterface $item): bool |
184
|
|
|
{ |
185
|
|
|
$this->assertCacheItemType($item, Item::class); |
186
|
|
|
|
187
|
|
|
return $this->instance->delete($item->getKey()); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* @return bool |
192
|
|
|
*/ |
193
|
|
|
protected function driverClear(): bool |
194
|
|
|
{ |
195
|
|
|
return $this->instance->flush(); |
196
|
|
|
} |
197
|
|
|
} |
198
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.