PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/theme/javascript.php

https://github.com/tcubansk/moodle
PHP | 191 lines | 112 code | 32 blank | 47 comment | 15 complexity | 4a12a9f61950130c06aa1df99e9e04f9 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 the one huge CSS of each theme.
  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. $themename = min_optional_param('theme', 'standard', 'SAFEDIR');
  30. $rev = min_optional_param('rev', 0, 'INT');
  31. $type = min_optional_param('type', 'head', 'RAW');
  32. if ($type !== 'head' and $type !== 'footer') {
  33. header('HTTP/1.0 404 not found');
  34. die('Theme was not found, sorry.');
  35. }
  36. if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
  37. // exists
  38. } else if (!empty($CFG->themedir) and file_exists("$CFG->themedir/$themename/config.php")) {
  39. // exists
  40. } else {
  41. header('HTTP/1.0 404 not found');
  42. die('Theme was not found, sorry.');
  43. }
  44. $candidate = "$CFG->cachedir/theme/$themename/javascript_$type.js";
  45. if ($rev > -1 and file_exists($candidate)) {
  46. if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
  47. // we do not actually need to verify the etag value because our files
  48. // never change in cache because we increment the rev parameter
  49. $lifetime = 60*60*24*30; // 30 days
  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: max-age='.$lifetime);
  53. header('Content-Type: application/javascript; charset=utf-8');
  54. die;
  55. }
  56. send_cached_js($candidate, $rev);
  57. }
  58. //=================================================================================
  59. // ok, now we need to start normal moodle script, we need to load all libs and $DB
  60. define('ABORT_AFTER_CONFIG_CANCEL', true);
  61. define('NO_MOODLE_COOKIES', true); // Session not used here
  62. define('NO_UPGRADE_CHECK', true); // Ignore upgrade check
  63. require("$CFG->dirroot/lib/setup.php");
  64. // setup include path
  65. set_include_path($CFG->libdir . '/minify/lib' . PATH_SEPARATOR . get_include_path());
  66. require_once('Minify.php');
  67. $theme = theme_config::load($themename);
  68. if ($rev > -1) {
  69. // note: cache reset might have purged our cache dir structure,
  70. // make sure we do not use stale file stat cache in the next check_dir_exists()
  71. clearstatcache();
  72. check_dir_exists(dirname($candidate));
  73. $fp = fopen($candidate, 'w');
  74. fwrite($fp, minify($theme->javascript_files($type)));
  75. fclose($fp);
  76. send_cached_js($candidate);
  77. } else {
  78. send_uncached_js($theme->javascript_content($type));
  79. }
  80. //=================================================================================
  81. //=== utility functions ==
  82. // we are not using filelib because we need to fine tune all header
  83. // parameters to get the best performance.
  84. function send_cached_js($jspath) {
  85. global $CFG;
  86. require("$CFG->dirroot/lib/xsendfilelib.php");
  87. $lifetime = 60*60*24*30; // 30 days
  88. header('Content-Disposition: inline; filename="javascript.php"');
  89. header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($jspath)) .' GMT');
  90. header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
  91. header('Pragma: ');
  92. header('Cache-Control: max-age='.$lifetime);
  93. header('Accept-Ranges: none');
  94. header('Content-Type: application/javascript; charset=utf-8');
  95. if (xsendfile($jspath)) {
  96. die;
  97. }
  98. if (!min_enable_zlib_compression()) {
  99. header('Content-Length: '.filesize($jspath));
  100. }
  101. readfile($jspath);
  102. die;
  103. }
  104. function send_uncached_js($js) {
  105. header('Content-Disposition: inline; filename="javascript.php"');
  106. header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
  107. header('Expires: '. gmdate('D, d M Y H:i:s', time() + 2) .' GMT');
  108. header('Pragma: ');
  109. header('Accept-Ranges: none');
  110. header('Content-Type: application/javascript; charset=utf-8');
  111. header('Content-Length: '.strlen($js));
  112. echo $js;
  113. die;
  114. }
  115. function minify($files) {
  116. if (empty($files)) {
  117. return '';
  118. }
  119. if (0 === stripos(PHP_OS, 'win')) {
  120. Minify::setDocRoot(); // IIS may need help
  121. }
  122. // disable all caching, we do it in moodle
  123. Minify::setCache(null, false);
  124. $options = array(
  125. 'bubbleCssImports' => false,
  126. // Don't gzip content we just want text for storage
  127. 'encodeOutput' => false,
  128. // Maximum age to cache, not used but required
  129. 'maxAge' => 1800,
  130. // The files to minify
  131. 'files' => $files,
  132. // Turn orr URI rewriting
  133. 'rewriteCssUris' => false,
  134. // This returns the CSS rather than echoing it for display
  135. 'quiet' => true
  136. );
  137. $error = 'unknown';
  138. try {
  139. $result = Minify::serve('Files', $options);
  140. if ($result['success']) {
  141. return $result['content'];
  142. }
  143. } catch (Exception $e) {
  144. $error = $e->getMessage();
  145. $error = str_replace("\r", ' ', $error);
  146. $error = str_replace("\n", ' ', $error);
  147. }
  148. // minification failed - try to inform the theme developer and include the non-minified version
  149. $js = <<<EOD
  150. try {console.log('Error: Minimisation of theme javascript failed!');} catch (e) {}
  151. // Error: $error
  152. // Problem detected during javascript minimisation, please review the following code
  153. // =================================================================================
  154. EOD;
  155. foreach ($files as $jsfile) {
  156. $js .= file_get_contents($jsfile)."\n";
  157. }
  158. return $js;
  159. }