[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 * This file is responsible for serving of yui Javascript and CSS 19 * 20 * @package core 21 * @copyright 2009 Petr Skoda (skodak) {@link http://skodak.org} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 26 // disable moodle specific debug messages and any errors in output, 27 // comment out when debugging or better look into error log! 28 define('NO_DEBUG_DISPLAY', true); 29 30 // we need just the values from config.php and minlib.php 31 define('ABORT_AFTER_CONFIG', true); 32 require('../config.php'); // this stops immediately at the beginning of lib/setup.php 33 34 // get special url parameters 35 36 list($parts, $slasharguments) = combo_params(); 37 if (!$parts) { 38 combo_not_found(); 39 } 40 41 $etag = sha1($parts); 42 $parts = trim($parts, '&'); 43 44 // find out what we are serving - only one type per request 45 $content = ''; 46 if (substr($parts, -3) === '.js') { 47 $mimetype = 'application/javascript'; 48 } else if (substr($parts, -4) === '.css') { 49 $mimetype = 'text/css'; 50 } else { 51 combo_not_found(); 52 } 53 54 // if they are requesting a revision that's not -1, and they have supplied an 55 // If-Modified-Since header, we can send back a 304 Not Modified since the 56 // content never changes (the rev number is increased any time the content changes) 57 if (strpos($parts, '/-1/') === false and (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']))) { 58 $lifetime = 60*60*24*360; // 1 year, we do not change YUI versions often, there are a few custom yui modules 59 header('HTTP/1.1 304 Not Modified'); 60 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 61 header('Cache-Control: public, max-age='.$lifetime); 62 header('Content-Type: '.$mimetype); 63 header('Etag: "'.$etag.'"'); 64 die; 65 } 66 67 $parts = explode('&', $parts); 68 $cache = true; 69 $lastmodified = 0; 70 71 while (count($parts)) { 72 $part = array_shift($parts); 73 if (empty($part)) { 74 continue; 75 } 76 $filecontent = ''; 77 $part = min_clean_param($part, 'SAFEPATH'); 78 $bits = explode('/', $part); 79 if (count($bits) < 2) { 80 $content .= "\n// Wrong combo resource $part!\n"; 81 continue; 82 } 83 84 $version = array_shift($bits); 85 if ($version === 'rollup') { 86 $yuipatchedversion = explode('_', array_shift($bits)); 87 $revision = $yuipatchedversion[0]; 88 $rollupname = array_shift($bits); 89 90 if (strpos($rollupname, 'yui-moodlesimple') !== false) { 91 if (substr($rollupname, -3) === '.js') { 92 // Determine which version of this rollup should be used. 93 $filesuffix = '.js'; 94 preg_match('/(-(debug|min))?\.js/', $rollupname, $matches); 95 if (isset($matches[1])) { 96 $filesuffix = $matches[0]; 97 } 98 99 $type = 'js'; 100 } else if (substr($rollupname, -4) === '.css') { 101 $type = 'css'; 102 } else { 103 continue; 104 } 105 106 // Allow support for revisions on YUI between official releases. 107 // We can just discard the subrevision since it is only used to invalidate the browser cache. 108 $yuipatchedversion = explode('_', $revision); 109 $yuiversion = $yuipatchedversion[0]; 110 111 $yuimodules = array( 112 'yui', 113 'oop', 114 'event-custom-base', 115 'dom-core', 116 'dom-base', 117 'color-base', 118 'dom-style', 119 'selector-native', 120 'selector', 121 'node-core', 122 'node-base', 123 'event-base', 124 'event-base-ie', 125 'pluginhost-base', 126 'pluginhost-config', 127 'event-delegate', 128 'node-event-delegate', 129 'node-pluginhost', 130 'dom-screen', 131 'node-screen', 132 'node-style', 133 'querystring-stringify-simple', 134 'io-base', 135 'json-parse', 136 'transition', 137 'selector-css2', 138 'selector-css3', 139 'dom-style-ie', 140 141 // Some extras we use everywhere. 142 'escape', 143 144 'attribute-core', 145 'event-custom-complex', 146 'base-core', 147 'attribute-base', 148 'attribute-extras', 149 'attribute-observable', 150 'base-observable', 151 'base-base', 152 'base-pluginhost', 153 'base-build', 154 'event-synthetic', 155 156 'attribute-complex', 157 'event-mouseenter', 158 'event-key', 159 'event-outside', 160 'event-focus', 161 'classnamemanager', 162 'widget-base', 163 'widget-htmlparser', 164 'widget-skin', 165 'widget-uievents', 166 'widget-stdmod', 167 'widget-position', 168 'widget-position-align', 169 'widget-stack', 170 'widget-position-constrain', 171 'overlay', 172 173 'widget-autohide', 174 'button-core', 175 'button-plugin', 176 'widget-buttons', 177 'widget-modality', 178 'panel', 179 'yui-throttle', 180 'dd-ddm-base', 181 'dd-drag', 182 'dd-plugin', 183 184 // Cache is used by moodle-core-tooltip which we include everywhere. 185 'cache-base', 186 ); 187 188 // We need to add these new parts to the beginning of the $parts list, not the end. 189 if ($type === 'js') { 190 $newparts = array(); 191 foreach ($yuimodules as $module) { 192 $newparts[] = $yuiversion . '/' . $module . '/' . $module . $filesuffix; 193 } 194 $newparts[] = 'yuiuseall/yuiuseall'; 195 $parts = array_merge($newparts, $parts); 196 } else { 197 $newparts = array(); 198 foreach ($yuimodules as $module) { 199 $candidate = $yuiversion . '/' . $module . '/assets/skins/sam/' . $module . '.css'; 200 if (!file_exists("$CFG->libdir/yuilib/$candidate")) { 201 continue; 202 } 203 $newparts[] = $candidate; 204 } 205 if ($newparts) { 206 $parts = array_merge($newparts, $parts); 207 } 208 } 209 } 210 211 // Handle the mcore rollup. 212 if (strpos($rollupname, 'mcore') !== false) { 213 $yuimodules = array( 214 'core/tooltip/tooltip', 215 'core/popuphelp/popuphelp', 216 'core/widget-focusafterclose/widget-focusafterclose', 217 'core/dock/dock-loader', 218 'core/notification/notification-dialogue', 219 ); 220 221 // Determine which version of this rollup should be used. 222 $filesuffix = '.js'; 223 preg_match('/(-(debug|min))?\.js/', $rollupname, $matches); 224 if (isset($matches[1])) { 225 $filesuffix = $matches[0]; 226 } 227 228 // We need to add these new parts to the beginning of the $parts list, not the end. 229 $newparts = array(); 230 foreach ($yuimodules as $module) { 231 $newparts[] = 'm/' . $revision . '/' . $module . $filesuffix; 232 } 233 $parts = array_merge($newparts, $parts); 234 } 235 continue; 236 } 237 if ($version === 'm') { 238 $version = 'moodle'; 239 } 240 if ($version === 'moodle') { 241 if (count($bits) <= 3) { 242 // This is an invalid module load attempt. 243 $content .= "\n// Incorrect moodle module inclusion. Not enough component information in {$part}.\n"; 244 continue; 245 } 246 $revision = (int)array_shift($bits); 247 if ($revision === -1) { 248 // Revision -1 says please don't cache the JS 249 $cache = false; 250 } 251 $frankenstyle = array_shift($bits); 252 $filename = array_pop($bits); 253 $modulename = $bits[0]; 254 $dir = core_component::get_component_directory($frankenstyle); 255 256 // For shifted YUI modules, we need the YUI module name in frankenstyle format. 257 $frankenstylemodulename = join('-', array($version, $frankenstyle, $modulename)); 258 $frankenstylefilename = preg_replace('/' . $modulename . '/', $frankenstylemodulename, $filename); 259 260 // Submodules are stored in a directory with the full submodule name. 261 // We need to remove the -debug.js, -min.js, and .js from the file name to calculate that directory name. 262 $frankenstyledirectoryname = str_replace(array('-min.js', '-debug.js', '.js', '.css'), '', $frankenstylefilename); 263 264 // By default, try and use the /yui/build directory. 265 $contentfile = $dir . '/yui/build/' . $frankenstyledirectoryname; 266 if ($mimetype == 'text/css') { 267 // CSS assets are in a slightly different place to the JS. 268 $contentfile = $contentfile . '/assets/skins/sam/' . $frankenstylefilename; 269 270 // Add the path to the bits to handle fallback for non-shifted assets. 271 $bits[] = 'assets'; 272 $bits[] = 'skins'; 273 $bits[] = 'sam'; 274 } else { 275 $contentfile = $contentfile . '/' . $frankenstylefilename; 276 } 277 278 // If the shifted versions don't exist, fall back to the non-shifted file. 279 if (!file_exists($contentfile) or !is_file($contentfile)) { 280 // We have to revert to the non-minified and non-debug versions. 281 $filename = preg_replace('/-(min|debug)\./', '.', $filename); 282 $contentfile = $dir . '/yui/' . join('/', $bits) . '/' . $filename; 283 } 284 } else if ($version === '2in3') { 285 $contentfile = "$CFG->libdir/yuilib/$part"; 286 287 } else if ($version == 'gallery') { 288 if (count($bits) <= 2) { 289 // This is an invalid module load attempt. 290 $content .= "\n// Incorrect moodle module inclusion. Not enough component information in {$part}.\n"; 291 continue; 292 } 293 $revision = (int)array_shift($bits); 294 if ($revision === -1) { 295 // Revision -1 says please don't cache the JS 296 $cache = false; 297 } 298 $contentfile = "$CFG->libdir/yuilib/gallery/" . join('/', $bits); 299 300 } else if ($version == 'yuiuseall') { 301 // Create global Y that is available in global scope, 302 // this is the trick behind original SimpleYUI. 303 $filecontent = "var Y = YUI().use('*');"; 304 305 } else { 306 // Allow support for revisions on YUI between official releases. 307 // We can just discard the subrevision since it is only used to invalidate the browser cache. 308 $yuipatchedversion = explode('_', $version); 309 $yuiversion = $yuipatchedversion[0]; 310 if ($yuiversion != $CFG->yui3version) { 311 $content .= "\n// Wrong yui version $part!\n"; 312 continue; 313 } 314 $newpart = explode('/', $part); 315 $newpart[0] = $yuiversion; 316 $part = implode('/', $newpart); 317 $contentfile = "$CFG->libdir/yuilib/$part"; 318 } 319 if (!file_exists($contentfile) or !is_file($contentfile)) { 320 $location = '$CFG->dirroot'.preg_replace('/^'.preg_quote($CFG->dirroot, '/').'/', '', $contentfile); 321 $content .= "\n// Combo resource $part ($location) not found!\n"; 322 continue; 323 } 324 325 if (empty($filecontent)) { 326 $filecontent = file_get_contents($contentfile); 327 } 328 $fmodified = filemtime($contentfile); 329 if ($fmodified > $lastmodified) { 330 $lastmodified = $fmodified; 331 } 332 333 $relroot = preg_replace('|^http.?://[^/]+|', '', $CFG->wwwroot); 334 $sep = ($slasharguments ? '/' : '?file='); 335 336 if ($mimetype === 'text/css') { 337 if ($version == 'moodle') { 338 // Search for all images in the file and replace with an appropriate link to the yui_image.php script 339 $imagebits = array( 340 $sep . $version, 341 $frankenstyle, 342 $modulename, 343 array_shift($bits), 344 '$1.$2' 345 ); 346 347 $filecontent = preg_replace('/([a-z0-9_-]+)\.(png|gif)/', $relroot . '/theme/yui_image.php' . implode('/', $imagebits), $filecontent); 348 } else if ($version == '2in3') { 349 // First we need to remove relative paths to images. These are used by YUI modules to make use of global assets. 350 // I've added this as a separate regex so it can be easily removed once 351 // YUI standardise there CSS methods 352 $filecontent = preg_replace('#(\.\./\.\./\.\./\.\./assets/skins/sam/)?([a-z0-9_-]+)\.(png|gif)#', '$2.$3', $filecontent); 353 354 // search for all images in yui2 CSS and serve them through the yui_image.php script 355 $filecontent = preg_replace('/([a-z0-9_-]+)\.(png|gif)/', $relroot.'/theme/yui_image.php'.$sep.$CFG->yui2version.'/$1.$2', $filecontent); 356 357 } else if ($version == 'gallery') { 358 // Replace any references to the CDN with a relative link. 359 $filecontent = preg_replace('#(' . preg_quote('http://yui.yahooapis.com/') . '(gallery-[^/]*/))#', '../../../../', $filecontent); 360 361 // Replace all relative image links with the a link to yui_image.php. 362 $filecontent = preg_replace('#(' . preg_quote('../../../../') . ')(gallery-[^/]*/assets/skins/sam/[a-z0-9_-]+)\.(png|gif)#', 363 $relroot . '/theme/yui_image.php' . $sep . '/gallery/' . $revision . '/$2.$3', $filecontent); 364 365 } else { 366 // First we need to remove relative paths to images. These are used by YUI modules to make use of global assets. 367 // I've added this as a separate regex so it can be easily removed once 368 // YUI standardise there CSS methods 369 $filecontent = preg_replace('#(\.\./\.\./\.\./\.\./assets/skins/sam/)?([a-z0-9_-]+)\.(png|gif)#', '$2.$3', $filecontent); 370 371 // search for all images in yui2 CSS and serve them through the yui_image.php script 372 $filecontent = preg_replace('/([a-z0-9_-]+)\.(png|gif)/', $relroot.'/theme/yui_image.php'.$sep.$version.'/$1.$2', $filecontent); 373 } 374 } 375 376 $content .= $filecontent; 377 } 378 379 if ($lastmodified == 0) { 380 $lastmodified = time(); 381 } 382 383 if ($cache) { 384 combo_send_cached($content, $mimetype, $etag, $lastmodified); 385 } else { 386 combo_send_uncached($content, $mimetype); 387 } 388 389 390 /** 391 * Send the JavaScript cached 392 * @param string $content 393 * @param string $mimetype 394 * @param string $etag 395 * @param int $lastmodified 396 */ 397 function combo_send_cached($content, $mimetype, $etag, $lastmodified) { 398 $lifetime = 60*60*24*360; // 1 year, we do not change YUI versions often, there are a few custom yui modules 399 400 header('Content-Disposition: inline; filename="combo"'); 401 header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT'); 402 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 403 header('Pragma: '); 404 header('Cache-Control: public, max-age='.$lifetime); 405 header('Accept-Ranges: none'); 406 header('Content-Type: '.$mimetype); 407 header('Etag: "'.$etag.'"'); 408 if (!min_enable_zlib_compression()) { 409 header('Content-Length: '.strlen($content)); 410 } 411 412 echo $content; 413 die; 414 } 415 416 /** 417 * Send the JavaScript uncached 418 * @param string $content 419 * @param string $mimetype 420 */ 421 function combo_send_uncached($content, $mimetype) { 422 header('Content-Disposition: inline; filename="combo"'); 423 header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT'); 424 header('Expires: '. gmdate('D, d M Y H:i:s', time() + 2) .' GMT'); 425 header('Pragma: '); 426 header('Accept-Ranges: none'); 427 header('Content-Type: '.$mimetype); 428 if (!min_enable_zlib_compression()) { 429 header('Content-Length: '.strlen($content)); 430 } 431 432 echo $content; 433 die; 434 } 435 436 function combo_not_found($message = '') { 437 header('HTTP/1.0 404 not found'); 438 if ($message) { 439 echo $message; 440 } else { 441 echo 'Combo resource not found, sorry.'; 442 } 443 die; 444 } 445 446 function combo_params() { 447 if (isset($_SERVER['QUERY_STRING']) and strpos($_SERVER['QUERY_STRING'], 'file=/') === 0) { 448 // url rewriting 449 $slashargument = substr($_SERVER['QUERY_STRING'], 6); 450 return array($slashargument, true); 451 452 } else if (isset($_SERVER['REQUEST_URI']) and strpos($_SERVER['REQUEST_URI'], '?') !== false) { 453 $parts = explode('?', $_SERVER['REQUEST_URI'], 2); 454 return array($parts[1], false); 455 456 } else if (isset($_SERVER['QUERY_STRING']) and strpos($_SERVER['QUERY_STRING'], '?') !== false) { 457 // note: buggy or misconfigured IIS does return the query string in REQUEST_URI 458 return array($_SERVER['QUERY_STRING'], false); 459 460 } else if ($slashargument = min_get_slash_argument(false)) { 461 $slashargument = ltrim($slashargument, '/'); 462 return array($slashargument, true); 463 464 } else { 465 // unsupported server, sorry! 466 combo_not_found('Unsupported server - query string can not be determined, try disabling YUI combo loading in admin settings.'); 467 } 468 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |