PageRenderTime 62ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/theme/yui_combo.php

https://bitbucket.org/kudutest1/moodlegit
PHP | 288 lines | 184 code | 41 blank | 63 comment | 54 complexity | 9841013607eb4c40cd69788dee8c27c4 MD5 | raw file
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * This file is responsible for serving of yui images
  18. *
  19. * @package moodlecore
  20. * @copyright 2009 Petr Skoda (skodak) {@link http://skodak.org}
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. // disable moodle specific debug messages and any errors in output,
  24. // comment out when debugging or better look into error log!
  25. define('NO_DEBUG_DISPLAY', true);
  26. // we need just the values from config.php and minlib.php
  27. define('ABORT_AFTER_CONFIG', true);
  28. require('../config.php'); // this stops immediately at the beginning of lib/setup.php
  29. // get special url parameters
  30. list($parts, $slasharguments) = combo_params();
  31. if (!$parts) {
  32. combo_not_found();
  33. }
  34. $etag = sha1($parts);
  35. $parts = trim($parts, '&');
  36. // find out what we are serving - only one type per request
  37. $content = '';
  38. if (substr($parts, -3) === '.js') {
  39. $mimetype = 'application/javascript';
  40. } else if (substr($parts, -4) === '.css') {
  41. $mimetype = 'text/css';
  42. } else {
  43. combo_not_found();
  44. }
  45. // if they are requesting a revision that's not -1, and they have supplied an
  46. // If-Modified-Since header, we can send back a 304 Not Modified since the
  47. // content never changes (the rev number is increased any time the content changes)
  48. if (strpos($parts, '/-1/') === false and (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']))) {
  49. $lifetime = 60*60*24*360; // 1 year, we do not change YUI versions often, there are a few custom yui modules
  50. header('HTTP/1.1 304 Not Modified');
  51. header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
  52. header('Cache-Control: public, max-age='.$lifetime);
  53. header('Content-Type: '.$mimetype);
  54. header('Etag: '.$etag);
  55. die;
  56. }
  57. $parts = explode('&', $parts);
  58. $cache = true;
  59. $lastmodified = 0;
  60. foreach ($parts as $part) {
  61. if (empty($part)) {
  62. continue;
  63. }
  64. $filecontent = '';
  65. $part = min_clean_param($part, 'SAFEPATH');
  66. $bits = explode('/', $part);
  67. if (count($bits) < 2) {
  68. $content .= "\n// Wrong combo resource $part!\n";
  69. continue;
  70. }
  71. //debug($bits);
  72. $version = array_shift($bits);
  73. if ($version === 'moodle') {
  74. if (count($bits) <= 3) {
  75. // This is an invalid module load attempt.
  76. $content .= "\n// Incorrect moodle module inclusion. Not enough component information in {$part}.\n";
  77. continue;
  78. }
  79. if (!defined('ABORT_AFTER_CONFIG_CANCEL')) {
  80. define('ABORT_AFTER_CONFIG_CANCEL', true);
  81. define('NO_UPGRADE_CHECK', true);
  82. define('NO_MOODLE_COOKIES', true);
  83. require($CFG->libdir.'/setup.php');
  84. }
  85. $revision = (int)array_shift($bits);
  86. if ($revision === -1) {
  87. // Revision -1 says please don't cache the JS
  88. $cache = false;
  89. }
  90. $frankenstyle = array_shift($bits);
  91. $filename = array_pop($bits);
  92. $modulename = $bits[0];
  93. $dir = get_component_directory($frankenstyle);
  94. // For shifted YUI modules, we need the YUI module name in frankenstyle format.
  95. $frankenstylemodulename = join('-', array($version, $frankenstyle, $modulename));
  96. $frankenstylefilename = preg_replace('/' . $modulename . '/', $frankenstylemodulename, $filename);
  97. // By default, try and use the /yui/build directory.
  98. if ($mimetype == 'text/css') {
  99. // CSS assets are in a slightly different place to the JS.
  100. $contentfile = $dir . '/yui/build/' . $frankenstylemodulename . '/assets/skins/sam/' . $frankenstylefilename;
  101. // Add the path to the bits to handle fallback for non-shifted assets.
  102. $bits[] = 'assets';
  103. $bits[] = 'skins';
  104. $bits[] = 'sam';
  105. } else {
  106. $contentfile = $dir . '/yui/build/' . $frankenstylemodulename . '/' . $frankenstylefilename;
  107. }
  108. // If the shifted versions don't exist, fall back to the non-shifted file.
  109. if (!file_exists($contentfile) or !is_file($contentfile)) {
  110. // We have to revert to the non-minified and non-debug versions.
  111. $filename = preg_replace('/-(min|debug)\./', '.', $filename);
  112. $contentfile = $dir . '/yui/' . join('/', $bits) . '/' . $filename;
  113. }
  114. } else if ($version === '2in3') {
  115. $contentfile = "$CFG->libdir/yuilib/$part";
  116. } else if ($version == 'gallery') {
  117. $contentfile = "$CFG->libdir/yui/$part";
  118. } else {
  119. if ($version != $CFG->yui3version) {
  120. $content .= "\n// Wrong yui version $part!\n";
  121. continue;
  122. }
  123. $contentfile = "$CFG->libdir/yuilib/$part";
  124. }
  125. if (!file_exists($contentfile) or !is_file($contentfile)) {
  126. $location = '$CFG->dirroot'.preg_replace('/^'.preg_quote($CFG->dirroot, '/').'/', '', $contentfile);
  127. $content .= "\n// Combo resource $part ($location) not found!\n";
  128. continue;
  129. }
  130. if (empty($filecontent)) {
  131. $filecontent = file_get_contents($contentfile);
  132. }
  133. $fmodified = filemtime($contentfile);
  134. if ($fmodified > $lastmodified) {
  135. $lastmodified = $fmodified;
  136. }
  137. $relroot = preg_replace('|^http.?://[^/]+|', '', $CFG->wwwroot);
  138. $sep = ($slasharguments ? '/' : '?file=');
  139. if ($mimetype === 'text/css') {
  140. if ($version == 'moodle') {
  141. // Search for all images in the file and replace with an appropriate link to the yui_image.php script
  142. $imagebits = array(
  143. $sep . $version,
  144. $frankenstyle,
  145. $modulename,
  146. array_shift($bits),
  147. '$1.$2'
  148. );
  149. $filecontent = preg_replace('/([a-z0-9_-]+)\.(png|gif)/', $relroot . '/theme/yui_image.php' . implode('/', $imagebits), $filecontent);
  150. } else if ($version == '2in3') {
  151. // First we need to remove relative paths to images. These are used by YUI modules to make use of global assets.
  152. // I've added this as a separate regex so it can be easily removed once
  153. // YUI standardise there CSS methods
  154. $filecontent = preg_replace('#(\.\./\.\./\.\./\.\./assets/skins/sam/)?([a-z0-9_-]+)\.(png|gif)#', '$2.$3', $filecontent);
  155. // search for all images in yui2 CSS and serve them through the yui_image.php script
  156. $filecontent = preg_replace('/([a-z0-9_-]+)\.(png|gif)/', $relroot.'/theme/yui_image.php'.$sep.$CFG->yui2version.'/$1.$2', $filecontent);
  157. } else if ($version == 'gallery') {
  158. // search for all images in gallery module CSS and serve them through the yui_image.php script
  159. $filecontent = preg_replace('/([a-z0-9_-]+)\.(png|gif)/', $relroot.'/theme/yui_image.php'.$sep.$version.'/'.$bits[0].'/'.$bits[1].'/$1.$2', $filecontent);
  160. } else {
  161. // First we need to remove relative paths to images. These are used by YUI modules to make use of global assets.
  162. // I've added this as a separate regex so it can be easily removed once
  163. // YUI standardise there CSS methods
  164. $filecontent = preg_replace('#(\.\./\.\./\.\./\.\./assets/skins/sam/)?([a-z0-9_-]+)\.(png|gif)#', '$2.$3', $filecontent);
  165. // search for all images in yui2 CSS and serve them through the yui_image.php script
  166. $filecontent = preg_replace('/([a-z0-9_-]+)\.(png|gif)/', $relroot.'/theme/yui_image.php'.$sep.$version.'/$1.$2', $filecontent);
  167. }
  168. }
  169. $content .= $filecontent;
  170. }
  171. if ($lastmodified == 0) {
  172. $lastmodified = time();
  173. }
  174. if ($cache) {
  175. combo_send_cached($content, $mimetype, $etag, $lastmodified);
  176. } else {
  177. combo_send_uncached($content, $mimetype);
  178. }
  179. /**
  180. * Send the JavaScript cached
  181. * @param string $content
  182. * @param string $mimetype
  183. * @param string $etag
  184. * @param int $lastmodified
  185. */
  186. function combo_send_cached($content, $mimetype, $etag, $lastmodified) {
  187. $lifetime = 60*60*24*360; // 1 year, we do not change YUI versions often, there are a few custom yui modules
  188. header('Content-Disposition: inline; filename="combo"');
  189. header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT');
  190. header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
  191. header('Pragma: ');
  192. header('Cache-Control: public, max-age='.$lifetime);
  193. header('Accept-Ranges: none');
  194. header('Content-Type: '.$mimetype);
  195. header('Etag: '.$etag);
  196. if (!min_enable_zlib_compression()) {
  197. header('Content-Length: '.strlen($content));
  198. }
  199. echo $content;
  200. die;
  201. }
  202. /**
  203. * Send the JavaScript uncached
  204. * @param string $content
  205. * @param string $mimetype
  206. */
  207. function combo_send_uncached($content, $mimetype) {
  208. header('Content-Disposition: inline; filename="combo"');
  209. header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
  210. header('Expires: '. gmdate('D, d M Y H:i:s', time() + 2) .' GMT');
  211. header('Pragma: ');
  212. header('Accept-Ranges: none');
  213. header('Content-Type: '.$mimetype);
  214. if (!min_enable_zlib_compression()) {
  215. header('Content-Length: '.strlen($content));
  216. }
  217. echo $content;
  218. die;
  219. }
  220. function combo_not_found($message = '') {
  221. header('HTTP/1.0 404 not found');
  222. if ($message) {
  223. echo $message;
  224. } else {
  225. echo 'Combo resource not found, sorry.';
  226. }
  227. die;
  228. }
  229. function combo_params() {
  230. if (isset($_SERVER['QUERY_STRING']) and strpos($_SERVER['QUERY_STRING'], 'file=/') === 0) {
  231. // url rewriting
  232. $slashargument = substr($_SERVER['QUERY_STRING'], 6);
  233. return array($slashargument, true);
  234. } else if (isset($_SERVER['REQUEST_URI']) and strpos($_SERVER['REQUEST_URI'], '?') !== false) {
  235. $parts = explode('?', $_SERVER['REQUEST_URI'], 2);
  236. return array($parts[1], false);
  237. } else if (isset($_SERVER['QUERY_STRING']) and strpos($_SERVER['QUERY_STRING'], '?') !== false) {
  238. // note: buggy or misconfigured IIS does return the query string in REQUEST_URI
  239. return array($_SERVER['QUERY_STRING'], false);
  240. } else if ($slashargument = min_get_slash_argument()) {
  241. $slashargument = ltrim($slashargument, '/');
  242. return array($slashargument, true);
  243. } else {
  244. // unsupported server, sorry!
  245. combo_not_found('Unsupported server - query string can not be determined, try disabling YUI combo loading in admin settings.');
  246. }
  247. }