pquery.cache.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. /**
  3. * pQuery plugin for parsing templates.
  4. *
  5. * @package pQuery
  6. */
  7. /**
  8. * @todo Documentation
  9. * @property string $files
  10. */
  11. class pQueryCache extends pQuery implements pQueryExtension {
  12. const CACHE_FOLDER = 'cache/';
  13. const ADMINISTRATION_FILE = 'administration.php';
  14. static $accepts = array('array' => 'get_modification_dates', 'string' => 'make_array');
  15. /**
  16. * @see pQuery::$variable_alias
  17. * @var string|array
  18. */
  19. static $variable_alias = 'files';
  20. /**
  21. * A list of latest known modification timestamps of all files currently in the cache.
  22. *
  23. * @var array
  24. */
  25. static $admin;
  26. /**
  27. * A list of actual modification timestamps of the current file list.
  28. *
  29. * @var array
  30. */
  31. var $modification_dates;
  32. /**
  33. * Reduced script content.
  34. *
  35. * @var string
  36. */
  37. var $content = '';
  38. /**
  39. * Make a single file into an array.
  40. *
  41. * @param string $file The file to put in an array.
  42. */
  43. function make_array($file) {
  44. return $this->get_modification_dates(array($file));
  45. }
  46. /**
  47. *
  48. */
  49. function get_modification_dates($files) {
  50. // Assert existence of all files
  51. foreach( $files as $file )
  52. file_exists($file) || self::error('File "%s" does not exist.', $file);
  53. $timestamps = array_map('filemtime', $files);
  54. $this->modification_dates = array_combine($files, $timestamps);
  55. return $files;
  56. }
  57. /**
  58. *
  59. *
  60. * @returns bool Whether the file list is in the cache and not updated.
  61. */
  62. function admin_updated() {
  63. self::assert_admin_exists();
  64. foreach( $this->modification_dates as $file => $timestamp )
  65. if( !isset(self::$admin[$file]) || self::$admin[$file] !== $timestamp )
  66. return true;
  67. return false;
  68. }
  69. /**
  70. *
  71. */
  72. function concatenate() {
  73. $this->content = implode("\n", array_map('file_get_contents', $this->files));
  74. return $this;
  75. }
  76. /**
  77. *
  78. */
  79. function filename() {
  80. return str_replace('/', '-', implode('-', $this->files));
  81. }
  82. /**
  83. *
  84. */
  85. function output() {
  86. $last_modified = max($this->modification_dates);
  87. header('Last-Modified: '.date('r', $last_modified));
  88. header('Expires: '.date('r', $last_modified + 60 * 60 * 24 * 365));
  89. header('Cache-Control: private');
  90. method_exists($this, 'set_headers') && $this->set_headers();
  91. if( $admin_updated = $this->admin_updated() || !isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ) {
  92. //echo 'admin updated';
  93. $this->save();
  94. } elseif( !isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ) {
  95. //echo 'hard refresh';
  96. //$this->concatenate();
  97. } elseif( isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ) {
  98. $if_modified_since = strtotime(preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']));
  99. if( $if_modified_since >= $last_modified ) {
  100. //echo 'not modified';
  101. // Not modified
  102. header((php_sapi_name() == 'CGI' ? 'Status:' : 'HTTP/1.0').' 304 Not Modified');
  103. exit;
  104. } else {
  105. //echo 'modified';
  106. }
  107. }
  108. die($this->content);
  109. }
  110. /**
  111. *
  112. */
  113. function save() {
  114. $this->concatenate();
  115. self::assert_cache_folder_exists();
  116. method_exists($this, 'minify') && $this->minify();
  117. file_put_contents(self::CACHE_FOLDER.$this->filename(), $this->content);
  118. self::$admin = array_merge(self::$admin, $this->modification_dates);
  119. self::save_administration();
  120. }
  121. /**
  122. *
  123. */
  124. static function save_administration() {
  125. $handle = fopen(self::CACHE_FOLDER.self::ADMINISTRATION_FILE, 'w');
  126. fwrite($handle, "<?php\n\npQueryCache::\$admin = array(\n");
  127. foreach( self::$admin as $file => $timestamp )
  128. fwrite($handle, "\t'$file' => $timestamp,\n");
  129. fwrite($handle, ");\n\n?>");
  130. fclose($handle);
  131. }
  132. /**
  133. * Assert existence of the administration list by including the administration
  134. * file if it exists, and assigning an empty array otherwise.
  135. */
  136. static function assert_admin_exists() {
  137. if( self::$admin !== null )
  138. return;
  139. $path = self::CACHE_FOLDER.self::ADMINISTRATION_FILE;
  140. if( file_exists($path) )
  141. include_once $path;
  142. else
  143. self::$admin = array();
  144. }
  145. /**
  146. * Assert existence of the cache folder.
  147. */
  148. static function assert_cache_folder_exists() {
  149. is_dir(self::CACHE_FOLDER) || mkdir(self::CACHE_FOLDER, 0777, true);
  150. }
  151. }
  152. /**
  153. * Shortcut constructor for {@link pQueryCache}.
  154. *
  155. * @param array|string $files
  156. * @returns pQueryCache A new cache instance.
  157. */
  158. function _cache($scripts) {
  159. return pQuery::create('cache', $scripts);
  160. }
  161. /*
  162. * Add plugin to pQuery
  163. */
  164. __p::extend('pQueryCache', 'cache');
  165. ?>