Merge branch 'w30_MDL-40545_m26_localcachedir' of https://github.com/skodak/moodle

This commit is contained in:
Dan Poltawski
2013-07-22 15:47:48 +08:00
19 changed files with 530 additions and 25 deletions
+3 -2
View File
@@ -394,8 +394,9 @@ if ($interactive) {
cli_error(get_string('pathserrcreatedataroot', 'install', $a));
}
}
$CFG->tempdir = $CFG->dataroot.'/temp';
$CFG->cachedir = $CFG->dataroot.'/cache';
$CFG->tempdir = $CFG->dataroot.'/temp';
$CFG->cachedir = $CFG->dataroot.'/cache';
$CFG->localcachedir = $CFG->dataroot.'/localcache';
// download required lang packs
if ($CFG->lang !== 'en') {
+1
View File
@@ -154,6 +154,7 @@ $CFG->jsrev = 1;
// Unset cache and temp directories to reset them again with the new $CFG->dataroot.
unset($CFG->cachedir);
unset($CFG->localcachedir);
unset($CFG->tempdir);
// Continues setup.
+5 -2
View File
@@ -213,6 +213,7 @@ $CFG->admin = 'admin';
// $CFG->xsendfilealiases = array(
// '/dataroot/' => $CFG->dataroot,
// '/cachedir/' => '/var/www/moodle/cache', // for custom $CFG->cachedir locations
// '/localcachedir/' => '/var/local/cache', // for custom $CFG->localcachedir locations
// '/tempdir/' => '/var/www/moodle/temp', // for custom $CFG->tempdir locations
// '/filedir' => '/var/www/moodle/filedir', // for custom $CFG->filedir locations
// );
@@ -353,10 +354,12 @@ $CFG->admin = 'admin';
//
// It is possible to specify different cache and temp directories, use local fast filesystem
// for normal web servers. Server clusters MUST use shared filesystem for cachedir!
// Localcachedir is intended for server clusters, it does not have to be shared by cluster nodes.
// The directories must not be accessible via web.
//
// $CFG->tempdir = '/var/www/moodle/temp';
// $CFG->cachedir = '/var/www/moodle/cache';
// $CFG->tempdir = '/var/www/moodle/temp'; // Files used during one HTTP request only.
// $CFG->cachedir = '/var/www/moodle/cache'; // Directory MUST BE SHARED by all cluster nodes, locking required.
// $CFG->localcachedir = '/var/local/cache'; // Intended for local node caching.
//
// Some filesystems such as NFS may not support file locking operations.
// Locking resolves race conditions and is strongly recommended for production servers.
+1
View File
@@ -170,6 +170,7 @@ $CFG->httpswwwroot = $CFG->wwwroot;
$CFG->dataroot = $config->dataroot;
$CFG->tempdir = $CFG->dataroot.'/temp';
$CFG->cachedir = $CFG->dataroot.'/cache';
$CFG->localcachedir = $CFG->dataroot.'/localcache';
$CFG->admin = $config->admin;
$CFG->docroot = 'http://docs.moodle.org';
$CFG->langotherroot = $CFG->dataroot.'/lang';
+1 -1
View File
@@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die();
*/
class core_component {
/** @var array list of ignored directories - watch out for auth/db exception */
protected static $ignoreddirs = array('CVS'=>true, '_vti_cnf'=>true, 'simpletest'=>true, 'db'=>true, 'yui'=>true, 'tests'=>true, 'classes'=>true);
protected static $ignoreddirs = array('CVS'=>true, '_vti_cnf'=>true, 'simpletest'=>true, 'db'=>true, 'yui'=>true, 'tests'=>true, 'classes'=>true, 'fonts'=>true);
/** @var array list plugin types that support subplugins, do not add more here unless absolutely necessary */
protected static $supportsubplugins = array('mod', 'editor', 'local');
+1 -1
View File
@@ -79,7 +79,7 @@ $etag = sha1($rev.implode(',', $jsfiles));
// Use the caching only for meaningful revision numbers which prevents future cache poisoning.
if ($rev > 0 and $rev < (time() + 60*60)) {
$candidate = $CFG->cachedir.'/js/'.$etag;
$candidate = $CFG->localcachedir.'/js/'.$etag;
if (file_exists($candidate)) {
if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
+6
View File
@@ -1560,6 +1560,12 @@ function purge_all_caches() {
// hack: this script may get called after the purifier was initialised,
// but we do not want to verify repeatedly this exists in each call
make_cache_directory('htmlpurifier');
// This is the only place where we purge local caches, we are only adding files there.
// The $CFG->localcachedirpurged flag forces local directories to be purged on cluster nodes.
remove_dir($CFG->localcachedir, true);
set_config('localcachedirpurged', time());
make_localcache_directory('', true);
}
/**
+117 -3
View File
@@ -44,7 +44,6 @@ require_once($CFG->libdir.'/outputrequirementslib.php');
*/
function theme_reset_all_caches() {
global $CFG, $PAGE;
require_once("$CFG->libdir/filelib.php");
$next = time();
if (isset($CFG->themerev) and $next <= $CFG->themerev and $CFG->themerev - $next < 60*60) {
@@ -55,7 +54,6 @@ function theme_reset_all_caches() {
}
set_config('themerev', $next); // time is unique even when you reset/switch database
fulldelete("$CFG->cachedir/theme");
if ($PAGE) {
$PAGE->reload_theme();
@@ -1016,7 +1014,7 @@ class theme_config {
*/
public function post_process($css) {
// now resolve all image locations
if (preg_match_all('/\[\[pix:([a-z_]+\|)?([^\]]+)\]\]/', $css, $matches, PREG_SET_ORDER)) {
if (preg_match_all('/\[\[pix:([a-z0-9_]+\|)?([^\]]+)\]\]/', $css, $matches, PREG_SET_ORDER)) {
$replaced = array();
foreach ($matches as $match) {
if (isset($replaced[$match[0]])) {
@@ -1032,6 +1030,23 @@ class theme_config {
}
}
// Now resolve all font locations.
if (preg_match_all('/\[\[font:([a-z0-9_]+\|)?([^\]]+)\]\]/', $css, $matches, PREG_SET_ORDER)) {
$replaced = array();
foreach ($matches as $match) {
if (isset($replaced[$match[0]])) {
continue;
}
$replaced[$match[0]] = true;
$fontname = $match[2];
$component = rtrim($match[1], '|');
$fonturl = $this->font_url($fontname, $component)->out(false);
// We do not need full url because the font.php is always in the same dir.
$fonturl = preg_replace('|^http.?://[^/]+|', '', $fonturl);
$css = str_replace($match[0], $fonturl, $css);
}
}
// now resolve all theme settings or do any other postprocessing
$csspostprocess = $this->csspostprocess;
if (function_exists($csspostprocess)) {
@@ -1088,6 +1103,42 @@ class theme_config {
return $url;
}
/**
* Return the URL for a font
*
* @param string $font the name of the font (including extension).
* @param string $component specification of one plugin like in get_string()
* @return moodle_url
*/
public function font_url($font, $component) {
global $CFG;
$params = array('theme'=>$this->name);
if (empty($component) or $component === 'moodle' or $component === 'core') {
$params['component'] = 'core';
} else {
$params['component'] = $component;
}
$rev = theme_get_revision();
if ($rev != -1) {
$params['rev'] = $rev;
}
$params['font'] = $font;
$url = new moodle_url("$CFG->httpswwwroot/theme/font.php");
if (!empty($CFG->slasharguments) and $rev > 0) {
$path = '/'.$params['theme'].'/'.$params['component'].'/'.$params['rev'].'/'.$params['font'];
$url->set_slashargument($path, 'noparam', true);
} else {
$url->params($params);
}
return $url;
}
/**
* Returns URL to the stored file via pluginfile.php.
*
@@ -1236,6 +1287,69 @@ class theme_config {
}
}
/**
* Resolves the real font location.
*
* @param string $font name of font file
* @param string $component
* @return string full file path
*/
public function resolve_font_location($font, $component) {
global $CFG;
if ($component === 'moodle' or $component === 'core' or empty($component)) {
if (file_exists("$this->dir/fonts_core/$font")) {
return "$this->dir/fonts_core/$font";
}
foreach (array_reverse($this->parent_configs) as $parent_config) { // Base first, the immediate parent last.
if (file_exists("$parent_config->dir/fonts_core/$font")) {
return "$parent_config->dir/fonts_core/$font";
}
}
if (file_exists("$CFG->dataroot/fonts/$font")) {
return "$CFG->dataroot/fonts/$font";
}
if (file_exists("$CFG->dirroot/lib/fonts/$font")) {
return "$CFG->dirroot/lib/fonts/$font";
}
return null;
} else if ($component === 'theme') { // Exception.
if (file_exists("$this->dir/fonts/$font")) {
return "$this->dir/fonts/$font";
}
foreach (array_reverse($this->parent_configs) as $parent_config) { // Base first, the immediate parent last.
if (file_exists("$parent_config->dir/fonts/$font")) {
return "$parent_config->dir/fonts/$font";
}
}
return null;
} else {
if (strpos($component, '_') === false) {
$component = 'mod_'.$component;
}
list($type, $plugin) = explode('_', $component, 2);
if (file_exists("$this->dir/fonts_plugins/$type/$plugin/$font")) {
return "$this->dir/fonts_plugins/$type/$plugin/$font";
}
foreach (array_reverse($this->parent_configs) as $parent_config) { // Base first, the immediate parent last.
if (file_exists("$parent_config->dir/fonts_plugins/$type/$plugin/$font")) {
return "$parent_config->dir/fonts_plugins/$type/$plugin/$font";
}
}
if (file_exists("$CFG->dataroot/fonts_plugins/$type/$plugin/$font")) {
return "$CFG->dataroot/fonts_plugins/$type/$plugin/$font";
}
$dir = core_component::get_plugin_directory($type, $plugin);
if (file_exists("$dir/fonts/$font")) {
return "$dir/fonts/$font";
}
return null;
}
}
/**
* Return true if we should look for SVG images as well.
*
-2
View File
@@ -1744,7 +1744,6 @@ class YUI_config {
*/
function js_reset_all_caches() {
global $CFG;
require_once("$CFG->libdir/filelib.php");
$next = time();
if (isset($CFG->jsrev) and $next <= $CFG->jsrev and $CFG->jsrev - $next < 60*60) {
@@ -1755,5 +1754,4 @@ function js_reset_all_caches() {
}
set_config('jsrev', $next);
fulldelete("$CFG->cachedir/js");
}
+7 -1
View File
@@ -37,7 +37,8 @@
* - $CFG->dirroot - Path to moodle's library folder on server's filesystem.
* - $CFG->libdir - Path to moodle's library folder on server's filesystem.
* - $CFG->tempdir - Path to moodle's temp file directory on server's filesystem.
* - $CFG->cachedir - Path to moodle's cache directory on server's filesystem.
* - $CFG->cachedir - Path to moodle's cache directory on server's filesystem (shared by cluster nodes).
* - $CFG->localcachedir - Path to moodle's local cache directory (not shared by cluster nodes).
*
* @global object $CFG
* @name $CFG
@@ -160,6 +161,11 @@ if (!isset($CFG->cachedir)) {
$CFG->cachedir = "$CFG->dataroot/cache";
}
// Allow overriding of localcachedir.
if (!isset($CFG->localcachedir)) {
$CFG->localcachedir = "$CFG->dataroot/localcache";
}
// The current directory in PHP version 4.3.0 and above isn't necessarily the
// directory of the script when run from the command line. The require_once()
// would fail, so we'll have to chdir()
+59 -2
View File
@@ -529,7 +529,7 @@ function get_exception_info($ex) {
// Remove some absolute paths from message and debugging info.
$searches = array();
$replaces = array();
$cfgnames = array('tempdir', 'cachedir', 'themedir',
$cfgnames = array('tempdir', 'cachedir', 'localcachedir', 'themedir',
'langmenucachefile', 'langcacheroot', 'dataroot', 'dirroot');
foreach ($cfgnames as $cfgname) {
if (property_exists($CFG, $cfgname)) {
@@ -1311,7 +1311,10 @@ function make_upload_directory($directory, $exceptiononerror = true) {
debugging('Use make_temp_directory() for creation of temporary directory and $CFG->tempdir to get the location.');
} else if (strpos($directory, 'cache/') === 0 or $directory === 'cache') {
debugging('Use make_cache_directory() for creation of chache directory and $CFG->cachedir to get the location.');
debugging('Use make_cache_directory() for creation of cache directory and $CFG->cachedir to get the location.');
} else if (strpos($directory, 'localcache/') === 0 or $directory === 'localcache') {
debugging('Use make_localcache_directory() for creation of local cache directory and $CFG->localcachedir to get the location.');
}
protect_directory($CFG->dataroot);
@@ -1340,6 +1343,8 @@ function make_temp_directory($directory, $exceptiononerror = true) {
/**
* Create a directory under cachedir and make sure it is writable.
*
* Note: this cache directory is shared by all cluster nodes.
*
* @param string $directory the full path of the directory to be created under $CFG->cachedir
* @param bool $exceptiononerror throw exception if error encountered
* @return string|false Returns full path to directory if successful, false if not; may throw exception
@@ -1355,6 +1360,58 @@ function make_cache_directory($directory, $exceptiononerror = true) {
return make_writable_directory("$CFG->cachedir/$directory", $exceptiononerror);
}
/**
* Create a directory under localcachedir and make sure it is writable.
* The files in this directory MUST NOT change, use revisions or content hashes to
* work around this limitation - this means you can only add new files here.
*
* The content of this directory gets purged automatically on all cluster nodes
* after calling purge_all_caches() before new data is written to this directory.
*
* Note: this local cache directory does not need to be shared by cluster nodes.
*
* @param string $directory the relative path of the directory to be created under $CFG->localcachedir
* @param bool $exceptiononerror throw exception if error encountered
* @return string|false Returns full path to directory if successful, false if not; may throw exception
*/
function make_localcache_directory($directory, $exceptiononerror = true) {
global $CFG;
make_writable_directory($CFG->localcachedir, $exceptiononerror);
if ($CFG->localcachedir !== "$CFG->dataroot/localcache") {
protect_directory($CFG->localcachedir);
} else {
protect_directory($CFG->dataroot);
}
if (!isset($CFG->localcachedirpurged)) {
$CFG->localcachedirpurged = 0;
}
$timestampfile = "$CFG->localcachedir/.lastpurged";
if (!file_exists($timestampfile)) {
touch($timestampfile);
@chmod($timestampfile, $CFG->filepermissions);
} else if (filemtime($timestampfile) < $CFG->localcachedirpurged) {
// This means our local cached dir was not purged yet.
remove_dir($CFG->localcachedir, true);
if ($CFG->localcachedir !== "$CFG->dataroot/localcache") {
protect_directory($CFG->localcachedir);
}
touch($timestampfile);
@chmod($timestampfile, $CFG->filepermissions);
clearstatcache();
}
if ($directory === '') {
return $CFG->localcachedir;
}
return make_writable_directory("$CFG->localcachedir/$directory", $exceptiononerror);
}
/**
* Checks if current user is a web crawler.
*
+1
View File
@@ -599,6 +599,7 @@ abstract class testing_util {
make_temp_directory('');
make_cache_directory('');
make_cache_directory('htmlpurifier');
make_localcache_directory('');
// Reset the cache API so that it recreates it's required directories as well.
cache_factory::reset();
// Purge all data from the caches. This is required for consistency.
+78 -2
View File
@@ -31,7 +31,7 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_setuplib_testcase extends basic_testcase {
class core_setuplib_testcase extends advanced_testcase {
/**
* Test get_docs_url_standard in the normal case when we should link to Moodle docs.
@@ -126,7 +126,7 @@ class core_setuplib_testcase extends basic_testcase {
global $CFG;
// This doesn't test them all possible ones, but these are set for unit tests.
$cfgnames = array('dataroot', 'dirroot', 'tempdir', 'cachedir');
$cfgnames = array('dataroot', 'dirroot', 'tempdir', 'cachedir', 'localcachedir');
$fixture = '';
$expected = '';
@@ -142,4 +142,80 @@ class core_setuplib_testcase extends basic_testcase {
$this->assertContains($expected, $exceptioninfo->message, 'Exception message does not contain system paths');
$this->assertContains($expected, $exceptioninfo->debuginfo, 'Exception debug info does not contain system paths');
}
public function test_localcachedir() {
global $CFG;
$this->resetAfterTest(true);
// Test default location - can not be modified in phpunit tests because we override everything in config.php.
$this->assertSame("$CFG->dataroot/localcache", $CFG->localcachedir);
$now = time();
$timestampfile = "$CFG->localcachedir/.lastpurged";
$dir = make_localcache_directory('', false);
$this->assertSame($CFG->localcachedir, $dir);
$this->assertFileNotExists("$CFG->localcachedir/.htaccess");
$this->assertFileExists($timestampfile);
$this->assertGreaterThanOrEqual($now, filemtime($timestampfile));
$this->assertLessThanOrEqual(time(), filemtime($timestampfile));
$dir = make_localcache_directory('test/test', false);
$this->assertSame("$CFG->localcachedir/test/test", $dir);
// Test custom location.
$CFG->localcachedir = "$CFG->dataroot/testlocalcache";
$now = time();
$timestampfile = "$CFG->localcachedir/.lastpurged";
$this->assertFileNotExists($timestampfile);
$dir = make_localcache_directory('', false);
$this->assertSame($CFG->localcachedir, $dir);
$this->assertFileExists("$CFG->localcachedir/.htaccess");
$this->assertFileExists($timestampfile);
$this->assertGreaterThanOrEqual($now, filemtime($timestampfile));
$this->assertLessThanOrEqual(time(), filemtime($timestampfile));
$dir = make_localcache_directory('test', false);
$this->assertSame("$CFG->localcachedir/test", $dir);
$prevtime = filemtime($timestampfile);
$dir = make_localcache_directory('pokus', false);
$this->assertSame("$CFG->localcachedir/pokus", $dir);
$this->assertSame($prevtime, filemtime($timestampfile));
// Test purging.
$testfile = "$CFG->localcachedir/test/test.txt";
$this->assertTrue(touch($testfile));
$now = time();
set_config('localcachedirpurged', $now - 2);
purge_all_caches();
$this->assertFileNotExists($testfile);
$this->assertFileNotExists(dirname($testfile));
$this->assertFileExists($timestampfile);
$this->assertGreaterThanOrEqual($now, filemtime($timestampfile));
$this->assertLessThanOrEqual(time(), filemtime($timestampfile));
$this->assertGreaterThanOrEqual($now, $CFG->localcachedirpurged);
$this->assertLessThanOrEqual(time(), $CFG->localcachedirpurged);
// Simulates purge_all_caches() on another server node.
make_localcache_directory('test', false);
$this->assertTrue(touch($testfile));
set_config('localcachedirpurged', $now - 1);
$this->assertTrue(touch($timestampfile, $now - 2));
clearstatcache();
$this->assertSame($now - 2, filemtime($timestampfile));
$now = time();
$dir = make_localcache_directory('', false);
$this->assertSame("$CFG->localcachedir", $dir);
$this->assertFileNotExists($testfile);
$this->assertFileNotExists(dirname($testfile));
$this->assertFileExists($timestampfile);
$this->assertGreaterThanOrEqual($now, filemtime($timestampfile));
$this->assertLessThanOrEqual(time(), filemtime($timestampfile));
}
}
+1
View File
@@ -10,6 +10,7 @@ information provided here is intended especially for developers.
core_component::get_plugin_list() does not accept empty parameter any more.
* Use core_text::* instead of textlib:: and also core_collator::* instead of collatorlib::*.
* Use new function moodleform::mock_submit() to simulate form submission in unit tests (backported).
* New $CFG->localcachedir setting useful for cluster nodes. Admins have to update X-Sendfile aliases if used.
DEPRECATIONS:
Various previously deprecated functions have now been altered to throw DEBUG_DEVELOPER debugging notices
+8 -3
View File
@@ -1467,12 +1467,17 @@ function install_core($version, $verbose) {
global $CFG, $DB;
// We can not call purge_all_caches() yet, make sure the temp and cache dirs exist and are empty.
make_cache_directory('', true);
remove_dir($CFG->cachedir.'', true);
make_temp_directory('', true);
make_cache_directory('', true);
remove_dir($CFG->localcachedir.'', true);
make_localcache_directory('', true);
remove_dir($CFG->tempdir.'', true);
make_writable_directory($CFG->dataroot.'/muc', true);
make_temp_directory('', true);
remove_dir($CFG->dataroot.'/muc', true);
make_writable_directory($CFG->dataroot.'/muc', true);
try {
set_time_limit(600);
+235
View File
@@ -0,0 +1,235 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file is responsible for serving the fonts used in CSS.
*
* Note: it is recommended to use only WOFF (Web Open Font Format) fonts.
*
* @package core
* @copyright 2013 Petr Skoda (skodak) {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// Disable moodle specific debug messages and any errors in output,
// comment out when debugging or better look into error log!
define('NO_DEBUG_DISPLAY', true);
define('ABORT_AFTER_CONFIG', true);
require('../config.php');
if ($slashargument = min_get_slash_argument()) {
$slashargument = ltrim($slashargument, '/');
if (substr_count($slashargument, '/') < 3) {
font_not_found();
}
list($themename, $component, $rev, $font) = explode('/', $slashargument, 4);
$themename = min_clean_param($themename, 'SAFEDIR');
$component = min_clean_param($component, 'SAFEDIR');
$rev = min_clean_param($rev, 'INT');
$font = min_clean_param($font, 'RAW');
} else {
$themename = min_optional_param('theme', 'standard', 'SAFEDIR');
$component = min_optional_param('component', 'core', 'SAFEDIR');
$rev = min_optional_param('rev', -1, 'INT');
$font = min_optional_param('font', '', 'RAW');
}
if (!$font) {
font_not_found();
}
if (empty($component) or $component === 'moodle' or $component === 'core') {
$component = 'core';
}
if (preg_match('/^[a-z0-9_-]+\.woff$/i', $font, $matches)) {
// This is the real standard!
$font = $matches[0];
$mimetype = 'application/font-woff';
} else if (preg_match('^[a-z0-9_-]+/\.ttf$/i', $font, $matches)) {
$font = $matches[0];
$mimetype = 'application/x-font-ttf';
} else if (preg_match('^[a-z0-9_-]+/\.otf$/i', $font, $matches)) {
$font = $matches[0];
$mimetype = 'application/x-font-opentype';
} else if (preg_match('^[a-z0-9_-]+/\.oet$/i', $font, $matches)) {
// IE8 must die!!!
$font = $matches[0];
$mimetype = 'application/vnd.ms-fontobject';
} else {
font_not_found();
}
if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
// Normal theme exists.
} else if (!empty($CFG->themedir) and file_exists("$CFG->themedir/$themename/config.php")) {
// Theme exists in alternative location.
} else {
font_not_found();
}
$candidatelocation = "$CFG->localcachedir/theme/$rev/$themename/fonts/$component";
$etag = sha1("$rev/$themename/$component/$font");
if ($rev > 0) {
if (file_exists("$candidatelocation/$font.error")) {
font_not_found();
}
if (file_exists("$candidatelocation/$font")) {
if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// We do not actually need to verify the etag value because our files
// never change in cache because we increment the rev parameter.
$lifetime = 60*60*24*60; // 60 days only - the revision may get incremented quite often.
header('HTTP/1.1 304 Not Modified');
header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
header('Cache-Control: public, max-age='.$lifetime);
header('Content-Type: '.$mimetype);
header('Etag: "'.$etag.'"');
die;
}
send_cached_font("$candidatelocation/$font", $etag, $font, $mimetype);
}
}
// Ok, now we need to start normal moodle script, we need to load all libs and $DB.
define('ABORT_AFTER_CONFIG_CANCEL', true);
define('NO_MOODLE_COOKIES', true); // Session not used here.
define('NO_UPGRADE_CHECK', true); // Ignore upgrade check.
require("$CFG->dirroot/lib/setup.php");
$theme = theme_config::load($themename);
$themerev = theme_get_revision();
$fontfile = $theme->resolve_font_location($font, $component);
if ($themerev <= 0 or $rev != $themerev) {
// Do not send caching headers if they do not request current revision,
// we do not want to pollute browser caches with outdated fonts.
if (empty($fontfile) or !is_readable($fontfile)) {
font_not_found();
}
send_uncached_font($fontfile, $font, $mimetype);
}
make_localcache_directory('theme', false);
if (empty($fontfile) or !is_readable($fontfile)) {
if (!file_exists($candidatelocation)) {
@mkdir($candidatelocation, $CFG->directorypermissions, true);
}
// Make note we can not find this file.
$cachefont = "$candidatelocation/$font.error";
$fp = fopen($cachefont, 'w');
fclose($fp);
font_not_found();
}
$cachefont = cache_font($font, $fontfile, $candidatelocation);
if (connection_aborted()) {
die;
}
// Make sure nothing failed.
clearstatcache();
if (file_exists($cachefont)) {
send_cached_font($cachefont, $etag, $font, $mimetype);
}
send_uncached_font($fontfile, $font, $mimetype);
// Utility functions.
function send_cached_font($fontpath, $etag, $font, $mimetype) {
global $CFG;
require("$CFG->dirroot/lib/xsendfilelib.php");
$lifetime = 60*60*24*60; // 60 days only - the revision may get incremented quite often.
header('Etag: "'.$etag.'"');
header('Content-Disposition: inline; filename="'.$font.'"');
header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($fontpath)) .' GMT');
header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
header('Pragma: ');
header('Cache-Control: public, max-age='.$lifetime);
header('Accept-Ranges: none');
header('Content-Type: '.$mimetype);
header('Content-Length: '.filesize($fontpath));
if (xsendfile($fontpath)) {
die;
}
// No need to gzip already compressed fonts.
readfile($fontpath);
die;
}
function send_uncached_font($fontpath, $font, $mimetype) {
header('Content-Disposition: inline; filename="'.$font.'"');
header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
header('Expires: '. gmdate('D, d M Y H:i:s', time() + 15) .' GMT');
header('Pragma: ');
header('Accept-Ranges: none');
header('Content-Type: '.$mimetype);
header('Content-Length: '.filesize($fontpath));
readfile($fontpath);
die;
}
function font_not_found() {
header('HTTP/1.0 404 not found');
die('font was not found, sorry.');
}
/**
* Caches a given font file.
*
* @param string $font The name of the font that was requested.
* @param string $fontfile The location of the font file we want to cache.
* @param string $candidatelocation The location to cache it in.
* @return string The path to the cached font.
*/
function cache_font($font, $fontfile, $candidatelocation) {
global $CFG;
$cachefont = "$candidatelocation/$font";
clearstatcache();
if (!file_exists($candidatelocation)) {
@mkdir($candidatelocation, $CFG->directorypermissions, true);
}
// Prevent serving of incomplete file from concurrent request,
// the rename() should be more atomic than copy().
ignore_user_abort(true);
if (@copy($fontfile, $cachefont.'.tmp')) {
rename($cachefont.'.tmp', $cachefont);
@chmod($cachefont, $CFG->filepermissions);
@unlink($cachefont.'.tmp'); // Just in case anything fails.
}
return $cachefont;
}
+2 -2
View File
@@ -74,7 +74,7 @@ if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
image_not_found();
}
$candidatelocation = "$CFG->cachedir/theme/$rev/$themename/pix/$component";
$candidatelocation = "$CFG->localcachedir/theme/$rev/$themename/pix/$component";
$etag = sha1("$rev/$themename/$component/$image");
if ($rev > 0) {
@@ -142,7 +142,7 @@ if ($themerev <= 0 or $rev != $themerev) {
send_uncached_image($imagefile);
}
make_cache_directory('theme', false);
make_localcache_directory('theme', false);
// We're not using SVG and there is no cached version of this file (in any format).
// As we're going to be caching a format other than svg, and because svg use is conditional we need to ensure that at the same
+2 -2
View File
@@ -63,7 +63,7 @@ if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
die('Theme was not found, sorry.');
}
$candidate = "$CFG->cachedir/theme/$rev/$themename/javascript_$type.js";
$candidate = "$CFG->localcachedir/theme/$rev/$themename/javascript_$type.js";
$etag = sha1("$rev/$themename/$type");
if ($rev > 0 and file_exists($candidate)) {
@@ -93,7 +93,7 @@ if ($themerev <= 0 or $rev != $themerev) {
js_send_uncached($theme->javascript_content($type));
}
make_cache_directory('theme', false);
make_localcache_directory('theme', false);
js_write_cache_file_content($candidate, js_minify($theme->javascript_files($type)));
// Verify nothing failed in cache file creation.
+2 -2
View File
@@ -87,7 +87,7 @@ if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
die('Theme was not found, sorry.');
}
$candidatedir = "$CFG->cachedir/theme/$rev/$themename/css";
$candidatedir = "$CFG->localcachedir/theme/$rev/$themename/css";
$etag = "$rev/$themename/$type";
$candidatename = $type;
if (!$usesvg) {
@@ -148,7 +148,7 @@ if ($themerev <= 0 or $themerev != $rev) {
$etag = sha1($etag);
}
make_cache_directory('theme', false);
make_localcache_directory('theme', false);
if ($type === 'editor') {
$cssfiles = $theme->editor_css_files();