Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
/theme/ -> jquery.php (source)
   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  /**
  18   * jQuery serving script.
  19   *
  20   * Do not include jQuery scripts or CSS directly, always use
  21   * $PAGE->requires->jquery() or $PAGE->requires->jquery_plugin('xx', 'yy').
  22   *
  23   * @package    core
  24   * @copyright  2013 Petr Skoda  {@link http://skodak.org}
  25   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26   */
  27  
  28  // Disable moodle specific debug messages and any errors in output,
  29  // comment out when debugging or better look into error log!
  30  define('NO_DEBUG_DISPLAY', true);
  31  
  32  // We need just the values from config.php and minlib.php.
  33  define('ABORT_AFTER_CONFIG', true);
  34  require('../config.php'); // This stops immediately at the beginning of lib/setup.php.
  35  
  36  if ($slashargument = min_get_slash_argument()) {
  37      $path = ltrim($slashargument, '/');
  38  } else {
  39      $path = min_optional_param('file', '', 'SAFEPATH');
  40      $path = ltrim($path, '/');
  41  }
  42  
  43  if (strpos($path, '/') === false) {
  44      jquery_file_not_found();
  45  }
  46  
  47  list($component, $path) = explode('/', $path, 2);
  48  
  49  if (empty($path) or empty($component)) {
  50      jquery_file_not_found();
  51  }
  52  
  53  // Find the jQuery dir for this component.
  54  if ($component === 'core') {
  55      $componentdir = "$CFG->dirroot/lib";
  56  
  57  } else if (strpos($component, 'theme_')) {
  58      if (!empty($CFG->themedir)) {
  59          $componentdir = "$CFG->themedir/$component";
  60      } else {
  61          $componentdir = "$CFG->dirroot/theme/$component";
  62      }
  63  
  64  } else {
  65      $componentdir = core_component::get_component_directory($component);
  66  }
  67  
  68  if (!file_exists($componentdir) or !file_exists("$componentdir/jquery/plugins.php")) {
  69      jquery_file_not_found();
  70  }
  71  
  72  $file = realpath("$componentdir/jquery/$path");
  73  
  74  if (!$file or is_dir($file)) {
  75      jquery_file_not_found();
  76  }
  77  
  78  $etag = sha1("$component/$path");
  79  // 90 days only - based on Moodle point release cadence being every 3 months.
  80  $lifetime = 60 * 60 * 24 * 90;
  81  $pathinfo = pathinfo($path);
  82  
  83  if (empty($pathinfo['extension'])) {
  84      jquery_file_not_found();
  85  }
  86  
  87  $filename = $pathinfo['filename'].'.'.$pathinfo['extension'];
  88  
  89  switch($pathinfo['extension']) {
  90      case 'gif'  : $mimetype = 'image/gif';
  91          break;
  92      case 'png'  : $mimetype = 'image/png';
  93          break;
  94      case 'jpg'  : $mimetype = 'image/jpeg';
  95          break;
  96      case 'jpeg' : $mimetype = 'image/jpeg';
  97          break;
  98      case 'ico'  : $mimetype = 'image/vnd.microsoft.icon';
  99          break;
 100      case 'svg'  : $mimetype = 'image/svg+xml';
 101          break;
 102      case 'js'   : $mimetype = 'application/javascript';
 103          break;
 104      case 'css'  : $mimetype = 'text/css';
 105          break;
 106      case 'php'  : jquery_file_not_found();
 107          break;
 108      default     : $mimetype = 'document/unknown';
 109  }
 110  
 111  if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
 112      // We do not actually need to verify the etag value because these files
 113      // never change, devs need to change file names on update!
 114      header('HTTP/1.1 304 Not Modified');
 115      header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
 116      header('Cache-Control: public, max-age='.$lifetime);
 117      header('Content-Type: '.$mimetype);
 118      header('Etag: "'.$etag.'"');
 119      die;
 120  }
 121  
 122  require_once("$CFG->dirroot/lib/xsendfilelib.php");
 123  
 124  header('Etag: "'.$etag.'"');
 125  header('Content-Disposition: inline; filename="'.$filename.'"');
 126  header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($file)) .' GMT');
 127  header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
 128  header('Pragma: ');
 129  header('Cache-Control: public, max-age='.$lifetime.', immutable');
 130  header('Accept-Ranges: none');
 131  header('Content-Type: '.$mimetype);
 132  
 133  if (xsendfile($file)) {
 134      die;
 135  }
 136  
 137  if ($mimetype === 'text/css' or $mimetype === 'application/javascript') {
 138      if (!min_enable_zlib_compression()) {
 139          header('Content-Length: '.filesize($file));
 140      }
 141  } else {
 142      // No need to compress images.
 143      header('Content-Length: '.filesize($file));
 144  }
 145  
 146  readfile($file);
 147  die;
 148  
 149  
 150  
 151  function jquery_file_not_found() {
 152      // Note: we can not disclose the exact file path here, sorry.
 153      header('HTTP/1.0 404 not found');
 154      die('File was not found, sorry.');
 155  }