TYPO3 CMS  TYPO3_7-6
SimpleFileBackend.php
Go to the documentation of this file.
1 <?php
3 
4 /* *
5  * This script belongs to the FLOW3 framework. *
6  * *
7  * It is free software; you can redistribute it and/or modify it under *
8  * the terms of the GNU Lesser General Public License, either version 3 *
9  * of the License, or (at your option) any later version. *
10  * *
11  * The TYPO3 project - inspiring people to share! *
12  * */
13 
17 
25 {
26  const SEPARATOR = '^';
27  const EXPIRYTIME_FORMAT = 'YmdHis';
28  const EXPIRYTIME_LENGTH = 14;
29  const DATASIZE_DIGITS = 10;
35  protected $cacheDirectory = '';
36 
46  protected $temporaryCacheDirectory = '';
47 
53  protected $cacheEntryFileExtension = '';
54 
58  protected $cacheEntryIdentifiers = [];
59 
63  protected $frozen = false;
64 
71  protected $useIgBinary = false;
72 
78  public function initializeObject()
79  {
80  $this->useIgBinary = extension_loaded('igbinary');
81  }
82 
95  public function setCache(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache)
96  {
97  parent::setCache($cache);
98  if (empty($this->temporaryCacheDirectory)) {
99  // If no cache directory was given with cacheDirectory
100  // configuration option, set it to a path below typo3temp/
101  $temporaryCacheDirectory = PATH_site . 'typo3temp/';
102  } else {
104  }
105  $codeOrData = $cache instanceof \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend ? 'Code' : 'Data';
106  $finalCacheDirectory = $temporaryCacheDirectory . 'Cache/' . $codeOrData . '/' . $this->cacheIdentifier . '/';
107  if (!is_dir($finalCacheDirectory)) {
108  $this->createFinalCacheDirectory($finalCacheDirectory);
109  }
110  unset($this->temporaryCacheDirectory);
111  $this->cacheDirectory = $finalCacheDirectory;
112  $this->cacheEntryFileExtension = $cache instanceof \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend ? '.php' : '';
113  if (strlen($this->cacheDirectory) + 23 > \TYPO3\CMS\Core\Utility\GeneralUtility::getMaximumPathLength()) {
114  throw new \TYPO3\CMS\Core\Cache\Exception('The length of the temporary cache file path "' . $this->cacheDirectory . '" exceeds the ' . 'maximum path length of ' . (\TYPO3\CMS\Core\Utility\GeneralUtility::getMaximumPathLength() - 23) . '. Please consider ' . 'setting the temporaryDirectoryBase option to a shorter path.', 1248710426);
115  }
116  }
117 
134  {
135  // Skip handling if directory is a stream ressource
136  // This is used by unit tests with vfs:// directoryies
137  if (strpos($cacheDirectory, '://')) {
138  $this->temporaryCacheDirectory = $cacheDirectory;
139  return;
140  }
141  $documentRoot = PATH_site;
142  if ($open_basedir = ini_get('open_basedir')) {
143  if (TYPO3_OS === 'WIN') {
144  $delimiter = ';';
145  $cacheDirectory = str_replace('\\', '/', $cacheDirectory);
146  if (!preg_match('/[A-Z]:/', substr($cacheDirectory, 0, 2))) {
147  $cacheDirectory = PATH_site . $cacheDirectory;
148  }
149  } else {
150  $delimiter = ':';
151  if ($cacheDirectory[0] != '/') {
152  // relative path to cache directory.
153  $cacheDirectory = PATH_site . $cacheDirectory;
154  }
155  }
156  $basedirs = explode($delimiter, $open_basedir);
157  $cacheDirectoryInBaseDir = false;
158  foreach ($basedirs as $basedir) {
159  if (TYPO3_OS === 'WIN') {
160  $basedir = str_replace('\\', '/', $basedir);
161  }
162  if ($basedir[strlen($basedir) - 1] !== '/') {
163  $basedir .= '/';
164  }
165  if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($cacheDirectory, $basedir)) {
166  $documentRoot = $basedir;
167  $cacheDirectory = str_replace($basedir, '', $cacheDirectory);
168  $cacheDirectoryInBaseDir = true;
169  break;
170  }
171  }
172  if (!$cacheDirectoryInBaseDir) {
173  throw new \TYPO3\CMS\Core\Cache\Exception('Open_basedir restriction in effect. The directory "' . $cacheDirectory . '" is not in an allowed path.');
174  }
175  } else {
176  if ($cacheDirectory[0] == '/') {
177  // Absolute path to cache directory.
178  $documentRoot = '';
179  }
180  if (TYPO3_OS === 'WIN') {
181  if (substr($cacheDirectory, 0, strlen($documentRoot)) === $documentRoot) {
182  $documentRoot = '';
183  }
184  }
185  }
186  // After this point all paths have '/' as directory separator
187  if ($cacheDirectory[strlen($cacheDirectory) - 1] !== '/') {
188  $cacheDirectory .= '/';
189  }
190  $this->temporaryCacheDirectory = $documentRoot . $cacheDirectory . $this->cacheIdentifier . '/';
191  }
192 
201  protected function createFinalCacheDirectory($finalCacheDirectory)
202  {
203  try {
205  } catch (\RuntimeException $e) {
206  throw new \TYPO3\CMS\Core\Cache\Exception('The directory "' . $finalCacheDirectory . '" can not be created.', 1303669848, $e);
207  }
208  if (!is_writable($finalCacheDirectory)) {
209  throw new \TYPO3\CMS\Core\Cache\Exception('The directory "' . $finalCacheDirectory . '" is not writable.', 1203965200);
210  }
211  }
212 
219  public function getCacheDirectory()
220  {
221  return $this->cacheDirectory;
222  }
223 
237  public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
238  {
239  if (!is_string($data)) {
240  throw new \TYPO3\CMS\Core\Cache\Exception\InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1334756734);
241  }
242  if ($entryIdentifier !== basename($entryIdentifier)) {
243  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1334756735);
244  }
245  if ($entryIdentifier === '') {
246  throw new \InvalidArgumentException('The specified entry identifier must not be empty.', 1334756736);
247  }
248  $temporaryCacheEntryPathAndFilename = $this->cacheDirectory . StringUtility::getUniqueId() . '.temp';
249  $result = file_put_contents($temporaryCacheEntryPathAndFilename, $data);
250  \TYPO3\CMS\Core\Utility\GeneralUtility::fixPermissions($temporaryCacheEntryPathAndFilename);
251  if ($result === false) {
252  throw new \TYPO3\CMS\Core\Cache\Exception('The temporary cache file "' . $temporaryCacheEntryPathAndFilename . '" could not be written.', 1334756737);
253  }
254  $cacheEntryPathAndFilename = $this->cacheDirectory . $entryIdentifier . $this->cacheEntryFileExtension;
255  rename($temporaryCacheEntryPathAndFilename, $cacheEntryPathAndFilename);
256  if ($this->cacheEntryFileExtension === '.php') {
257  GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive($cacheEntryPathAndFilename);
258  }
259  }
260 
269  public function get($entryIdentifier)
270  {
271  if ($entryIdentifier !== basename($entryIdentifier)) {
272  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1334756877);
273  }
274  $pathAndFilename = $this->cacheDirectory . $entryIdentifier . $this->cacheEntryFileExtension;
275  if (!file_exists($pathAndFilename)) {
276  return false;
277  }
278  return file_get_contents($pathAndFilename);
279  }
280 
289  public function has($entryIdentifier)
290  {
291  if ($entryIdentifier !== basename($entryIdentifier)) {
292  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1334756878);
293  }
294  return file_exists($this->cacheDirectory . $entryIdentifier . $this->cacheEntryFileExtension);
295  }
296 
306  public function remove($entryIdentifier)
307  {
308  if ($entryIdentifier !== basename($entryIdentifier)) {
309  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1334756960);
310  }
311  if ($entryIdentifier === '') {
312  throw new \InvalidArgumentException('The specified entry identifier must not be empty.', 1334756961);
313  }
314  try {
315  unlink($this->cacheDirectory . $entryIdentifier . $this->cacheEntryFileExtension);
316  } catch (\Exception $e) {
317  return false;
318  }
319  return true;
320  }
321 
328  public function flush()
329  {
330  \TYPO3\CMS\Core\Utility\GeneralUtility::flushDirectory($this->cacheDirectory, true);
331  }
332 
341  protected function isCacheFileExpired($cacheEntryPathAndFilename)
342  {
343  return file_exists($cacheEntryPathAndFilename) === false;
344  }
345 
352  public function collectGarbage()
353  {
354  }
355 
362  protected function findCacheFilesByIdentifier($entryIdentifier)
363  {
364  $pathAndFilename = $this->cacheDirectory . $entryIdentifier . $this->cacheEntryFileExtension;
365  return file_exists($pathAndFilename) ? [$pathAndFilename] : false;
366  }
367 
376  public function requireOnce($entryIdentifier)
377  {
378  $pathAndFilename = $this->cacheDirectory . $entryIdentifier . $this->cacheEntryFileExtension;
379  if ($entryIdentifier !== basename($entryIdentifier)) {
380  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1282073037);
381  }
382  return file_exists($pathAndFilename) ? require_once $pathAndFilename : false;
383  }
384 }
static mkdir_deep($directory, $deepDirectory='')
static flushDirectory($directory, $keepOriginalDirectory=false, $flushOpcodeCache=false)
static isFirstPartOfStr($str, $partStr)
setCache(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache)
static fixPermissions($path, $recursive=false)