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 contains CSS file serving functions. 19 * 20 * NOTE: these functions are not expected to be used from any addons. 21 * 22 * @package core 23 * @copyright 2012 Sam Hemelryk 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 if (!defined('THEME_DESIGNER_CACHE_LIFETIME')) { 30 // This can be also set in config.php file, 31 // it needs to be higher than the time it takes to generate all CSS content. 32 define('THEME_DESIGNER_CACHE_LIFETIME', 10); 33 } 34 35 /** 36 * Stores CSS in a file at the given path. 37 * 38 * This function either succeeds or throws an exception. 39 * 40 * @param theme_config $theme The theme that the CSS belongs to. 41 * @param string $csspath The path to store the CSS at. 42 * @param string $csscontent the complete CSS in one string. 43 */ 44 function css_store_css(theme_config $theme, $csspath, $csscontent) { 45 global $CFG; 46 47 clearstatcache(); 48 if (!file_exists(dirname($csspath))) { 49 @mkdir(dirname($csspath), $CFG->directorypermissions, true); 50 } 51 52 // Prevent serving of incomplete file from concurrent request, 53 // the rename() should be more atomic than fwrite(). 54 ignore_user_abort(true); 55 56 // First up write out the single file for all those using decent browsers. 57 css_write_file($csspath, $csscontent); 58 59 ignore_user_abort(false); 60 if (connection_aborted()) { 61 die; 62 } 63 } 64 65 /** 66 * Writes a CSS file. 67 * 68 * @param string $filename 69 * @param string $content 70 */ 71 function css_write_file($filename, $content) { 72 global $CFG; 73 if ($fp = fopen($filename.'.tmp', 'xb')) { 74 fwrite($fp, $content); 75 fclose($fp); 76 rename($filename.'.tmp', $filename); 77 @chmod($filename, $CFG->filepermissions); 78 @unlink($filename.'.tmp'); // Just in case anything fails. 79 } 80 } 81 82 /** 83 * Sends a cached CSS file 84 * 85 * This function sends the cached CSS file. Remember it is generated on the first 86 * request, then optimised/minified, and finally cached for serving. 87 * 88 * @param string $csspath The path to the CSS file we want to serve. 89 * @param string $etag The revision to make sure we utilise any caches. 90 */ 91 function css_send_cached_css($csspath, $etag) { 92 // 90 days only - based on Moodle point release cadence being every 3 months. 93 $lifetime = 60 * 60 * 24 * 90; 94 95 header('Etag: "'.$etag.'"'); 96 header('Content-Disposition: inline; filename="styles.php"'); 97 header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($csspath)) .' GMT'); 98 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 99 header('Pragma: '); 100 header('Cache-Control: public, max-age='.$lifetime.', immutable'); 101 header('Accept-Ranges: none'); 102 header('Content-Type: text/css; charset=utf-8'); 103 if (!min_enable_zlib_compression()) { 104 header('Content-Length: '.filesize($csspath)); 105 } 106 107 readfile($csspath); 108 die; 109 } 110 111 /** 112 * Sends a cached CSS content 113 * 114 * @param string $csscontent The actual CSS markup. 115 * @param string $etag The revision to make sure we utilise any caches. 116 */ 117 function css_send_cached_css_content($csscontent, $etag) { 118 // 90 days only - based on Moodle point release cadence being every 3 months. 119 $lifetime = 60 * 60 * 24 * 90; 120 121 header('Etag: "'.$etag.'"'); 122 header('Content-Disposition: inline; filename="styles.php"'); 123 header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT'); 124 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 125 header('Pragma: '); 126 header('Cache-Control: public, max-age='.$lifetime.', immutable'); 127 header('Accept-Ranges: none'); 128 header('Content-Type: text/css; charset=utf-8'); 129 if (!min_enable_zlib_compression()) { 130 header('Content-Length: '.strlen($csscontent)); 131 } 132 133 echo($csscontent); 134 die; 135 } 136 137 /** 138 * Sends CSS directly and disables all caching. 139 * The Content-Length of the body is also included, but the script is not ended. 140 * 141 * @param string $css The CSS content to send 142 */ 143 function css_send_temporary_css($css) { 144 header('Cache-Control: no-cache, no-store, must-revalidate'); 145 header('Pragma: no-cache'); 146 header('Expires: 0'); 147 header('Content-Disposition: inline; filename="styles_debug.php"'); 148 header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT'); 149 header('Accept-Ranges: none'); 150 header('Content-Type: text/css; charset=utf-8'); 151 header('Content-Length: ' . strlen($css)); 152 153 echo $css; 154 } 155 156 /** 157 * Sends CSS directly without caching it. 158 * 159 * This function takes a raw CSS string, optimises it if required, and then 160 * serves it. 161 * Turning both themedesignermode and CSS optimiser on at the same time is awful 162 * for performance because of the optimiser running here. However it was done so 163 * that theme designers could utilise the optimised output during development to 164 * help them optimise their CSS... not that they should write lazy CSS. 165 * 166 * @param string $css 167 */ 168 function css_send_uncached_css($css) { 169 header('Content-Disposition: inline; filename="styles_debug.php"'); 170 header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT'); 171 header('Expires: '. gmdate('D, d M Y H:i:s', time() + THEME_DESIGNER_CACHE_LIFETIME) .' GMT'); 172 header('Pragma: '); 173 header('Accept-Ranges: none'); 174 header('Content-Type: text/css; charset=utf-8'); 175 176 if (is_array($css)) { 177 $css = implode("\n\n", $css); 178 } 179 echo $css; 180 die; 181 } 182 183 /** 184 * Send file not modified headers 185 * 186 * @param int $lastmodified 187 * @param string $etag 188 */ 189 function css_send_unmodified($lastmodified, $etag) { 190 // 90 days only - based on Moodle point release cadence being every 3 months. 191 $lifetime = 60 * 60 * 24 * 90; 192 header('HTTP/1.1 304 Not Modified'); 193 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 194 header('Cache-Control: public, max-age='.$lifetime); 195 header('Content-Type: text/css; charset=utf-8'); 196 header('Etag: "'.$etag.'"'); 197 if ($lastmodified) { 198 header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT'); 199 } 200 die; 201 } 202 203 /** 204 * Sends a 404 message about CSS not being found. 205 */ 206 function css_send_css_not_found() { 207 header('HTTP/1.0 404 not found'); 208 die('CSS was not found, sorry.'); 209 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body