d3af7f5843461a55238ccf58a8ff78b7c0cce78c
[yaffs-website] / web / core / lib / Drupal / Core / Cache / PhpBackend.php
1 <?php
2
3 namespace Drupal\Core\Cache;
4
5 use Drupal\Component\Assertion\Inspector;
6 use Drupal\Core\PhpStorage\PhpStorageFactory;
7 use Drupal\Component\Utility\Crypt;
8
9 /**
10  * Defines a PHP cache implementation.
11  *
12  * Stores cache items in a PHP file using a storage that implements
13  * Drupal\Component\PhpStorage\PhpStorageInterface.
14  *
15  * This is fast because of PHP's opcode caching mechanism. Once a file's
16  * content is stored in PHP's opcode cache, including it doesn't require
17  * reading the contents from a filesystem. Instead, PHP will use the already
18  * compiled opcodes stored in memory.
19  *
20  * @ingroup cache
21  */
22 class PhpBackend implements CacheBackendInterface {
23
24   /**
25    * @var string
26    */
27   protected $bin;
28
29   /**
30    * Array to store cache objects.
31    */
32   protected $cache = [];
33
34   /**
35    * The cache tags checksum provider.
36    *
37    * @var \Drupal\Core\Cache\CacheTagsChecksumInterface
38    */
39   protected $checksumProvider;
40
41   /**
42    * Constructs a PhpBackend object.
43    *
44    * @param string $bin
45    *   The cache bin for which the object is created.
46    * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider
47    *   The cache tags checksum provider.
48    */
49   public function __construct($bin, CacheTagsChecksumInterface $checksum_provider) {
50     $this->bin = 'cache_' . $bin;
51     $this->checksumProvider = $checksum_provider;
52   }
53
54   /**
55    * {@inheritdoc}
56    */
57   public function get($cid, $allow_invalid = FALSE) {
58     return $this->getByHash($this->normalizeCid($cid), $allow_invalid);
59   }
60
61   /**
62    * Fetch a cache item using a hashed cache ID.
63    *
64    * @param string $cidhash
65    *   The hashed version of the original cache ID after being normalized.
66    * @param bool $allow_invalid
67    *   (optional) If TRUE, a cache item may be returned even if it is expired or
68    *   has been invalidated.
69    *
70    * @return bool|mixed
71    */
72   protected function getByHash($cidhash, $allow_invalid = FALSE) {
73     if ($file = $this->storage()->getFullPath($cidhash)) {
74       $cache = @include $file;
75     }
76     if (isset($cache)) {
77       return $this->prepareItem($cache, $allow_invalid);
78     }
79     return FALSE;
80   }
81
82   /**
83    * {@inheritdoc}
84    */
85   public function setMultiple(array $items) {
86     foreach ($items as $cid => $item) {
87       $this->set($cid, $item['data'], isset($item['expire']) ? $item['expire'] : CacheBackendInterface::CACHE_PERMANENT, isset($item['tags']) ? $item['tags'] : []);
88     }
89   }
90
91   /**
92    * {@inheritdoc}
93    */
94   public function getMultiple(&$cids, $allow_invalid = FALSE) {
95     $ret = [];
96
97     foreach ($cids as $cid) {
98       if ($item = $this->get($cid, $allow_invalid)) {
99         $ret[$item->cid] = $item;
100       }
101     }
102
103     $cids = array_diff($cids, array_keys($ret));
104
105     return $ret;
106   }
107
108   /**
109    * Prepares a cached item.
110    *
111    * Checks that items are either permanent or did not expire, and returns data
112    * as appropriate.
113    *
114    * @param object $cache
115    *   An item loaded from cache_get() or cache_get_multiple().
116    * @param bool $allow_invalid
117    *   If FALSE, the method returns FALSE if the cache item is not valid.
118    *
119    * @return mixed
120    *   The item with data as appropriate or FALSE if there is no
121    *   valid item to load.
122    */
123   protected function prepareItem($cache, $allow_invalid) {
124     if (!isset($cache->data)) {
125       return FALSE;
126     }
127
128     // Check expire time.
129     $cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME;
130
131     // Check if invalidateTags() has been called with any of the item's tags.
132     if (!$this->checksumProvider->isValid($cache->checksum, $cache->tags)) {
133       $cache->valid = FALSE;
134     }
135
136     if (!$allow_invalid && !$cache->valid) {
137       return FALSE;
138     }
139
140     return $cache;
141   }
142
143   /**
144    * {@inheritdoc}
145    */
146   public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = []) {
147     assert(Inspector::assertAllStrings($tags), 'Cache Tags must be strings.');
148
149     $item = (object) [
150       'cid' => $cid,
151       'data' => $data,
152       'created' => round(microtime(TRUE), 3),
153       'expire' => $expire,
154       'tags' => array_unique($tags),
155       'checksum' => $this->checksumProvider->getCurrentChecksum($tags),
156     ];
157     $this->writeItem($this->normalizeCid($cid), $item);
158   }
159
160   /**
161    * {@inheritdoc}
162    */
163   public function delete($cid) {
164     $this->storage()->delete($this->normalizeCid($cid));
165   }
166
167   /**
168    * {@inheritdoc}
169    */
170   public function deleteMultiple(array $cids) {
171     foreach ($cids as $cid) {
172       $this->delete($cid);
173     }
174   }
175
176   /**
177    * {@inheritdoc}
178    */
179   public function deleteAll() {
180     $this->storage()->deleteAll();
181   }
182
183   /**
184    * {@inheritdoc}
185    */
186   public function invalidate($cid) {
187     $this->invalidatebyHash($this->normalizeCid($cid));
188   }
189
190   /**
191    * Invalidate one cache item.
192    *
193    * @param string $cidhash
194    *   The hashed version of the original cache ID after being normalized.
195    */
196   protected function invalidatebyHash($cidhash) {
197     if ($item = $this->getByHash($cidhash)) {
198       $item->expire = REQUEST_TIME - 1;
199       $this->writeItem($cidhash, $item);
200     }
201   }
202
203   /**
204    * {@inheritdoc}
205    */
206   public function invalidateMultiple(array $cids) {
207     foreach ($cids as $cid) {
208       $this->invalidate($cid);
209     }
210   }
211
212   /**
213    * {@inheritdoc}
214    */
215   public function invalidateAll() {
216     foreach ($this->storage()->listAll() as $cidhash) {
217       $this->invalidatebyHash($cidhash);
218     }
219   }
220
221   /**
222    * {@inheritdoc}
223    */
224   public function garbageCollection() {
225   }
226
227   /**
228    * {@inheritdoc}
229    */
230   public function removeBin() {
231     $this->cache = [];
232     $this->storage()->deleteAll();
233   }
234
235   /**
236    * Writes a cache item to PhpStorage.
237    *
238    * @param string $cidhash
239    *   The hashed version of the original cache ID after being normalized.
240    * @param \stdClass $item
241    *   The cache item to store.
242    */
243   protected function writeItem($cidhash, \stdClass $item) {
244     $content = '<?php return unserialize(' . var_export(serialize($item), TRUE) . ');';
245     $this->storage()->save($cidhash, $content);
246   }
247
248   /**
249    * Gets the PHP code storage object to use.
250    *
251    * @return \Drupal\Component\PhpStorage\PhpStorageInterface
252    */
253   protected function storage() {
254     if (!isset($this->storage)) {
255       $this->storage = PhpStorageFactory::get($this->bin);
256     }
257     return $this->storage;
258   }
259
260   /**
261    * Ensures a normalized cache ID.
262    *
263    * @param string $cid
264    *   The passed in cache ID.
265    *
266    * @return string
267    *   A normalized cache ID.
268    */
269   protected function normalizeCid($cid) {
270     return Crypt::hashBase64($cid);
271   }
272
273 }