PageRenderTime 27ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/cache/storage/file.php

https://github.com/ixpectus/core
PHP | 306 lines | 154 code | 53 blank | 99 comment | 18 complexity | 8027f649f82cd6de58c67a7a4b448c66 MD5 | raw file
  1. <?php
  2. /**
  3. * Fuel
  4. *
  5. * Fuel is a fast, lightweight, community driven PHP5 framework.
  6. *
  7. * @package Fuel
  8. * @version 1.0
  9. * @author Fuel Development Team
  10. * @license MIT License
  11. * @copyright 2010 - 2011 Fuel Development Team
  12. * @link http://fuelphp.com
  13. */
  14. namespace Fuel\Core;
  15. class Cache_Storage_File extends \Cache_Storage_Driver {
  16. /**
  17. * @const string Tag used for opening & closing cache properties
  18. */
  19. const PROPS_TAG = 'Fuel_Cache_Properties';
  20. /**
  21. * @var string File caching basepath
  22. */
  23. protected static $path = '';
  24. /**
  25. * @var driver specific configuration
  26. */
  27. protected $config = array();
  28. // ---------------------------------------------------------------------
  29. public function __construct($identifier, $config)
  30. {
  31. parent::__construct($identifier, $config);
  32. $this->config = isset($config['file']) ? $config['file'] : array();
  33. // check for an expiration override
  34. $this->expiration = $this->_validate_config('expiration', isset($this->config['expiration']) ? $this->config['expiration'] : $this->expiration);
  35. // determine the file cache path
  36. static::$path = !empty($this->config['path']) ? $this->config['path'] : \Config::get('cache_dir', APPPATH.'cache'.DS);
  37. if ( ! is_dir(static::$path) || ! is_writable(static::$path))
  38. {
  39. throw new \Cache_Exception('Cache directory does not exist or is not writable.');
  40. }
  41. }
  42. // ---------------------------------------------------------------------
  43. /**
  44. * Translates a given identifier to a valid path
  45. *
  46. * @param string
  47. * @return string
  48. * @throws Cache_Exception
  49. */
  50. protected function identifier_to_path( $identifier )
  51. {
  52. // replace dots with dashes
  53. $identifier = str_replace('.', DS, $identifier);
  54. return $identifier;
  55. }
  56. // ---------------------------------------------------------------------
  57. /**
  58. * Prepend the cache properties
  59. *
  60. * @return string
  61. */
  62. protected function prep_contents()
  63. {
  64. $properties = array(
  65. 'created' => $this->created,
  66. 'expiration' => $this->expiration,
  67. 'dependencies' => $this->dependencies,
  68. 'content_handler' => $this->content_handler
  69. );
  70. $properties = '{{'.self::PROPS_TAG.'}}'.json_encode($properties).'{{/'.self::PROPS_TAG.'}}';
  71. return $properties . $this->contents;
  72. }
  73. // ---------------------------------------------------------------------
  74. /**
  75. * Remove the prepended cache properties and save them in class properties
  76. *
  77. * @param string
  78. * @throws Cache_Exception
  79. */
  80. protected function unprep_contents($payload)
  81. {
  82. $properties_end = strpos($payload, '{{/'.self::PROPS_TAG.'}}');
  83. if ($properties_end === FALSE)
  84. {
  85. throw new \Cache_Exception('Incorrect formatting');
  86. }
  87. $this->contents = substr($payload, $properties_end + strlen('{{/'.self::PROPS_TAG.'}}'));
  88. $props = substr(substr($payload, 0, $properties_end), strlen('{{'.self::PROPS_TAG.'}}'));
  89. $props = json_decode($props, true);
  90. if ($props === NULL)
  91. {
  92. throw new \Cache_Exception('Properties retrieval failed');
  93. }
  94. $this->created = $props['created'];
  95. $this->expiration = is_null($props['expiration']) ? null : (int) ($props['expiration'] - time());
  96. $this->dependencies = $props['dependencies'];
  97. $this->content_handler = $props['content_handler'];
  98. }
  99. // ---------------------------------------------------------------------
  100. /**
  101. * Check if other caches or files have been changed since cache creation
  102. *
  103. * @param array
  104. * @return bool
  105. */
  106. public function check_dependencies(Array $dependencies)
  107. {
  108. foreach($dependencies as $dep)
  109. {
  110. if (file_exists($file = static::$path.str_replace('.', DS, $dep).'.cache'))
  111. {
  112. $filemtime = filemtime($file);
  113. if ($filemtime === false || $filemtime > $this->created)
  114. return false;
  115. }
  116. elseif (file_exists($dep))
  117. {
  118. $filemtime = filemtime($file);
  119. if ($filemtime === false || $filemtime > $this->created)
  120. return false;
  121. }
  122. else
  123. {
  124. return false;
  125. }
  126. }
  127. return true;
  128. }
  129. // ---------------------------------------------------------------------
  130. /**
  131. * Delete Cache
  132. */
  133. public function delete()
  134. {
  135. $file = static::$path.$this->identifier_to_path($this->identifier).'.cache';
  136. @unlink($file);
  137. $this->reset();
  138. }
  139. // ---------------------------------------------------------------------
  140. /**
  141. * Purge all caches
  142. *
  143. * @param limit purge to subsection
  144. * @return bool
  145. * @throws Cache_Exception
  146. */
  147. public function delete_all($section)
  148. {
  149. $path = rtrim(static::$path, '\\/').DS;
  150. $section = static::identifier_to_path($section);
  151. return \File::delete_dir($path.$section, true, false);
  152. }
  153. // ---------------------------------------------------------------------
  154. /**
  155. * Save a cache, this does the generic pre-processing
  156. *
  157. * @return bool
  158. */
  159. protected function _set()
  160. {
  161. $payload = $this->prep_contents();
  162. $id_path = $this->identifier_to_path($this->identifier);
  163. // create directory if necessary
  164. $subdirs = explode(DS, $id_path);
  165. if (count($subdirs) > 1)
  166. {
  167. array_pop($subdirs);
  168. $test_path = static::$path.implode(DS, $subdirs);
  169. // check if specified subdir exists
  170. if ( ! @is_dir($test_path))
  171. {
  172. // create non existing dir
  173. if ( ! @mkdir($test_path, 0755, true)) return false;
  174. }
  175. }
  176. // write the cache
  177. $file = static::$path.$id_path.'.cache';
  178. $handle = fopen($file, 'c');
  179. if ($handle)
  180. {
  181. // wait for a lock
  182. while( ! flock($handle, LOCK_EX));
  183. // write the session data
  184. fwrite($handle, $payload);
  185. //release the lock
  186. flock($handle, LOCK_UN);
  187. // close the file
  188. fclose($handle);
  189. }
  190. }
  191. // ---------------------------------------------------------------------
  192. /**
  193. * Load a cache, this does the generic post-processing
  194. *
  195. * @return bool
  196. */
  197. protected function _get()
  198. {
  199. $id_path = $this->identifier_to_path( $this->identifier );
  200. $file = static::$path.$id_path.'.cache';
  201. if ( ! file_exists($file))
  202. return false;
  203. $handle = fopen($file, 'r');
  204. if ( ! $handle)
  205. return false;
  206. // wait for a lock
  207. while( ! flock($handle, LOCK_EX));
  208. // read the session data
  209. $payload = fread($handle, filesize($file));
  210. //release the lock
  211. flock($handle, LOCK_UN);
  212. // close the file
  213. fclose($handle);
  214. try
  215. {
  216. $this->unprep_contents($payload);
  217. }
  218. catch(Cache_Exception $e)
  219. {
  220. return false;
  221. }
  222. return true;
  223. }
  224. // ---------------------------------------------------------------------
  225. /**
  226. * validate a driver config value
  227. *
  228. * @param string name of the config variable to validate
  229. * @param mixed value
  230. * @access private
  231. * @return mixed
  232. */
  233. private function _validate_config($name, $value)
  234. {
  235. switch ($name)
  236. {
  237. case 'cache_id':
  238. if (empty($value) or ! is_string($value))
  239. {
  240. $value = 'fuel';
  241. }
  242. break;
  243. case 'expiration':
  244. if (empty($value) or ! is_numeric($value))
  245. {
  246. $value = null;
  247. }
  248. break;
  249. }
  250. return $value;
  251. }
  252. }
  253. /* End of file file.php */