TYPO3  7.6
XcacheBackend.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Cache\Backend;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 
40 {
46  protected $identifierPrefix;
47 
55  public function __construct($context, array $options = array())
56  {
57  if (!extension_loaded('xcache')) {
58  throw new Exception(
59  'The PHP extension "xcache" must be installed and loaded in order to use the xcache backend.',
60  1363116592
61  );
62  }
63  parent::__construct($context, $options);
64  }
65 
77  public function set($entryIdentifier, $data, array $tags = array(), $lifetime = null)
78  {
80  return;
81  }
82  if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
83  throw new Exception(
84  'No cache frontend has been set yet via setCache().',
85  1363117491
86  );
87  }
88  if (!is_string($data)) {
89  throw new Exception\InvalidDataException(
90  'The specified data is of type "' . gettype($data) . '" but a string is expected.',
91  1363117435
92  );
93  }
94  $tags[] = '%XCBE%' . $this->cache->getIdentifier();
95  $expiration = $lifetime !== null ? $lifetime : $this->defaultLifetime;
96  $success = xcache_set($this->identifierPrefix . $entryIdentifier, $data, $expiration);
97  if ($success === true) {
98  $this->removeIdentifierFromAllTags($entryIdentifier);
99  $this->addIdentifierToTags($entryIdentifier, $tags);
100  } else {
101  throw new Exception(
102  'Could not set value.',
103  1363117507
104  );
105  }
106  }
107 
114  public function get($entryIdentifier)
115  {
116  if ($this->runningFromCliOrWrongConfiguration()) {
117  return false;
118  }
119  $value = xcache_get($this->identifierPrefix . $entryIdentifier);
120  return $value ?: false;
121  }
122 
129  public function has($entryIdentifier)
130  {
131  if ($this->runningFromCliOrWrongConfiguration()) {
132  return false;
133  }
134  return xcache_isset($this->identifierPrefix . $entryIdentifier);
135  }
136 
145  public function remove($entryIdentifier)
146  {
147  if ($this->runningFromCliOrWrongConfiguration()) {
148  return false;
149  }
150  $this->removeIdentifierFromAllTags($entryIdentifier);
151  return xcache_unset($this->identifierPrefix . $entryIdentifier);
152  }
153 
161  public function findIdentifiersByTag($tag)
162  {
163  if ($this->runningFromCliOrWrongConfiguration()) {
164  return array();
165  }
166  $identifiers = xcache_get($this->identifierPrefix . 'tag_' . $tag);
167  return $identifiers ?: array();
168  }
169 
177  protected function findTagsByIdentifier($identifier)
178  {
179  if ($this->runningFromCliOrWrongConfiguration()) {
180  return array();
181  }
182  $tags = xcache_get($this->identifierPrefix . 'ident_' . $identifier);
183  return $tags ?: array();
184  }
185 
192  public function flush()
193  {
194  if ($this->runningFromCliOrWrongConfiguration()) {
195  return;
196  }
197  if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
198  throw new Exception(
199  'Yet no cache frontend has been set via setCache().',
200  1363117531
201  );
202  }
203  $this->flushByTag('%XCBE%' . $this->cache->getIdentifier());
204  }
205 
213  public function flushByTag($tag)
214  {
215  $identifiers = $this->findIdentifiersByTag($tag);
216  foreach ($identifiers as $identifier) {
217  $this->remove($identifier);
218  }
219  }
220 
228  protected function addIdentifierToTags($entryIdentifier, array $tags)
229  {
230  if ($this->runningFromCliOrWrongConfiguration()) {
231  return;
232  }
233 
234  // Get identifier-to-tag index to look for updates
235  $existingTags = $this->findTagsByIdentifier($entryIdentifier);
236  $existingTagsUpdated = false;
237 
238 
239  foreach ($tags as $tag) {
240  // Update tag-to-identifier index
241  $identifiers = $this->findIdentifiersByTag($tag);
242  if (!in_array($entryIdentifier, $identifiers, true)) {
243  $identifiers[] = $entryIdentifier;
244  xcache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
245  }
246  // Test if identifier-to-tag index needs update
247  if (!in_array($tag, $existingTags, true)) {
248  $existingTags[] = $tag;
249  $existingTagsUpdated = true;
250  }
251  }
252 
253  // Update identifier-to-tag index if needed
254  if ($existingTagsUpdated) {
255  xcache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags);
256  }
257  }
258 
265  protected function removeIdentifierFromAllTags($entryIdentifier)
266  {
267  if ($this->runningFromCliOrWrongConfiguration()) {
268  return;
269  }
270  // Get tags for this identifier
271  $tags = $this->findTagsByIdentifier($entryIdentifier);
272  // Disassociate tags with this identifier
273  foreach ($tags as $tag) {
274  $identifiers = $this->findIdentifiersByTag($tag);
275  // Formally array_search() below should never return false due to
276  // the behavior of findTagsByIdentifier(). But if reverse index is
277  // corrupted, we still can get 'false' from array_search(). This is
278  // not a problem because we are removing this identifier from
279  // anywhere.
280  if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
281  unset($identifiers[$key]);
282  if (!empty($identifiers)) {
283  xcache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
284  } else {
285  xcache_unset($this->identifierPrefix . 'tag_' . $tag);
286  }
287  }
288  }
289  // Clear reverse tag index for this identifier
290  xcache_unset($this->identifierPrefix . 'ident_' . $entryIdentifier);
291  }
292 
298  public function collectGarbage()
299  {
300  }
301 
310  {
311  $varSize = ini_get('xcache.var_size');
312  return php_sapi_name() === 'cli' || empty($varSize);
313  }
314 }