Merge branch 'w30_MDL-40545_m26_localcachedir' of https://github.com/skodak/moodle
This commit is contained in:
@@ -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') {
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
@@ -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'])) {
|
||||
|
||||
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user