Commit | Line | Data |
---|---|---|
b7009474 | 1 | <?php |
2 | ||
3 | // This file is part of Moodle - http://moodle.org/ | |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
18 | /** | |
78946b9b | 19 | * This file is responsible for serving the one huge CSS of each theme. |
b7009474 | 20 | * |
21 | * @package moodlecore | |
78946b9b | 22 | * @copyright 2009 Petr Skoda (skodak) {@link http://skodak.org} |
b7009474 | 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
24 | */ | |
25 | ||
73e504bc | 26 | |
78946b9b PS |
27 | // we need just the values from config.php and minlib.php |
28 | define('ABORT_AFTER_CONFIG', true); | |
29 | require('../config.php'); // this stops immediately at the beginning of lib/setup.php | |
b7009474 | 30 | |
78946b9b PS |
31 | $themename = min_optional_param('theme', 'standard', 'SAFEDIR'); |
32 | $type = min_optional_param('type', 'all', 'SAFEDIR'); | |
33 | $rev = min_optional_param('rev', 0, 'INT'); | |
b7009474 | 34 | |
c724f835 | 35 | if (!in_array($type, array('all', 'ie', 'editor', 'plugins', 'parents', 'theme'))) { |
78946b9b PS |
36 | header('HTTP/1.0 404 not found'); |
37 | die('Theme was not found, sorry.'); | |
b7009474 | 38 | } |
39 | ||
73e504bc PS |
40 | if (file_exists("$CFG->dirroot/theme/$themename/config.php")) { |
41 | // exists | |
42 | } else if (!empty($CFG->themedir) and file_exists("$CFG->themedir/$themename/config.php")) { | |
43 | // exists | |
44 | } else { | |
78946b9b PS |
45 | header('HTTP/1.0 404 not found'); |
46 | die('Theme was not found, sorry.'); | |
47 | } | |
b7009474 | 48 | |
78946b9b PS |
49 | if ($type === 'ie') { |
50 | send_ie_css($themename, $rev); | |
51 | } | |
b7009474 | 52 | |
78946b9b | 53 | $candidatesheet = "$CFG->dataroot/cache/theme/$themename/css/$type.css"; |
b7009474 | 54 | |
78946b9b PS |
55 | if (file_exists($candidatesheet)) { |
56 | if (!empty($_SERVER['HTTP_IF_NONE_MATCH'])) { | |
57 | // we do not actually need to verify the etag value because our files | |
58 | // never change in cache because we increment the rev parameter | |
59 | header('HTTP/1.1 304 Not Modified'); | |
60 | die; | |
61 | } | |
62 | send_cached_css($candidatesheet, $rev); | |
b7009474 | 63 | } |
64 | ||
78946b9b PS |
65 | //================================================================================= |
66 | // ok, now we need to start normal moodle script, we need to load all libs and $DB | |
67 | define('ABORT_AFTER_CONFIG_CANCEL', true); | |
fdeb7fa1 | 68 | |
78946b9b PS |
69 | define('NO_MOODLE_COOKIES', true); // Session not used here |
70 | define('NO_UPGRADE_CHECK', true); // Ignore upgrade check | |
fdeb7fa1 | 71 | |
78946b9b | 72 | require("$CFG->dirroot/lib/setup.php"); |
b7009474 | 73 | |
78946b9b | 74 | $theme = theme_config::load($themename); |
fdeb7fa1 | 75 | |
78946b9b PS |
76 | if ($type === 'editor') { |
77 | $css = $theme->editor_css_content(); | |
78 | store_css($candidatesheet, $css); | |
79 | } else { | |
80 | $css = $theme->css_content(); | |
81 | foreach ($css as $key=>$value) { | |
82 | $sheet = ''; | |
83 | foreach($value as $val) { | |
84 | if (is_array($val)) { | |
e10f304d PS |
85 | foreach ($val as $k=>$v) { |
86 | $sheet .= compress_css($v)."\n"; | |
87 | } | |
78946b9b | 88 | } else { |
e10f304d | 89 | $sheet .= compress_css($val)."\n"; |
78946b9b PS |
90 | } |
91 | } | |
92 | $css[$key] = $sheet; | |
93 | $cssfile = "$CFG->dataroot/cache/theme/$themename/css/$key.css"; | |
94 | store_css($cssfile, $sheet); | |
fdeb7fa1 | 95 | } |
78946b9b PS |
96 | $css = implode('', $css); |
97 | $cssfile = "$CFG->dataroot/cache/theme/$themename/css/all.css"; | |
98 | store_css($cssfile, $css); | |
fdeb7fa1 | 99 | } |
100 | ||
78946b9b | 101 | send_cached_css($candidatesheet, $rev); |
b7009474 | 102 | |
b7009474 | 103 | |
78946b9b PS |
104 | //================================================================================= |
105 | //=== utility functions == | |
106 | // we are not using filelib because we need to fine tune all header | |
107 | // parameters to get the best performance. | |
b7009474 | 108 | |
78946b9b PS |
109 | function store_css($csspath, $css) { |
110 | check_dir_exists(dirname($csspath), true, true); | |
111 | $fp = fopen($csspath, 'w'); | |
112 | fwrite($fp, $css); | |
113 | fclose($fp); | |
b7009474 | 114 | } |
115 | ||
78946b9b PS |
116 | function send_ie_css($themename, $rev) { |
117 | $lifetime = 60*60*24*3; | |
118 | ||
119 | $css = <<<EOF | |
120 | /** Unfortunately IE6/7 does not support more than 4096 selectors in one CSS file, which means we have to use some ugly hacks :-( **/ | |
78946b9b PS |
121 | @import url(styles.php?theme=$themename&rev=$rev&type=plugins); |
122 | @import url(styles.php?theme=$themename&rev=$rev&type=parents); | |
123 | @import url(styles.php?theme=$themename&rev=$rev&type=theme); | |
124 | ||
125 | EOF; | |
126 | ||
127 | header('Etag: '.md5($rev)); | |
128 | header('Content-Disposition: inline; filename="styles.php"'); | |
129 | header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT'); | |
130 | header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); | |
131 | header('Pragma: '); | |
132 | header('Accept-Ranges: none'); | |
133 | header('Content-Type: text/css'); | |
e10f304d | 134 | header('Content-Length: '.strlen($css)); |
78946b9b | 135 | |
78946b9b PS |
136 | echo $css; |
137 | die; | |
b7009474 | 138 | } |
b7009474 | 139 | |
78946b9b PS |
140 | function send_cached_css($csspath, $rev) { |
141 | $lifetime = 60*60*24*20; | |
b7009474 | 142 | |
78946b9b PS |
143 | header('Content-Disposition: inline; filename="styles.php"'); |
144 | header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($csspath)) .' GMT'); | |
145 | header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); | |
146 | header('Pragma: '); | |
147 | header('Accept-Ranges: none'); | |
148 | header('Content-Type: text/css'); | |
7c986f04 PS |
149 | if (!min_enable_zlib_compression()) { |
150 | header('Content-Length: '.filesize($csspath)); | |
151 | } | |
b7009474 | 152 | |
78946b9b PS |
153 | readfile($csspath); |
154 | die; | |
b7009474 | 155 | } |
e10f304d PS |
156 | |
157 | function compress_css($css) { | |
158 | // remove comments - credit for this regex goes to "reinhold weber" | |
159 | $css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css); | |
160 | ||
161 | // replace newlines, tabs, etc. | |
162 | $css = str_replace(array("\r\n", "\r", "\n", "\t"), ' ', $css); | |
163 | ||
164 | // replace repeated spaces | |
165 | $css = preg_replace('/ +/', ' ', $css); | |
166 | ||
167 | // fix whitespace around separators | |
168 | $css = preg_replace('/ ([;,:\{\}])/', '$1', $css); | |
169 | $css = preg_replace('/([;,:\{\}]) /', '$1', $css); | |
170 | ||
171 | $css = str_replace('url (', 'url(', $css); | |
172 | ||
173 | return $css; | |
174 | } |