98 if (!extension_loaded(
'memcache') && !extension_loaded(
'memcached')) {
99 throw new Exception(
'The PHP extension "memcache" or "memcached" must be installed and loaded in ' .
'order to use the Memcached backend.', 1213987706);
102 parent::__construct(
$context, $options);
104 if ($this->usedPeclModule ===
'') {
105 if (extension_loaded(
'memcache')) {
106 $this->usedPeclModule =
'memcache';
107 } elseif (extension_loaded(
'memcached')) {
108 $this->usedPeclModule =
'memcached';
131 $compressionFlag = $this->usedPeclModule ===
'memcache' ? MEMCACHE_COMPRESSED : \Memcached::OPT_COMPRESSION;
132 if ($useCompression ===
true) {
133 $this->flags ^= $compressionFlag;
135 $this->flags &= ~$compressionFlag;
146 return $this->flags !== 0;
156 if (empty($this->servers)) {
157 throw new Exception(
'No servers were given to Memcache', 1213115903);
159 $memcachedPlugin =
'\\' . ucfirst($this->usedPeclModule);
160 $this->memcache =
new $memcachedPlugin;
161 $defaultPort = $this->usedPeclModule ===
'memcache' ? ini_get(
'memcache.default_port') : 11211;
162 foreach ($this->servers as $server) {
163 if (strpos($server,
'unix://') === 0) {
167 if (strpos($server,
'tcp://') === 0) {
168 $server = substr($server, 6);
170 if (strpos($server,
':') !==
false) {
171 list($host, $port) = explode(
':', $server, 2);
174 $port = $defaultPort;
177 $this->memcache->addserver($host, $port);
179 if ($this->usedPeclModule ===
'memcached') {
180 $this->memcache->setOption(\Memcached::OPT_COMPRESSION, $this->
getCompression());
192 if ($peclModule !==
'memcache' && $peclModule !==
'memcached') {
193 throw new Exception(
'PECL module must be either "memcache" or "memcached".', 1442239768);
196 $this->usedPeclModule = $peclModule;
208 $this->identifierPrefix =
'TYPO3_' . $identifierHash .
'_';
221 public function set($entryIdentifier, $data, array $tags = [], $lifetime =
null)
223 if (strlen($this->identifierPrefix . $entryIdentifier) > 250) {
224 throw new \InvalidArgumentException(
'Could not set value. Key more than 250 characters (' . $this->identifierPrefix . $entryIdentifier .
').', 1232969508);
226 if (!$this->cache instanceof FrontendInterface) {
227 throw new Exception(
'No cache frontend has been set yet via setCache().', 1207149215);
234 if ($expiration > 2592000) {
238 if (is_string($data) && strlen($data) > self::MAX_BUCKET_SIZE) {
239 $data = str_split($data, 1024 * 1000);
242 foreach ($data as $chunk) {
243 $success = $success && $this->
setInternal($entryIdentifier .
'_chunk_' . $chunkNumber, $chunk, $expiration);
246 $success = $success && $this->
setInternal($entryIdentifier,
'TYPO3*chunked:' . $chunkNumber, $expiration);
248 $success = $this->
setInternal($entryIdentifier, $data, $expiration);
250 if ($success ===
true) {
254 throw new Exception(
'Could not set data to memcache server.', 1275830266);
256 }
catch (\Exception $exception) {
257 $this->logger->alert(
'Memcache: could not set value.', [
'exception' => $exception]);
269 protected function setInternal($entryIdentifier, $data, $expiration)
271 if ($this->usedPeclModule ===
'memcache') {
272 return $this->memcache->set($this->identifierPrefix . $entryIdentifier, $data, $this->flags, $expiration);
274 return $this->memcache->set($this->identifierPrefix . $entryIdentifier, $data, $expiration);
283 public function get($entryIdentifier)
285 $value = $this->memcache->get($this->identifierPrefix . $entryIdentifier);
286 if (is_string($value) && strpos($value,
'TYPO3*chunked:') === 0) {
287 list(, $chunkCount) = explode(
':', $value);
289 for ($chunkNumber = 1; $chunkNumber < $chunkCount; $chunkNumber++) {
290 $value .= $this->memcache->get($this->identifierPrefix . $entryIdentifier .
'_chunk_' . $chunkNumber);
302 public function has($entryIdentifier)
304 if ($this->usedPeclModule ===
'memcache') {
305 return $this->memcache->get($this->identifierPrefix . $entryIdentifier) !==
false;
309 $this->memcache->get($this->identifierPrefix . $entryIdentifier);
310 return $this->memcache->getResultCode() !== \Memcached::RES_NOTFOUND;
321 public function remove($entryIdentifier)
324 return $this->memcache->delete($this->identifierPrefix . $entryIdentifier, 0);
336 $identifiers = $this->memcache->get($this->identifierPrefix .
'tag_' . $tag);
337 if ($identifiers !==
false) {
338 return (array)$identifiers;
350 if (!$this->cache instanceof FrontendInterface) {
351 throw new Exception(
'No cache frontend has been set via setCache() yet.', 1204111376);
353 $this->
flushByTag(
'%MEMCACHEBE%' . $this->cacheIdentifier);
364 foreach ($identifiers as $identifier) {
365 $this->
remove($identifier);
379 $existingTagsUpdated =
false;
381 foreach ($tags as $tag) {
384 if (!in_array($entryIdentifier, $identifiers,
true)) {
385 $identifiers[] = $entryIdentifier;
386 $this->memcache->set($this->identifierPrefix .
'tag_' . $tag, $identifiers);
389 if (!in_array($tag, $existingTags,
true)) {
390 $existingTags[] = $tag;
391 $existingTagsUpdated =
true;
396 if ($existingTagsUpdated) {
397 $this->memcache->set($this->identifierPrefix .
'ident_' . $entryIdentifier, $existingTags);
411 foreach ($tags as $tag) {
418 if (($key = array_search($entryIdentifier, $identifiers)) !==
false) {
419 unset($identifiers[$key]);
420 if (!empty($identifiers)) {
421 $this->memcache->set($this->identifierPrefix .
'tag_' . $tag, $identifiers);
423 $this->memcache->delete($this->identifierPrefix .
'tag_' . $tag, 0);
428 $this->memcache->delete($this->identifierPrefix .
'ident_' . $entryIdentifier, 0);
440 $tags = $this->memcache->get($this->identifierPrefix .
'ident_' . $identifier);
441 return $tags ===
false ? [] : (array)$tags;