/classes/Head.php

https://github.com/urkle/INQ-Calculators · PHP · 279 lines · 210 code · 21 blank · 48 comment · 37 complexity · 594cf04cb3d5c3d69c9345c6176a691e MD5 · raw file

  1. <?php
  2. /*
  3. * Head.php
  4. *
  5. * Copyright (c) 2011 Edward Rudd <urkle at outoforder.cc>
  6. *
  7. * This file is part of INQ-Calculators.
  8. *
  9. * INQ-Calculators is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Affero General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * INQ-Calculators is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License
  20. * along with INQ-Calculators. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * Description of Head
  24. *
  25. * @author Edward Rudd <urkle at outoforder.cc>
  26. */
  27. class Head {
  28. /** If we should NOT combine this file with others */
  29. const NO_COMBINE = 0x0001;
  30. /** If we should NOT minify this file */
  31. const NO_MINIFY = 0x0002;
  32. /** A standalone preminified file */
  33. const STANDALONE = 0x0003;
  34. const ADD_FIRST = 0x0100;
  35. const ADD_LAST = 0x0200;
  36. const TYPE_CSS = 1;
  37. const TYPE_JS = 3;
  38. const FEAT_COMBINE = 0x01;
  39. const FEAT_MINIFY = 0x02;
  40. const FEAT_DEFAULT = 0x01;
  41. private static $links;
  42. private static $combined;
  43. private static $debug = false;
  44. private static $memcached = false;
  45. private static $features = self::FEAT_DEFAULT;
  46. /**
  47. * Configure what features are enabled (minification, combination)
  48. * @param integer $flags And ored list of Head::FEAT_* flags
  49. */
  50. public static function setFeatures($flags)
  51. {
  52. self::$features = $flags;
  53. }
  54. /**
  55. * Configure the caching in memcached
  56. * @param Memcached $obj The memcached object to use
  57. */
  58. public static function setMemecache(Memcached $obj)
  59. {
  60. self::$memcached = $obj;
  61. }
  62. /**
  63. * If debug mode is enabled, then file combining and minification is not done
  64. */
  65. public static function setDebug($debug = true)
  66. {
  67. self::$debug = $debug;
  68. }
  69. public static function addCSS($link, $flags = Head::ADD_LAST)
  70. {
  71. $data = (object)array('link'=>$link,'flags'=>$flags,'type'=>self::TYPE_CSS);
  72. if ($flags & self::ADD_FIRST) {
  73. array_unshift(self::$links->css, $data);
  74. } else { // The default is add last
  75. array_push(self::$links->css, $data);
  76. }
  77. }
  78. public static function addJS($link, $flags = Head::ADD_LAST)
  79. {
  80. $data = (object)array('link'=>$link,'flags'=>$flags,'type'=>self::TYPE_JS);
  81. if ($flags & self::ADD_FIRST) {
  82. array_unshift(self::$links->js, $data);
  83. } else { // The default is add last
  84. array_push(self::$links->js, $data);
  85. }
  86. }
  87. /**
  88. * Returns all of the processed CSS links
  89. */
  90. public static function CSS()
  91. {
  92. return self::ProcessCSS();
  93. }
  94. /**
  95. * Returns all of the processed JS links
  96. */
  97. public static function JS()
  98. {
  99. return self::ProcessJS();
  100. }
  101. public static function OutputCombined($tag, $modstamp = 0)
  102. {
  103. if (substr($tag,0,3)=='css') {
  104. self::ProcessCSS();
  105. } else {
  106. self::ProcessJS();
  107. }
  108. if (self::$memcached) {
  109. $ret = self::$memcached->get($tag.'-'.$modstamp);
  110. if ($ret) {
  111. echo $ret;
  112. return;
  113. }
  114. ob_start();
  115. }
  116. if (isset(self::$combined[$tag])) {
  117. foreach (self::$combined[$tag] as $_f) {
  118. if ($_f->flags & self::NO_MINIFY || (self::$features & self::FEAT_MINIFY) == 0) {
  119. readfile(WEB_ROOT.DIRECTORY_SEPARATOR.$_f->link);
  120. } else {
  121. if ($_f->type == self::TYPE_JS) {
  122. try {
  123. echo JSMin::minify(
  124. file_get_contents(WEB_ROOT.DIRECTORY_SEPARATOR.$_f->link)
  125. );
  126. } catch(Exception $ex) {
  127. error_log((string)$ex);
  128. }
  129. } elseif ($_f->type == self::TYPE_CSS) {
  130. try {
  131. echo Minify_CSS_Compressor::process(
  132. file_get_contents(WEB_ROOT.DIRECTORY_SEPARATOR.$_f->link)
  133. );
  134. } catch(Exception $ex) {
  135. error_log((string)$ex);
  136. }
  137. }
  138. }
  139. }
  140. }
  141. if (self::$memcached) {
  142. self::$memcached->set($tag.'-'.$modstamp, ob_get_contents());
  143. ob_end_flush();
  144. }
  145. }
  146. /**
  147. * Static initializer to setup the main data structures
  148. */
  149. public static function Init()
  150. {
  151. self::$links = (object)array(
  152. 'js'=>array(),
  153. 'css'=>array(),
  154. );
  155. self::$combined = array();
  156. }
  157. public static function GetVersionLink($file)
  158. {
  159. $real = WEB_ROOT.DIRECTORY_SEPARATOR.$file;
  160. if (file_exists($real)) {
  161. $time = @filemtime($real);
  162. return $file .'?t='.$time;
  163. } else {
  164. return $file;
  165. }
  166. }
  167. private static function getModStamp($file)
  168. {
  169. $real = WEB_ROOT.DIRECTORY_SEPARATOR.$file;
  170. if (file_exists($real)) {
  171. return @filemtime($real);
  172. } else {
  173. return 0;
  174. }
  175. }
  176. private static function ProcessCSS()
  177. {
  178. $ret = array();
  179. $combine = (object)array(
  180. 'files'=>array(),
  181. 'tag'=>'',
  182. 'stamp'=>'',
  183. );
  184. foreach (self::$links->css as $_css) {
  185. if (self::$debug) {
  186. $ret[] = self::GetVersionLink($_css->link);
  187. } elseif ($_css->flags & self::NO_COMBINE || (self::$features & self::FEAT_COMBINE)==0) {
  188. if (!empty($combine->files)) {
  189. $tag = 'css/COMBINED_'.md5($combine->tag);
  190. self::$combined[$tag] = $combine->files;
  191. $ret[] = $tag.'?t='.md5($combine->stamp);
  192. $combine->files = array();
  193. $combine->tag = '';
  194. $combine->last = '';
  195. }
  196. if ($_css->flags & self::NO_MINIFY || (self::$features & self::FEAT_MINIFY)==0) {
  197. $ret[] = self::GetVersionLink($_css->link);
  198. } else {
  199. $tag = 'js/MINIFIED_'.md5($_css->link);
  200. self::$combined[$tag] = array($_css);
  201. $ret[] = $tag.'?t='.self::getModStamp($_css->link);
  202. }
  203. } else {
  204. $combine->tag .= $_css->link.':';
  205. $combine->stamp .= self::getModStamp($_css->link);
  206. $combine->files[] = $_css;
  207. }
  208. }
  209. if (!empty($combine->files)) {
  210. $tag = 'css/COMBINED_'.md5($combine->tag);
  211. self::$combined[$tag] = $combine->files;
  212. $ret[] = $tag.'?t='.md5($combine->stamp);
  213. }
  214. return $ret;
  215. }
  216. private static function ProcessJS()
  217. {
  218. $ret = array();
  219. $combine = (object)array(
  220. 'files'=>array(),
  221. 'tag'=>'',
  222. 'stamp'=>'',
  223. );
  224. foreach (self::$links->js as $_js) {
  225. if (self::$debug) {
  226. $ret[] = self::GetVersionLink($_js->link);
  227. } elseif ($_js->flags & self::NO_COMBINE || (self::$features & self::FEAT_COMBINE)==0) {
  228. if (!empty($combine->files)) {
  229. $tag = 'js/COMBINED_'.md5($combine->tag);
  230. self::$combined[$tag] = $combine->files;
  231. $ret[] = $tag.'?t='.md5($combine->stamp);
  232. $combine->files = array();
  233. $combine->tag = '';
  234. $combine->last = '';
  235. }
  236. if ($_js->flags & self::NO_MINIFY || (self::$features & self::FEAT_MINIFY)==0) {
  237. $ret[] = self::GetVersionLink($_js->link);
  238. } else {
  239. $tag = 'js/MINIFIED_'.md5($_js->link);
  240. self::$combined[$tag] = array($_js);
  241. $ret[] = $tag.'?t='.self::getModStamp($_js->link);
  242. }
  243. } else {
  244. $combine->tag .= $_js->link.':';
  245. $combine->stamp .= self::getModStamp($_js->link);
  246. $combine->files[] = $_js;
  247. }
  248. }
  249. if (!empty($combine->files)) {
  250. $tag = 'js/COMBINED_'.md5($combine->tag);
  251. self::$combined[$tag] = $combine->files;
  252. $ret[] = $tag.'?t='.md5($combine->stamp);
  253. }
  254. return $ret;
  255. }
  256. }
  257. Head::Init();
  258. ?>