vendor/gregwar/cache/Gregwar/Cache/Cache.php line 362

Open in your IDE?
  1. <?php
  2. namespace Gregwar\Cache;
  3. /**
  4.  * A cache system based on files
  5.  *
  6.  * @author Gregwar <g.passault@gmail.com>
  7.  */
  8. class Cache implements CacheInterface
  9. {
  10.     /**
  11.      * Cache directory
  12.      * @var string
  13.      */
  14.     protected $cacheDirectory;
  15.     /**
  16.      * Use a different directory as actual cache
  17.      * @var string|null
  18.      */
  19.     protected $actualCacheDirectory;
  20.     /**
  21.      * Prefix directories size
  22.      *
  23.      * For instance, if the file is helloworld.txt and the prefix size is
  24.      * 5, the cache file will be: h/e/l/l/o/helloworld.txt
  25.      *
  26.      * This is useful to avoid reaching a too large number of files into the
  27.      * cache system directories
  28.      * @var int
  29.      */
  30.     protected $prefixSize 5;
  31.     /**
  32.      * Directory mode
  33.      *
  34.      * Allows setting of the access mode for the directories created.
  35.      * @var int
  36.      */
  37.     protected $directoryMode 0755;
  38.     /**
  39.      * Constructs the cache system
  40.      *
  41.      * @param string $cacheDirectory the cache directory
  42.      */
  43.     public function __construct($cacheDirectory 'cache')
  44.     {
  45.         $this->cacheDirectory $cacheDirectory;
  46.     }
  47.     /**
  48.      * Sets the cache directory
  49.      *
  50.      * @param string $cacheDirectory the cache directory
  51.      * @return self
  52.      */
  53.     public function setCacheDirectory($cacheDirectory)
  54.     {
  55.         $this->cacheDirectory $cacheDirectory;
  56.         return $this;
  57.     }
  58.     /**
  59.      * Gets the cache directory
  60.      *
  61.      * @return string the cache directory
  62.      */
  63.     public function getCacheDirectory()
  64.     {
  65.         return $this->cacheDirectory;
  66.     }
  67.     /**
  68.      * Sets the actual cache directory
  69.      *
  70.      * @param string|null $actualCacheDirectory the actual cache directory
  71.      * @return self
  72.      */
  73.     public function setActualCacheDirectory($actualCacheDirectory null)
  74.     {
  75.         $this->actualCacheDirectory $actualCacheDirectory;
  76.         return $this;
  77.     }
  78.     /**
  79.      * Returns the actual cache directory
  80.      */
  81.     public function getActualCacheDirectory()
  82.     {
  83.         return $this->actualCacheDirectory ?: $this->cacheDirectory;
  84.     }
  85.     /**
  86.      * Change the prefix size
  87.      *
  88.      * @param int $prefixSize the size of the prefix directories
  89.      * @return self
  90.      */
  91.     public function setPrefixSize($prefixSize)
  92.     {
  93.         $this->prefixSize $prefixSize;
  94.         return $this;
  95.     }
  96.     /**
  97.      * Change the directory mode
  98.      *
  99.      * @param int $directoryMode the directory mode to use
  100.      * @return self
  101.      */
  102.     public function setDirectoryMode($directoryMode)
  103.     {
  104.         if (!$directoryMode) {
  105.             $directoryMode 0755;
  106.         }
  107.         $this->directoryMode $directoryMode;
  108.         return $this;
  109.     }
  110.     /**
  111.      * Creates a directory
  112.      *
  113.      * @param string $directory the target directory
  114.      */
  115.     protected function mkdir($directory)
  116.     {
  117.         if (!is_dir($directory)) {
  118.             @mkdir($directory$this->directoryModetrue);
  119.         }
  120.     }
  121.     /**
  122.      * Gets the cache file name
  123.      *
  124.      * @param string $filename the name of the cache file
  125.      * @param bool $actual get the actual file or the public file
  126.      * @param bool $mkdir a boolean to enable/disable the construction of the
  127.      *        cache file directory
  128.      * @return string
  129.      */
  130.     public function getCacheFile($filename$actual false$mkdir false)
  131.     {
  132.         $path = array();
  133.         // Getting the length of the filename before the extension
  134.         $parts explode('.'$filename);
  135.         $len strlen($parts[0]);
  136.         for ($i=0$i<min($len$this->prefixSize); $i++) {
  137.             $path[] = $filename[$i];
  138.         }
  139.         $path implode('/'$path);
  140.         if ($mkdir) {
  141.             $actualDir $this->getActualCacheDirectory() . '/' $path;
  142.             $this->mkdir($actualDir);
  143.         }
  144.         $path .= '/' $filename;
  145.         if ($actual) {
  146.             return $this->getActualCacheDirectory() . '/' $path;
  147.         } else {
  148.             return $this->getCacheDirectory() . '/' $path;
  149.         }
  150.     }
  151.     /**
  152.      * Checks that the cache conditions are respected
  153.      *
  154.      * @param string $cacheFile the cache file
  155.      * @param array $conditions an array of conditions to check
  156.      * @return bool
  157.      * @throws \Exception
  158.      */
  159.     protected function checkConditions($cacheFile, array $conditions = array())
  160.     {
  161.         // Implicit condition: the cache file should exist
  162.         if (!file_exists($cacheFile)) {
  163.             return false;
  164.         }
  165.         foreach ($conditions as $type => $value) {
  166.             switch ($type) {
  167.             case 'maxage':
  168.             case 'max-age':
  169.                 // Return false if the file is older than $value
  170.                 $age time() - filemtime($cacheFile);
  171.                 if ($age $value) {
  172.                     return false;
  173.                 }
  174.                 break;
  175.             case 'younger-than':
  176.             case 'youngerthan':
  177.                 // Return false if the file is older than the file $value, or the files $value
  178.                 $check = function($filename) use ($cacheFile) {
  179.                     return !file_exists($filename) || filemtime($cacheFile) < filemtime($filename);
  180.                 };
  181.                 if (!is_array($value)) {
  182.                     if (!$this->isRemote($value) && $check($value)) {
  183.                         return false;
  184.                     }
  185.                 } else {
  186.                     foreach ($value as $file) {
  187.                         if (!$this->isRemote($file) && $check($file)) {
  188.                             return false;
  189.                         }
  190.                     }
  191.                 }
  192.                 break;
  193.             default:
  194.                 throw new \Exception('Cache condition '.$type.' not supported');
  195.             }
  196.         }
  197.         return true;
  198.     }
  199.     /**
  200.      * Checks if the target filename exists in the cache and if the conditions
  201.      * are respected
  202.      *
  203.      * @param string $filename the filename
  204.      * @param array $conditions the conditions to respect
  205.      * @return bool
  206.      */
  207.     public function exists($filename, array $conditions = array())
  208.     {
  209.         $cacheFile $this->getCacheFile($filenametrue);
  210.         return $this->checkConditions($cacheFile$conditions);
  211.     }
  212.     /**
  213.      * Alias for exists
  214.      *
  215.      * @param string $filename the filename
  216.      * @param array $conditions the conditions to respect
  217.      * @return bool
  218.      */
  219.     public function check($filename, array $conditions = array())
  220.     {
  221.         return $this->exists($filename$conditions);
  222.     }
  223.     /**
  224.      * Write data in the cache
  225.      *
  226.      * @param string $filename the name of the cache file
  227.      * @param string $contents the contents to store
  228.      * @return self
  229.      */
  230.     public function set($filename$contents '')
  231.     {
  232.         $cacheFile $this->getCacheFile($filenametruetrue);
  233.         file_put_contents($cacheFile$contents\LOCK_EX);
  234.         return $this;
  235.     }
  236.     /**
  237.      * Alias for set()
  238.      *
  239.      * @param string $filename the name of the cache file
  240.      * @param string $contents the contents to store
  241.      * @return self
  242.      */
  243.     public function write($filename$contents '')
  244.     {
  245.         return $this->set($filename$contents);
  246.     }
  247.     /**
  248.      * Get data from the cache
  249.      *
  250.      * @param string $filename the cache file name
  251.      * @param array $conditions
  252.      * @return null|string
  253.      */
  254.     public function get($filename, array $conditions = array())
  255.     {
  256.         if ($this->exists($filename$conditions)) {
  257.             return file_get_contents($this->getCacheFile($filenametrue));
  258.         } else {
  259.             return null;
  260.         }
  261.     }
  262.     /**
  263.      * Is this URL remote?
  264.      *
  265.      * @param string $file
  266.      * @return bool
  267.      */
  268.     protected function isRemote($file)
  269.     {
  270.         if (preg_match('/^([a-z]+):\/\//'$file$match)) {
  271.             return ($match[1] != 'file');
  272.         }
  273.         return false;
  274.     }
  275.     /**
  276.      * Get or create the cache entry
  277.      *
  278.      * @param string $filename the cache file name
  279.      * @param array $conditions an array of conditions about expiration
  280.      * @param \Closure $function the closure to call if the file does not exist
  281.      * @param bool $file returns the cache file or the file contents
  282.      * @param bool $actual returns the actual cache file
  283.      * @return string
  284.      * @throws \InvalidArgumentException
  285.      */
  286.     public function getOrCreate($filename, array $conditions$function$file false$actual false)
  287.     {
  288.         if (!is_callable($function)) {
  289.             throw new \InvalidArgumentException('The argument $function should be callable');
  290.         }
  291.         $cacheFile $this->getCacheFile($filenametruetrue);
  292.         $data null;
  293.         if (!$this->check($filename$conditions)) {
  294.             if(file_exists($cacheFile)) {
  295.                 unlink($cacheFile);
  296.             }
  297.             $data call_user_func($function$cacheFile);
  298.             // Test if the closure wrote the file or if it returned the data
  299.             if (!file_exists($cacheFile)) {
  300.                 $this->set($filename$data);
  301.             } else {
  302.                 $data file_get_contents($cacheFile);
  303.             }
  304.         }
  305.         return $file $this->getCacheFile($filename$actual) : file_get_contents($cacheFile);
  306.     }
  307.     /**
  308.      * Alias to getOrCreate with $file = true
  309.      *
  310.      * @param string $filename the cache file name
  311.      * @param array $conditions an array of conditions about expiration
  312.      * @param \Closure $function the closure to call if the file does not exist
  313.      * @param bool $actual returns the actual cache file
  314.      * @return string
  315.      * @throws \InvalidArgumentException
  316.      */
  317.     public function getOrCreateFile($filename, array $conditions$function$actual false)
  318.     {
  319.         return $this->getOrCreate($filename$conditions$functiontrue$actual);
  320.     }
  321. }