/** * Stores CSS in a file at the given path. * * This function either succeeds or throws an exception. * * @param theme_config $theme The theme that the CSS belongs to. * @param string $csspath The path to store the CSS at. * @param array $cssfiles The CSS files to store. */ function css_store_css(theme_config $theme, $csspath, array $cssfiles) { global $CFG; // Check if both the CSS optimiser is enabled and the theme supports it. if (!empty($CFG->enablecssoptimiser) && $theme->supportscssoptimisation) { // This is an experimental feature introduced in Moodle 2.3 // The CSS optimiser organises the CSS in order to reduce the overall number // of rules and styles being sent to the client. It does this by collating // the CSS before it is cached removing excess styles and rules and stripping // out any extraneous content such as comments and empty rules. $optimiser = new css_optimiser; $css = ''; foreach ($cssfiles as $file) { $css .= file_get_contents($file)."\n"; } $css = $theme->post_process($css); $css = $optimiser->process($css); // If cssoptimisestats is set then stats from the optimisation are collected // and output at the beginning of the CSS if (!empty($CFG->cssoptimiserstats)) { $css = $optimiser->output_stats_css().$css; } } else { // This is the default behaviour. // The cssoptimise setting was introduced in Moodle 2.3 and will hopefully // in the future be changed from an experimental setting to the default. // The css_minify_css will method will use the Minify library remove // comments, additional whitespace and other minor measures to reduce the // the overall CSS being sent. // However it has the distinct disadvantage of having to minify the CSS // before running the post process functions. Potentially things may break // here if theme designers try to push things with CSS post processing. $css = $theme->post_process(css_minify_css($cssfiles)); } clearstatcache(); if (!file_exists(dirname($csspath))) { @mkdir(dirname($csspath), $CFG->directorypermissions, true); } // Prevent serving of incomplete file from concurrent request, // the rename() should be more atomic than fwrite(). ignore_user_abort(true); if ($fp = fopen($csspath.'.tmp', 'xb')) { fwrite($fp, $css); fclose($fp); rename($csspath.'.tmp', $csspath); @chmod($csspath, $CFG->filepermissions); @unlink($csspath.'.tmp'); // just in case anything fails } ignore_user_abort(false); if (connection_aborted()) { die; } }
/** * Get the theme designer css markup, * the parameters are coming from css_urls(). * * NOTE: this method is not expected to be used from any addons. * * @param string $type * @param string $subtype * @param string $sheet * @return string CSS markup */ public function get_css_content_debug($type, $subtype, $sheet) { global $CFG; require_once $CFG->dirroot . '/lib/csslib.php'; // The LESS file of the theme is requested. if ($type === 'less') { $csscontent = $this->get_css_content_from_less(true); if ($csscontent !== false) { return $csscontent; } return ''; } $optimiser = null; if (!empty($CFG->enablecssoptimiser) && $this->supportscssoptimisation) { // This is an experimental feature introduced in Moodle 2.3 // The CSS optimiser organises the CSS in order to reduce the overall number // of rules and styles being sent to the client. It does this by collating // the CSS before it is cached removing excess styles and rules and stripping // out any extraneous content such as comments and empty rules. $optimiser = new css_optimiser(); } $cssfiles = array(); $css = $this->get_css_files(true); if ($type === 'ie') { // IE is a sloppy browser with weird limits, sorry. if ($subtype === 'plugins') { $cssfiles = $css['plugins']; } else { if ($subtype === 'parents') { if (empty($sheet)) { // Do not bother with the empty parent here. } else { // Build up the CSS for that parent so we can serve it as one file. foreach ($css[$subtype][$sheet] as $parent => $css) { $cssfiles[] = $css; } } } else { if ($subtype === 'theme') { $cssfiles = $css['theme']; foreach ($cssfiles as $key => $value) { if ($this->lessfile && $key === $this->lessfile) { // Remove the LESS file from the theme CSS files. // The LESS files use the type 'less', not 'ie'. unset($cssfiles[$key]); } } } } } } else { if ($type === 'plugin') { if (isset($css['plugins'][$subtype])) { $cssfiles[] = $css['plugins'][$subtype]; } } else { if ($type === 'parent') { if (isset($css['parents'][$subtype][$sheet])) { $cssfiles[] = $css['parents'][$subtype][$sheet]; } } else { if ($type === 'theme') { if (isset($css['theme'][$sheet])) { $cssfiles[] = $css['theme'][$sheet]; } } } } } $csscontent = ''; foreach ($cssfiles as $file) { $contents = file_get_contents($file); $contents = $this->post_process($contents); $comment = "/** Path: {$type} {$subtype} {$sheet}.' **/\n"; $stats = ''; if ($optimiser) { $contents = $optimiser->process($contents); if (!empty($CFG->cssoptimiserstats)) { $stats = $optimiser->output_stats_css(); } } $csscontent .= $comment . $stats . $contents . "\n\n"; } return $csscontent; }
/** * Sends CSS directly without caching it. * * This function takes a raw CSS string, optimises it if required, and then * serves it. * Turning both themedesignermode and CSS optimiser on at the same time is aweful * for performance because of the optimiser running here. However it was done so * that theme designers could utilise the optimised output during development to * help them optimise their CSS... not that they should write lazy CSS. * * @param string CSS */ function css_send_uncached_css($css) { global $CFG; header('Content-Disposition: inline; filename="styles_debug.php"'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + THEME_DESIGNER_CACHE_LIFETIME) . ' GMT'); header('Pragma: '); header('Accept-Ranges: none'); header('Content-Type: text/css; charset=utf-8'); if (is_array($css)) { $css = implode("\n\n", $css); } if (!empty($CFG->enablecssoptimiser)) { $css = str_replace("\n", "\r\n", $css); $optimiser = new css_optimiser(); $css = $optimiser->process($css); if (!empty($CFG->cssoptimiserstats)) { $css = $optimiser->output_stats_css() . $css; } } echo $css; die; }
/** * Stores CSS in a file at the given path. * * This function either succeeds or throws an exception. * * @param theme_config $theme The theme that the CSS belongs to. * @param string $csspath The path to store the CSS at. * @param array $cssfiles The CSS files to store. * @param bool $chunk If set to true these files will be chunked to ensure * that no one file contains more than 4095 selectors. * @param string $chunkurl If the CSS is be chunked then we need to know the URL * to use for the chunked files. */ function css_store_css(theme_config $theme, $csspath, array $cssfiles, $chunk = false, $chunkurl = null) { global $CFG; $css = ''; foreach ($cssfiles as $file) { $css .= file_get_contents($file) . "\n"; } // Check if both the CSS optimiser is enabled and the theme supports it. if (!empty($CFG->enablecssoptimiser) && $theme->supportscssoptimisation) { // This is an experimental feature introduced in Moodle 2.3 // The CSS optimiser organises the CSS in order to reduce the overall number // of rules and styles being sent to the client. It does this by collating // the CSS before it is cached removing excess styles and rules and stripping // out any extraneous content such as comments and empty rules. $optimiser = new css_optimiser(); $css = $theme->post_process($css); $css = $optimiser->process($css); // If cssoptimisestats is set then stats from the optimisation are collected // and output at the beginning of the CSS. if (!empty($CFG->cssoptimiserstats)) { $css = $optimiser->output_stats_css() . $css; } } else { // This is the default behaviour. // The cssoptimise setting was introduced in Moodle 2.3 and will hopefully // in the future be changed from an experimental setting to the default. // The css_minify_css will method will use the Minify library remove // comments, additional whitespace and other minor measures to reduce the // the overall CSS being sent. // However it has the distinct disadvantage of having to minify the CSS // before running the post process functions. Potentially things may break // here if theme designers try to push things with CSS post processing. $css = $theme->post_process($css); $css = core_minify::css($css); } clearstatcache(); if (!file_exists(dirname($csspath))) { @mkdir(dirname($csspath), $CFG->directorypermissions, true); } // Prevent serving of incomplete file from concurrent request, // the rename() should be more atomic than fwrite(). ignore_user_abort(true); // First up write out the single file for all those using decent browsers. css_write_file($csspath, $css); if ($chunk) { // If we need to chunk the CSS for browsers that are sub-par. $css = css_chunk_by_selector_count($css, $chunkurl); $files = count($css); $count = 1; foreach ($css as $content) { if ($count === $files) { // If there is more than one file and this IS the last file. $filename = preg_replace('#\\.css$#', '.0.css', $csspath); } else { // If there is more than one file and this is not the last file. $filename = preg_replace('#\\.css$#', '.' . $count . '.css', $csspath); } $count++; css_write_file($filename, $content); } } ignore_user_abort(false); if (connection_aborted()) { die; } }