MyAsset.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <?php
  2. # idea: serve (tools) package files on the fly...
  3. class MyAsset {
  4. protected $pluginPaths = array();
  5. protected $url;
  6. protected $parseData;
  7. /**
  8. * MyAsset::js()
  9. *
  10. * @param boolean $setHeaders
  11. * @return string Script tags.
  12. */
  13. public function js($setHeaders = true) {
  14. $this->_init();
  15. $res = $this->_parse($_SERVER['QUERY_STRING'], 'js');
  16. if ($setHeaders) {
  17. $this->_headers('js');
  18. }
  19. return $this->_get($res, 'js');
  20. }
  21. /**
  22. * MyAsset::css()
  23. *
  24. * @param boolean $setHeaders
  25. * @return string Style tags.
  26. */
  27. public function css($setHeaders = true) {
  28. $this->_init();
  29. $res = $this->_parse($_SERVER['QUERY_STRING'], 'css');
  30. if ($setHeaders) {
  31. $this->_headers('css');
  32. }
  33. return $this->_get($res, 'css');
  34. }
  35. /**
  36. * MyAsset::_headers()
  37. *
  38. * @param string $type
  39. * @return void
  40. */
  41. public function _headers($type) {
  42. if ($type === 'js') {
  43. $type = 'text/javascript'; //'application/x-javascript';
  44. } elseif ($type === 'css') {
  45. $type = 'text/css';
  46. }
  47. header("Date: " . date("D, j M Y G:i:s ", time()) . 'GMT');
  48. header("Content-Type: " . $type . '; charset=utf-8');
  49. header("Expires: " . gmdate("D, j M Y H:i:s", time() + DAY) . " GMT");
  50. header("Cache-Control: max-age=" . DAY . ", must-revalidate"); // HTTP/1.1
  51. header("Pragma: cache"); // HTTP/1.0
  52. }
  53. /**
  54. * searches, combines, packs, caches and returns scripts
  55. */
  56. public function _get($assets, $type = null) {
  57. $script = array();
  58. foreach ($assets as $plugin => $packages) {
  59. foreach ($packages as $package => $packageFiles) {
  60. $path = $this->_path($plugin, $package, $type);
  61. foreach ($packageFiles as $file) {
  62. $script[] = $this->_read($path . $file);
  63. }
  64. }
  65. }
  66. $script = implode(PHP_EOL, $script);
  67. return $script;
  68. }
  69. public function _init() {
  70. if (empty($_SERVER['QUERY_STRING'])) {
  71. header('HTTP/1.1 404 Not Found');
  72. exit('File Not Found');
  73. }
  74. Configure::write('debug', 0);
  75. }
  76. /**
  77. * Get the content of a single file
  78. */
  79. public function _read($path) {
  80. $path = str_replace('/', DS, $path);
  81. if (strpos($path, '..') !== false) {
  82. trigger_error('MyAsset: Invalid file (' . $path . ') [' . $this->url . ']');
  83. return '';
  84. }
  85. if (!file_exists($path)) {
  86. trigger_error('MyAsset: File not exists (' . $path . ') [' . $this->url . ']');
  87. return '';
  88. }
  89. $data = file_get_contents($path);
  90. //TODO: compress?
  91. return $data;
  92. }
  93. /**
  94. * @deprecated?
  95. */
  96. public function _makeCleanCss($path, $name, $pack = false) {
  97. $data = file_get_contents($path);
  98. if (!$pack) {
  99. $output = " /* file: $name, uncompressed */ " . $data;
  100. return $output;
  101. }
  102. if (!isset($this->Css)) {
  103. App::import('Vendor', 'csspp' . DS . 'csspp');
  104. $this->Css = new csspp();
  105. }
  106. $output = $this->Css->compress($data);
  107. $ratio = 100 - (round(strlen($output) / strlen($data), 3) * 100);
  108. $output = " /* file: $name, ratio: $ratio% */ " . $output;
  109. return $output;
  110. }
  111. /**
  112. * @return string result or bool FALSE on failure
  113. */
  114. public function _readCssCache($path) {
  115. if (file_exists($path)) {
  116. return file_get_contents($path);
  117. }
  118. return false;
  119. }
  120. /**
  121. * @return boolean result
  122. * @deprecated?
  123. */
  124. public function _writeCssCache($path, $content) {
  125. if (!is_dir(dirname($path))) {
  126. if (!mkdir(dirname($path), 0755, true)) {
  127. trigger_error('MyAsset: Cannot create cache folder');
  128. return false;
  129. }
  130. }
  131. $cache = new File($path);
  132. return $cache->write($content);
  133. }
  134. /**
  135. * Get correct path of asset file.
  136. *
  137. * - PluginName.Asset => webroot/asset/ dir in plugin (new)
  138. * - App.Webroot => webroot/ dir
  139. * - App => packages
  140. * - Root => packages
  141. * - PluginName => packages in plugin
  142. *
  143. * @return string Path or bool false on failure.
  144. */
  145. public function _path($plugin, $package, $type = null) {
  146. if ($type !== 'js' && $type !== 'css') {
  147. return false;
  148. }
  149. $pluginPathKey = $plugin;
  150. if ($package === 'Asset') {
  151. $pluginPathKey .= $package;
  152. }
  153. if (isset($this->pluginPaths[$pluginPathKey])) {
  154. return $this->pluginPaths[$pluginPathKey];
  155. }
  156. if ($plugin === 'App' && $package === 'Webroot') {
  157. $pluginPath = WWW_ROOT . $type . DS;
  158. } elseif ($plugin === 'App') {
  159. $pluginPath = APP . 'packages' . DS;
  160. } elseif ($plugin === 'Root') {
  161. $pluginPath = ROOT . DS . 'packages' . DS;
  162. } elseif ($package === 'Asset') {
  163. $pluginPath = App::pluginPath($plugin) . 'webroot' . DS . 'asset' . DS;
  164. $plugin = $plugin . 'Asset';
  165. } else {
  166. $pluginPath = App::pluginPath($plugin) . 'packages' . DS;
  167. }
  168. if (!$pluginPath) {
  169. return false;
  170. }
  171. if ($package === 'Webroot' || $package === 'Asset') {
  172. $packagePath = '';
  173. } else {
  174. $packagePath = strtolower($package) . DS . 'files' . DS;
  175. }
  176. $this->pluginPaths[$pluginPathKey] = $pluginPath;
  177. return $this->pluginPaths[$pluginPathKey] . $packagePath;
  178. }
  179. /**
  180. * Url (example): file=x & file=Tools|y & file=Tools.Jquery|jquery/sub/z
  181. * => x is in webroot/
  182. * => y is in plugins/tools/webroot/
  183. * => z is in plugins/tools/packages/jquery/files/jquery/sub/
  184. */
  185. public function _parse($string, $type = null) {
  186. $parts = explode('&', urldecode($string));
  187. $res = array();
  188. foreach ($parts as $part) {
  189. if (preg_match('|\.\.|', $part)) {
  190. trigger_error('MyAsset: Invalid piece (' . $part . ')');
  191. continue;
  192. }
  193. $plugin = 'App';
  194. $package = 'Webroot';
  195. list($key, $content) = explode('=', $part, 2);
  196. if ($key !== 'file') {
  197. continue;
  198. }
  199. if (strpos($content, '|') !== false) {
  200. list($plugin, $content) = explode('|', $content, 2);
  201. if (strpos($plugin, '.') !== false) {
  202. list($plugin, $package) = explode('.', $plugin, 2);
  203. }
  204. }
  205. if ($type === 'js') {
  206. if (substr($content, -3) !== '.js') {
  207. $content .= '.js';
  208. }
  209. } elseif ($type === 'css') {
  210. if (substr($content, -4) !== '.css') {
  211. $content .= '.css';
  212. }
  213. }
  214. $res[$plugin][$package][] = $content;
  215. }
  216. $this->url = $string;
  217. $this->parseData = $res;
  218. return $res;
  219. }
  220. }
  221. /*
  222. if (preg_match('|\.\.|', $url) || !preg_match('|^ccss/(.+)$|i', $url, $regs)) {
  223. die('Wrong file name.');
  224. }
  225. $filename = 'css/' . $regs[1];
  226. $filepath = CSS . $regs[1];
  227. $cachepath = CACHE . 'css' . DS . str_replace(array('/','\\'), '-', $regs[1]);
  228. if (!file_exists($filepath)) {
  229. die('Wrong file name.');
  230. }
  231. if (file_exists($cachepath)) {
  232. $templateModified = filemtime($filepath);
  233. $cacheModified = filemtime($cachepath);
  234. if ($templateModified > $cacheModified) {
  235. $output = make_clean_css($filepath, $filename);
  236. write_css_cache($cachepath, $output);
  237. } else {
  238. $output = file_get_contents($cachepath);
  239. }
  240. } else {
  241. $output = make_clean_css($filepath, $filename);
  242. write_css_cache($cachepath, $output);
  243. $templateModified = time();
  244. }
  245. header("Date: " . date("D, j M Y G:i:s ", $templateModified) . 'GMT');
  246. header("Content-Type: text/css");
  247. header("Expires: " . gmdate("D, d M Y H:i:s", time() + DAY) . " GMT");
  248. header("Cache-Control: max-age=86400, must-revalidate"); // HTTP/1.1
  249. header("Pragma: cache"); // HTTP/1.0
  250. print $output;
  251. */