‪TYPO3CMS  ‪main
SimpleFileBackend.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
27 
33 {
34  public const ‪SEPARATOR = '^';
35  public const ‪EXPIRYTIME_FORMAT = 'YmdHis';
36  public const ‪EXPIRYTIME_LENGTH = 14;
37  public const ‪DATASIZE_DIGITS = 10;
43  protected ‪$cacheDirectory = '';
44 
53  protected ‪$temporaryCacheDirectory = '';
54 
60  protected ‪$cacheEntryFileExtension = '';
61 
65  protected ‪$cacheEntryIdentifiers = [];
66 
70  protected ‪$frozen = false;
71 
80  {
81  parent::setCache(‪$cache);
82  if (empty($this->temporaryCacheDirectory)) {
83  // If no cache directory was given with cacheDirectory
84  // configuration option, set it to a path below var/ folder
86  } else {
88  }
89  $codeOrData = ‪$cache instanceof ‪PhpFrontend ? 'code' : 'data';
90  $finalCacheDirectory = ‪$temporaryCacheDirectory . 'cache/' . $codeOrData . '/' . $this->cacheIdentifier . '/';
91  if (!is_dir($finalCacheDirectory)) {
92  $this->‪createFinalCacheDirectory($finalCacheDirectory);
93  }
94  unset($this->temporaryCacheDirectory);
95  $this->cacheDirectory = $finalCacheDirectory;
96  $this->cacheEntryFileExtension = ‪$cache instanceof ‪PhpFrontend ? '.php' : '';
97  if (strlen($this->cacheDirectory) + 23 > PHP_MAXPATHLEN) {
98  throw new ‪Exception('The length of the temporary cache file path "' . $this->cacheDirectory . '" exceeds the maximum path length of ' . (PHP_MAXPATHLEN - 23) . '. Please consider setting the temporaryDirectoryBase option to a shorter path.', 1248710426);
99  }
100  }
101 
116  {
117  // Skip handling if directory is a stream resource
118  // This is used by unit tests with vfs:// directories
120  $this->temporaryCacheDirectory = ‪$cacheDirectory;
121  return;
122  }
123  $documentRoot = ‪Environment::getProjectPath() . '/';
124  if ($open_basedir = ini_get('open_basedir')) {
126  $delimiter = ';';
127  ‪$cacheDirectory = str_replace('\\', '/', ‪$cacheDirectory);
128  if (!preg_match('/[A-Z]:/', substr(‪$cacheDirectory, 0, 2))) {
130  }
131  } else {
132  $delimiter = ':';
133  if (‪$cacheDirectory[0] !== '/') {
134  // relative path to cache directory.
136  }
137  }
138  $basedirs = explode($delimiter, $open_basedir);
139  $cacheDirectoryInBaseDir = false;
140  foreach ($basedirs as $basedir) {
142  $basedir = str_replace('\\', '/', $basedir);
143  }
144  if ($basedir[strlen($basedir) - 1] !== '/') {
145  $basedir .= '/';
146  }
147  if (str_starts_with(‪$cacheDirectory, $basedir)) {
148  $documentRoot = $basedir;
149  ‪$cacheDirectory = str_replace($basedir, '', ‪$cacheDirectory);
150  $cacheDirectoryInBaseDir = true;
151  break;
152  }
153  }
154  if (!$cacheDirectoryInBaseDir) {
155  throw new Exception(
156  'Open_basedir restriction in effect. The directory "' . ‪$cacheDirectory . '" is not in an allowed path.',
157  1476045417
158  );
159  }
160  } else {
161  if (‪$cacheDirectory[0] === '/') {
162  // Absolute path to cache directory.
163  $documentRoot = '';
164  }
166  if (!empty($documentRoot) && str_starts_with(‪$cacheDirectory, $documentRoot)) {
167  $documentRoot = '';
168  }
169  }
170  }
171  // After this point all paths have '/' as directory separator
172  if (‪$cacheDirectory[strlen(‪$cacheDirectory) - 1] !== '/') {
173  ‪$cacheDirectory .= '/';
174  }
175  $this->temporaryCacheDirectory = $documentRoot . ‪$cacheDirectory;
176  }
177 
184  protected function ‪createFinalCacheDirectory($finalCacheDirectory)
185  {
186  try {
187  ‪GeneralUtility::mkdir_deep($finalCacheDirectory);
188  } catch (\RuntimeException $e) {
189  throw new Exception('The directory "' . $finalCacheDirectory . '" can not be created.', 1303669848, $e);
190  }
191  if (!is_writable($finalCacheDirectory)) {
192  throw new Exception('The directory "' . $finalCacheDirectory . '" is not writable.', 1203965200);
193  }
194  }
195 
201  public function ‪getCacheDirectory()
202  {
204  }
205 
217  public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
218  {
219  if (!is_string($data)) {
220  throw new InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1334756734);
221  }
222  if ($entryIdentifier !== ‪PathUtility::basename($entryIdentifier)) {
223  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1334756735);
224  }
225  if ($entryIdentifier === '') {
226  throw new \InvalidArgumentException('The specified entry identifier must not be empty.', 1334756736);
227  }
228  $temporaryCacheEntryPathAndFilename = $this->cacheDirectory . ‪StringUtility::getUniqueId() . '.temp';
229  $result = file_put_contents($temporaryCacheEntryPathAndFilename, $data);
230  ‪GeneralUtility::fixPermissions($temporaryCacheEntryPathAndFilename);
231  if ($result === false) {
232  throw new Exception('The temporary cache file "' . $temporaryCacheEntryPathAndFilename . '" could not be written.', 1334756737);
233  }
234  $cacheEntryPathAndFilename = $this->cacheDirectory . $entryIdentifier . ‪$this->cacheEntryFileExtension;
235  rename($temporaryCacheEntryPathAndFilename, $cacheEntryPathAndFilename);
236  if ($this->cacheEntryFileExtension === '.php') {
237  GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive($cacheEntryPathAndFilename);
238  }
239  }
240 
248  public function get($entryIdentifier)
249  {
250  if ($entryIdentifier !== ‪PathUtility::basename($entryIdentifier)) {
251  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1334756877);
252  }
253  $pathAndFilename = $this->cacheDirectory . $entryIdentifier . ‪$this->cacheEntryFileExtension;
254  if (!file_exists($pathAndFilename)) {
255  return false;
256  }
257  return file_get_contents($pathAndFilename);
258  }
259 
267  public function ‪has($entryIdentifier)
268  {
269  if ($entryIdentifier !== ‪PathUtility::basename($entryIdentifier)) {
270  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1334756878);
271  }
272  return file_exists($this->cacheDirectory . $entryIdentifier . $this->cacheEntryFileExtension);
273  }
274 
283  public function remove($entryIdentifier)
284  {
285  if ($entryIdentifier !== ‪PathUtility::basename($entryIdentifier)) {
286  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1334756960);
287  }
288  if ($entryIdentifier === '') {
289  throw new \InvalidArgumentException('The specified entry identifier must not be empty.', 1334756961);
290  }
291  $file = $this->cacheDirectory . $entryIdentifier . ‪$this->cacheEntryFileExtension;
292  if (file_exists($file)) {
293  return unlink($file);
294  }
295  return false;
296  }
297 
304  public function ‪flush()
305  {
306  $directory = ‪$this->cacheDirectory;
307  if (is_link($directory)) {
308  // Avoid attempting to rename the symlink see #87367
309  $directory = (string)realpath($directory);
310  }
311 
312  if (is_dir($directory)) {
313  $temporaryDirectory = rtrim($directory, '/') . '.' . ‪StringUtility::getUniqueId('remove');
314  if (rename($directory, $temporaryDirectory)) {
315  ‪GeneralUtility::mkdir($directory);
316  clearstatcache();
317  ‪GeneralUtility::rmdir($temporaryDirectory, true);
318  }
319  }
320  }
321 
329  protected function ‪isCacheFileExpired($cacheEntryPathAndFilename)
330  {
331  return file_exists($cacheEntryPathAndFilename) === false;
332  }
333 
337  public function ‪collectGarbage() {}
338 
345  protected function ‪findCacheFilesByIdentifier($entryIdentifier)
346  {
347  $pathAndFilename = $this->cacheDirectory . $entryIdentifier . ‪$this->cacheEntryFileExtension;
348  return file_exists($pathAndFilename) ? [$pathAndFilename] : false;
349  }
350 
358  public function ‪requireOnce($entryIdentifier)
359  {
360  $pathAndFilename = $this->cacheDirectory . $entryIdentifier . ‪$this->cacheEntryFileExtension;
361  if ($entryIdentifier !== ‪PathUtility::basename($entryIdentifier)) {
362  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1282073037);
363  }
364  return file_exists($pathAndFilename) ? require_once $pathAndFilename : false;
365  }
366 
374  public function require(string $entryIdentifier)
375  {
376  $pathAndFilename = $this->cacheDirectory . $entryIdentifier . ‪$this->cacheEntryFileExtension;
377  if ($entryIdentifier !== ‪PathUtility::basename($entryIdentifier)) {
378  throw new \InvalidArgumentException('The specified entry identifier must not contain a path segment.', 1532528267);
379  }
380  return file_exists($pathAndFilename) ? require $pathAndFilename : false;
381  }
382 }
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir
‪static bool mkdir(string $newFolder)
Definition: GeneralUtility.php:1638
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\flush
‪flush()
Definition: SimpleFileBackend.php:299
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:27
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\$cacheEntryFileExtension
‪string $cacheEntryFileExtension
Definition: SimpleFileBackend.php:57
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$cache
‪FrontendInterface $cache
Definition: AbstractBackend.php:38
‪TYPO3\CMS\Core\Cache\Frontend\PhpFrontend
Definition: PhpFrontend.php:25
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\$cacheDirectory
‪string $cacheDirectory
Definition: SimpleFileBackend.php:42
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\has
‪bool has($entryIdentifier)
Definition: SimpleFileBackend.php:262
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\createFinalCacheDirectory
‪createFinalCacheDirectory($finalCacheDirectory)
Definition: SimpleFileBackend.php:179
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\findCacheFilesByIdentifier
‪mixed findCacheFilesByIdentifier($entryIdentifier)
Definition: SimpleFileBackend.php:340
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\$cacheEntryIdentifiers
‪array $cacheEntryIdentifiers
Definition: SimpleFileBackend.php:61
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\collectGarbage
‪collectGarbage()
Definition: SimpleFileBackend.php:332
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\setCacheDirectory
‪setCacheDirectory($cacheDirectory)
Definition: SimpleFileBackend.php:110
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir_deep
‪static mkdir_deep(string $directory)
Definition: GeneralUtility.php:1654
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static getVarPath()
Definition: Environment.php:197
‪TYPO3\CMS\Core\Utility\PathUtility\basename
‪static basename(string $path)
Definition: PathUtility.php:219
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\$temporaryCacheDirectory
‪string $temporaryCacheDirectory
Definition: SimpleFileBackend.php:51
‪TYPO3\CMS\Core\Cache\Backend\PhpCapableBackendInterface
Definition: PhpCapableBackendInterface.php:23
‪TYPO3\CMS\Core\Core\Environment\getProjectPath
‪static string getProjectPath()
Definition: Environment.php:160
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\setCache
‪setCache(FrontendInterface $cache)
Definition: SimpleFileBackend.php:74
‪TYPO3\CMS\Core\Cache\Exception
Definition: DuplicateIdentifierException.php:16
‪TYPO3\CMS\Core\Cache\Exception\InvalidDataException
Definition: InvalidDataException.php:23
‪TYPO3\CMS\Core\Utility\GeneralUtility\rmdir
‪static bool rmdir(string $path, bool $removeNonEmpty=false)
Definition: GeneralUtility.php:1702
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend
Definition: SimpleFileBackend.php:33
‪TYPO3\CMS\Core\Service\OpcodeCacheService
Definition: OpcodeCacheService.php:27
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\requireOnce
‪mixed requireOnce($entryIdentifier)
Definition: SimpleFileBackend.php:353
‪TYPO3\CMS\Core\Utility\GeneralUtility\fixPermissions
‪static bool fixPermissions(string $path, bool $recursive=false)
Definition: GeneralUtility.php:1496
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\EXPIRYTIME_FORMAT
‪const EXPIRYTIME_FORMAT
Definition: SimpleFileBackend.php:35
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\DATASIZE_DIGITS
‪const DATASIZE_DIGITS
Definition: SimpleFileBackend.php:37
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\EXPIRYTIME_LENGTH
‪const EXPIRYTIME_LENGTH
Definition: SimpleFileBackend.php:36
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend
Definition: AbstractBackend.php:28
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\getCacheDirectory
‪string getCacheDirectory()
Definition: SimpleFileBackend.php:196
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\SEPARATOR
‪const SEPARATOR
Definition: SimpleFileBackend.php:34
‪TYPO3\CMS\Core\Cache\Backend
Definition: AbstractBackend.php:16
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\isCacheFileExpired
‪bool isCacheFileExpired($cacheEntryPathAndFilename)
Definition: SimpleFileBackend.php:324
‪TYPO3\CMS\Core\Utility\PathUtility\hasProtocolAndScheme
‪static hasProtocolAndScheme(string $path)
Definition: PathUtility.php:445
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:24
‪TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend\$frozen
‪bool $frozen
Definition: SimpleFileBackend.php:65
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static getUniqueId(string $prefix='')
Definition: StringUtility.php:57
‪TYPO3\CMS\Core\Cache\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Core\Core\Environment\isWindows
‪static isWindows()
Definition: Environment.php:276