PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/www/libs/Zend/Cache/Pattern/CaptureCache.php

https://bitbucket.org/Ppito/kawaiviewmodel2
PHP | 386 lines | 287 code | 32 blank | 67 comment | 22 complexity | a545a242b4bbb3d5dafe1bcad51cca17 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. * @package Zend_Cache
  9. */
  10. namespace Zend\Cache\Pattern;
  11. use Zend\Cache\Exception;
  12. use Zend\Stdlib\ErrorHandler;
  13. /**
  14. * @category Zend
  15. * @package Zend_Cache
  16. * @subpackage Pattern
  17. */
  18. class CaptureCache extends AbstractPattern
  19. {
  20. /**
  21. * Start the cache
  22. *
  23. * @param string $pageId Page identifier
  24. * @return void
  25. */
  26. public function start($pageId = null)
  27. {
  28. if ($pageId === null) {
  29. $pageId = $this->detectPageId();
  30. }
  31. $that = $this;
  32. ob_start(function ($content) use ($that, $pageId) {
  33. $that->set($content, $pageId);
  34. // http://php.net/manual/function.ob-start.php
  35. // -> If output_callback returns FALSE original input is sent to the browser.
  36. return false;
  37. });
  38. ob_implicit_flush(false);
  39. }
  40. /**
  41. * Write content to page identity
  42. *
  43. * @param string $content
  44. * @param null|string $pageId
  45. * @throws Exception\LogicException
  46. */
  47. public function set($content, $pageId = null)
  48. {
  49. $publicDir = $this->getOptions()->getPublicDir();
  50. if ($publicDir === null) {
  51. throw new Exception\LogicException("Option 'public_dir' no set");
  52. }
  53. if ($pageId === null) {
  54. $pageId = $this->detectPageId();
  55. }
  56. $path = $this->pageId2Path($pageId);
  57. $file = $path . \DIRECTORY_SEPARATOR . $this->pageId2Filename($pageId);
  58. $this->createDirectoryStructure($publicDir . \DIRECTORY_SEPARATOR . $path);
  59. $this->putFileContent($publicDir . \DIRECTORY_SEPARATOR . $file, $content);
  60. }
  61. /**
  62. * Get from cache
  63. *
  64. * @param null|string $pageId
  65. * @return bool|string
  66. * @throws Exception\LogicException
  67. * @throws Exception\RuntimeException
  68. */
  69. public function get($pageId = null)
  70. {
  71. $publicDir = $this->getOptions()->getPublicDir();
  72. if ($publicDir === null) {
  73. throw new Exception\LogicException("Option 'public_dir' no set");
  74. }
  75. if ($pageId === null) {
  76. $pageId = $this->detectPageId();
  77. }
  78. $file = $publicDir
  79. . \DIRECTORY_SEPARATOR . $this->pageId2Path($pageId)
  80. . \DIRECTORY_SEPARATOR . $this->pageId2Filename($pageId);
  81. if (file_exists($file)) {
  82. ErrorHandler::start();
  83. $content = file_get_contents($file);
  84. $error = ErrorHandler::stop();
  85. if ($content === false) {
  86. throw new Exception\RuntimeException(
  87. "Failed to read cached pageId '{$pageId}'", 0, $error
  88. );
  89. }
  90. return $content;
  91. }
  92. }
  93. /**
  94. * Checks if a cache with given id exists
  95. *
  96. * @param null|string $pageId
  97. * @throws Exception\LogicException
  98. * @return boolean
  99. */
  100. public function has($pageId = null)
  101. {
  102. $publicDir = $this->getOptions()->getPublicDir();
  103. if ($publicDir === null) {
  104. throw new Exception\LogicException("Option 'public_dir' no set");
  105. }
  106. if ($pageId === null) {
  107. $pageId = $this->detectPageId();
  108. }
  109. $file = $publicDir
  110. . \DIRECTORY_SEPARATOR . $this->pageId2Path($pageId)
  111. . \DIRECTORY_SEPARATOR . $this->pageId2Filename($pageId);
  112. return file_exists($file);
  113. }
  114. /**
  115. * Remove from cache
  116. *
  117. * @param null|string $pageId
  118. * @throws Exception\LogicException
  119. * @throws Exception\RuntimeException
  120. * @return boolean
  121. */
  122. public function remove($pageId = null)
  123. {
  124. $publicDir = $this->getOptions()->getPublicDir();
  125. if ($publicDir === null) {
  126. throw new Exception\LogicException("Option 'public_dir' no set");
  127. }
  128. if ($pageId === null) {
  129. $pageId = $this->detectPageId();
  130. }
  131. $file = $publicDir
  132. . \DIRECTORY_SEPARATOR . $this->pageId2Path($pageId)
  133. . \DIRECTORY_SEPARATOR . $this->pageId2Filename($pageId);
  134. if (file_exists($file)) {
  135. ErrorHandler::start();
  136. $res = unlink($file);
  137. $err = ErrorHandler::stop();
  138. if (!$res) {
  139. throw new Exception\RuntimeException(
  140. "Failed to remove cached pageId '{$pageId}'", 0, $err
  141. );
  142. }
  143. return true;
  144. }
  145. return false;
  146. }
  147. /**
  148. * Clear cached pages matching glob pattern
  149. *
  150. * @param string $pattern
  151. * @throws Exception\LogicException
  152. */
  153. public function clearByGlob($pattern = '**')
  154. {
  155. $publicDir = $this->getOptions()->getPublicDir();
  156. if ($publicDir === null) {
  157. throw new Exception\LogicException("Option 'public_dir' no set");
  158. }
  159. $it = new \GlobIterator(
  160. $publicDir . '/' . $pattern,
  161. \GlobIterator::CURRENT_AS_SELF | \GlobIterator::SKIP_DOTS | \GlobIterator::UNIX_PATHS
  162. );
  163. foreach ($it as $pathname => $entry) {
  164. if ($entry->isFile()) {
  165. unlink($pathname);
  166. }
  167. }
  168. }
  169. /**
  170. * Determine the page to save from the request
  171. *
  172. * @throws Exception\RuntimeException
  173. * @return string
  174. */
  175. protected function detectPageId()
  176. {
  177. if (!isset($_SERVER['REQUEST_URI'])) {
  178. throw new Exception\RuntimeException("Can't auto-detect current page identity");
  179. }
  180. return $_SERVER['REQUEST_URI'];
  181. }
  182. /**
  183. * Get filename for page id
  184. *
  185. * @param string $pageId
  186. * @return string
  187. */
  188. protected function pageId2Filename($pageId)
  189. {
  190. if (substr($pageId, -1) === '/') {
  191. return $this->getOptions()->getIndexFilename();
  192. }
  193. return basename($pageId);
  194. }
  195. /**
  196. * Get path for page id
  197. *
  198. * @param string $pageId
  199. * @return string
  200. */
  201. protected function pageId2Path($pageId)
  202. {
  203. if (substr($pageId, -1) == '/') {
  204. $path = rtrim($pageId, '/');
  205. } else {
  206. $path = dirname($pageId);
  207. }
  208. // convert requested "/" to the valid local directory separator
  209. if ('/' != \DIRECTORY_SEPARATOR) {
  210. $path = str_replace('/', \DIRECTORY_SEPARATOR, $path);
  211. }
  212. return $path;
  213. }
  214. /**
  215. * Write content to a file
  216. *
  217. * @param string $file File complete path
  218. * @param string $data Data to write
  219. * @return void
  220. * @throws Exception\RuntimeException
  221. */
  222. protected function putFileContent($file, $data)
  223. {
  224. $options = $this->getOptions();
  225. $locking = $options->getFileLocking();
  226. $perm = $options->getFilePermission();
  227. $umask = $options->getUmask();
  228. if ($umask !== false && $perm !== false) {
  229. $perm = $perm & ~$umask;
  230. }
  231. ErrorHandler::start();
  232. $umask = ($umask !== false) ? umask($umask) : false;
  233. $rs = file_put_contents($file, $data, $locking ? \LOCK_EX : 0);
  234. if ($umask) {
  235. umask($umask);
  236. }
  237. if ($rs === false) {
  238. $err = ErrorHandler::stop();
  239. throw new Exception\RuntimeException(
  240. "Error writing file '{$file}'", 0, $err
  241. );
  242. }
  243. if ($perm !== false && !chmod($file, $perm)) {
  244. $oct = decoct($perm);
  245. $err = ErrorHandler::stop();
  246. throw new Exception\RuntimeException("chmod('{$file}', 0{$oct}) failed", 0, $err);
  247. }
  248. ErrorHandler::stop();
  249. }
  250. /**
  251. * Creates directory if not already done.
  252. *
  253. * @param string $pathname
  254. * @return void
  255. * @throws Exception\RuntimeException
  256. */
  257. protected function createDirectoryStructure($pathname)
  258. {
  259. // Directory structure already exists
  260. if (file_exists($pathname)) {
  261. return;
  262. }
  263. $options = $this->getOptions();
  264. $perm = $options->getDirPermission();
  265. $umask = $options->getUmask();
  266. if ($umask !== false && $perm !== false) {
  267. $perm = $perm & ~$umask;
  268. }
  269. ErrorHandler::start();
  270. if ($perm === false) {
  271. // build-in mkdir function is enough
  272. $umask = ($umask !== false) ? umask($umask) : false;
  273. $res = mkdir($pathname, ($perm !== false) ? $perm : 0777, true);
  274. if ($umask !== false) {
  275. umask($umask);
  276. }
  277. if (!$res) {
  278. $oct = ($perm === false) ? '777' : decoct($perm);
  279. $err = ErrorHandler::stop();
  280. throw new Exception\RuntimeException(
  281. "mkdir('{$pathname}', 0{$oct}, true) failed", 0, $err
  282. );
  283. }
  284. if ($perm !== false && !chmod($pathname, $perm)) {
  285. $oct = decoct($perm);
  286. $err = ErrorHandler::stop();
  287. throw new Exception\RuntimeException(
  288. "chmod('{$pathname}', 0{$oct}) failed", 0, $err
  289. );
  290. }
  291. } else {
  292. // build-in mkdir function sets permission together with current umask
  293. // which doesn't work well on multo threaded webservers
  294. // -> create directories one by one and set permissions
  295. // find existing path and missing path parts
  296. $parts = array();
  297. $path = $pathname;
  298. while (!file_exists($path)) {
  299. array_unshift($parts, basename($path));
  300. $nextPath = dirname($path);
  301. if ($nextPath === $path) {
  302. break;
  303. }
  304. $path = $nextPath;
  305. }
  306. // make all missing path parts
  307. foreach ($parts as $part) {
  308. $path.= \DIRECTORY_SEPARATOR . $part;
  309. // create a single directory, set and reset umask immediately
  310. $umask = ($umask !== false) ? umask($umask) : false;
  311. $res = mkdir($path, ($perm === false) ? 0777 : $perm, false);
  312. if ($umask !== false) {
  313. umask($umask);
  314. }
  315. if (!$res) {
  316. $oct = ($perm === false) ? '777' : decoct($perm);
  317. $err = ErrorHandler::stop();
  318. throw new Exception\RuntimeException(
  319. "mkdir('{$path}', 0{$oct}, false) failed"
  320. );
  321. }
  322. if ($perm !== false && !chmod($path, $perm)) {
  323. $oct = decoct($perm);
  324. $err = ErrorHandler::stop();
  325. throw new Exception\RuntimeException(
  326. "chmod('{$path}', 0{$oct}) failed"
  327. );
  328. }
  329. }
  330. }
  331. ErrorHandler::stop();
  332. }
  333. }