vendor/symfony/cache/Traits/PhpFilesTrait.php line 96

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Cache\Traits;
  11. use Symfony\Component\Cache\Exception\CacheException;
  12. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  13. use Symfony\Component\VarExporter\VarExporter;
  14. /**
  15.  * @author Piotr Stankowski <git@trakos.pl>
  16.  * @author Nicolas Grekas <p@tchwork.com>
  17.  * @author Rob Frawley 2nd <rmf@src.run>
  18.  *
  19.  * @internal
  20.  */
  21. trait PhpFilesTrait
  22. {
  23.     use FilesystemCommonTrait {
  24.         doClear as private doCommonClear;
  25.         doDelete as private doCommonDelete;
  26.     }
  27.     private $includeHandler;
  28.     private $appendOnly;
  29.     private $values = array();
  30.     private $files = array();
  31.     private static $startTime;
  32.     public static function isSupported()
  33.     {
  34.         self::$startTime self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
  35.         return \function_exists('opcache_invalidate') && ('cli' !== \PHP_SAPI || filter_var(ini_get('opcache.enable_cli'), FILTER_VALIDATE_BOOLEAN)) && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN);
  36.     }
  37.     /**
  38.      * @return bool
  39.      */
  40.     public function prune()
  41.     {
  42.         $time time();
  43.         $pruned true;
  44.         set_error_handler($this->includeHandler);
  45.         try {
  46.             foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
  47.                 try {
  48.                     list($expiresAt) = include $file;
  49.                 } catch (\ErrorException $e) {
  50.                     $expiresAt $time;
  51.                 }
  52.                 if ($time >= $expiresAt) {
  53.                     $pruned $this->doUnlink($file) && !file_exists($file) && $pruned;
  54.                 }
  55.             }
  56.         } finally {
  57.             restore_error_handler();
  58.         }
  59.         return $pruned;
  60.     }
  61.     /**
  62.      * {@inheritdoc}
  63.      */
  64.     protected function doFetch(array $ids)
  65.     {
  66.         if ($this->appendOnly) {
  67.             $now 0;
  68.             $missingIds = array();
  69.         } else {
  70.             $now time();
  71.             $missingIds $ids;
  72.             $ids = array();
  73.         }
  74.         $values = array();
  75.         begin:
  76.         foreach ($ids as $id) {
  77.             if (null === $value $this->values[$id] ?? null) {
  78.                 $missingIds[] = $id;
  79.             } elseif ('N;' === $value) {
  80.                 $values[$id] = null;
  81.             } elseif ($value instanceof \Closure) {
  82.                 $values[$id] = $value();
  83.             } else {
  84.                 $values[$id] = $value;
  85.             }
  86.             if (!$this->appendOnly) {
  87.                 unset($this->values[$id]);
  88.             }
  89.         }
  90.         if (!$missingIds) {
  91.             return $values;
  92.         }
  93.         set_error_handler($this->includeHandler);
  94.         try {
  95.             foreach ($missingIds as $k => $id) {
  96.                 try {
  97.                     $file $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
  98.                     list($expiresAt$this->values[$id]) = include $file;
  99.                     if ($now >= $expiresAt) {
  100.                         unset($this->values[$id], $missingIds[$k]);
  101.                     }
  102.                 } catch (\ErrorException $e) {
  103.                     unset($missingIds[$k]);
  104.                 }
  105.             }
  106.         } finally {
  107.             restore_error_handler();
  108.         }
  109.         $ids $missingIds;
  110.         $missingIds = array();
  111.         goto begin;
  112.     }
  113.     /**
  114.      * {@inheritdoc}
  115.      */
  116.     protected function doHave($id)
  117.     {
  118.         if ($this->appendOnly && $this->values[$id]) {
  119.             return true;
  120.         }
  121.         set_error_handler($this->includeHandler);
  122.         try {
  123.             $file $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
  124.             list($expiresAt$value) = include $file;
  125.         } catch (\ErrorException $e) {
  126.             return false;
  127.         } finally {
  128.             restore_error_handler();
  129.         }
  130.         if ($this->appendOnly) {
  131.             $now 0;
  132.             $this->values[$id] = $value;
  133.         } else {
  134.             $now time();
  135.         }
  136.         return $now $expiresAt;
  137.     }
  138.     /**
  139.      * {@inheritdoc}
  140.      */
  141.     protected function doSave(array $values$lifetime)
  142.     {
  143.         $ok true;
  144.         $expiry $lifetime time() + $lifetime 'PHP_INT_MAX';
  145.         $allowCompile self::isSupported();
  146.         foreach ($values as $key => $value) {
  147.             unset($this->values[$key]);
  148.             $isStaticValue true;
  149.             if (null === $value) {
  150.                 $value "'N;'";
  151.             } elseif (\is_object($value) || \is_array($value)) {
  152.                 try {
  153.                     $value VarExporter::export($value$isStaticValue);
  154.                 } catch (\Exception $e) {
  155.                     throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.'$key, \is_object($value) ? \get_class($value) : 'array'), 0$e);
  156.                 }
  157.             } elseif (\is_string($value)) {
  158.                 // Wrap "N;" in a closure to not confuse it with an encoded `null`
  159.                 if ('N;' === $value) {
  160.                     $isStaticValue false;
  161.                 }
  162.                 $value var_export($valuetrue);
  163.             } elseif (!\is_scalar($value)) {
  164.                 throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.'$key, \gettype($value)));
  165.             } else {
  166.                 $value var_export($valuetrue);
  167.             }
  168.             if (!$isStaticValue) {
  169.                 $value str_replace("\n""\n    "$value);
  170.                 $value "static function () {\n\n    return {$value};\n\n}";
  171.             }
  172.             $file $this->files[$key] = $this->getFile($keytrue);
  173.             // Since OPcache only compiles files older than the script execution start, set the file's mtime in the past
  174.             $ok $this->write($file"<?php return array({$expiry}{$value});\n"self::$startTime 10) && $ok;
  175.             if ($allowCompile) {
  176.                 @opcache_invalidate($filetrue);
  177.                 @opcache_compile_file($file);
  178.             }
  179.         }
  180.         if (!$ok && !is_writable($this->directory)) {
  181.             throw new CacheException(sprintf('Cache directory is not writable (%s)'$this->directory));
  182.         }
  183.         return $ok;
  184.     }
  185.     /**
  186.      * {@inheritdoc}
  187.      */
  188.     protected function doClear($namespace)
  189.     {
  190.         $this->values = array();
  191.         return $this->doCommonClear($namespace);
  192.     }
  193.     /**
  194.      * {@inheritdoc}
  195.      */
  196.     protected function doDelete(array $ids)
  197.     {
  198.         foreach ($ids as $id) {
  199.             unset($this->values[$id]);
  200.         }
  201.         return $this->doCommonDelete($ids);
  202.     }
  203.     protected function doUnlink($file)
  204.     {
  205.         if (self::isSupported()) {
  206.             @opcache_invalidate($filetrue);
  207.         }
  208.         return @unlink($file);
  209.     }
  210. }