webmaster@1
|
1 <?php |
franck@19
|
2 // $Id: bootstrap.inc,v 1.206.2.9 2009/01/14 19:10:25 goba Exp $ |
webmaster@1
|
3 |
webmaster@1
|
4 /** |
webmaster@1
|
5 * @file |
webmaster@1
|
6 * Functions that need to be loaded on every Drupal request. |
webmaster@1
|
7 */ |
webmaster@1
|
8 |
webmaster@1
|
9 /** |
webmaster@1
|
10 * Indicates that the item should never be removed unless explicitly told to |
webmaster@1
|
11 * using cache_clear_all() with a cache ID. |
webmaster@1
|
12 */ |
webmaster@1
|
13 define('CACHE_PERMANENT', 0); |
webmaster@1
|
14 |
webmaster@1
|
15 /** |
webmaster@1
|
16 * Indicates that the item should be removed at the next general cache wipe. |
webmaster@1
|
17 */ |
webmaster@1
|
18 define('CACHE_TEMPORARY', -1); |
webmaster@1
|
19 |
webmaster@1
|
20 /** |
webmaster@1
|
21 * Indicates that page caching is disabled. |
webmaster@1
|
22 */ |
webmaster@1
|
23 define('CACHE_DISABLED', 0); |
webmaster@1
|
24 |
webmaster@1
|
25 /** |
webmaster@1
|
26 * Indicates that page caching is enabled, using "normal" mode. |
webmaster@1
|
27 */ |
webmaster@1
|
28 define('CACHE_NORMAL', 1); |
webmaster@1
|
29 |
webmaster@1
|
30 /** |
webmaster@1
|
31 * Indicates that page caching is using "aggressive" mode. This bypasses |
webmaster@1
|
32 * loading any modules for additional speed, which may break functionality in |
webmaster@1
|
33 * modules that expect to be run on each page load. |
webmaster@1
|
34 */ |
webmaster@1
|
35 define('CACHE_AGGRESSIVE', 2); |
webmaster@1
|
36 |
webmaster@1
|
37 /** |
webmaster@1
|
38 * |
webmaster@1
|
39 * Severity levels, as defined in RFC 3164 http://www.faqs.org/rfcs/rfc3164.html |
webmaster@1
|
40 * @see watchdog() |
webmaster@1
|
41 * @see watchdog_severity_levels() |
webmaster@1
|
42 */ |
webmaster@1
|
43 define('WATCHDOG_EMERG', 0); // Emergency: system is unusable |
webmaster@1
|
44 define('WATCHDOG_ALERT', 1); // Alert: action must be taken immediately |
webmaster@1
|
45 define('WATCHDOG_CRITICAL', 2); // Critical: critical conditions |
webmaster@1
|
46 define('WATCHDOG_ERROR', 3); // Error: error conditions |
webmaster@1
|
47 define('WATCHDOG_WARNING', 4); // Warning: warning conditions |
webmaster@1
|
48 define('WATCHDOG_NOTICE', 5); // Notice: normal but significant condition |
webmaster@1
|
49 define('WATCHDOG_INFO', 6); // Informational: informational messages |
webmaster@1
|
50 define('WATCHDOG_DEBUG', 7); // Debug: debug-level messages |
webmaster@1
|
51 |
webmaster@1
|
52 /** |
webmaster@1
|
53 * First bootstrap phase: initialize configuration. |
webmaster@1
|
54 */ |
webmaster@1
|
55 define('DRUPAL_BOOTSTRAP_CONFIGURATION', 0); |
webmaster@1
|
56 |
webmaster@1
|
57 /** |
webmaster@1
|
58 * Second bootstrap phase: try to call a non-database cache |
webmaster@1
|
59 * fetch routine. |
webmaster@1
|
60 */ |
webmaster@1
|
61 define('DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE', 1); |
webmaster@1
|
62 |
webmaster@1
|
63 /** |
webmaster@1
|
64 * Third bootstrap phase: initialize database layer. |
webmaster@1
|
65 */ |
webmaster@1
|
66 define('DRUPAL_BOOTSTRAP_DATABASE', 2); |
webmaster@1
|
67 |
webmaster@1
|
68 /** |
webmaster@1
|
69 * Fourth bootstrap phase: identify and reject banned hosts. |
webmaster@1
|
70 */ |
webmaster@1
|
71 define('DRUPAL_BOOTSTRAP_ACCESS', 3); |
webmaster@1
|
72 |
webmaster@1
|
73 /** |
webmaster@1
|
74 * Fifth bootstrap phase: initialize session handling. |
webmaster@1
|
75 */ |
webmaster@1
|
76 define('DRUPAL_BOOTSTRAP_SESSION', 4); |
webmaster@1
|
77 |
webmaster@1
|
78 /** |
webmaster@1
|
79 * Sixth bootstrap phase: load bootstrap.inc and module.inc, start |
webmaster@1
|
80 * the variable system and try to serve a page from the cache. |
webmaster@1
|
81 */ |
webmaster@1
|
82 define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 5); |
webmaster@1
|
83 |
webmaster@1
|
84 /** |
webmaster@1
|
85 * Seventh bootstrap phase: find out language of the page. |
webmaster@1
|
86 */ |
webmaster@1
|
87 define('DRUPAL_BOOTSTRAP_LANGUAGE', 6); |
webmaster@1
|
88 |
webmaster@1
|
89 /** |
webmaster@1
|
90 * Eighth bootstrap phase: set $_GET['q'] to Drupal path of request. |
webmaster@1
|
91 */ |
webmaster@1
|
92 define('DRUPAL_BOOTSTRAP_PATH', 7); |
webmaster@1
|
93 |
webmaster@1
|
94 /** |
webmaster@1
|
95 * Final bootstrap phase: Drupal is fully loaded; validate and fix |
webmaster@1
|
96 * input data. |
webmaster@1
|
97 */ |
webmaster@1
|
98 define('DRUPAL_BOOTSTRAP_FULL', 8); |
webmaster@1
|
99 |
webmaster@1
|
100 /** |
webmaster@1
|
101 * Role ID for anonymous users; should match what's in the "role" table. |
webmaster@1
|
102 */ |
webmaster@1
|
103 define('DRUPAL_ANONYMOUS_RID', 1); |
webmaster@1
|
104 |
webmaster@1
|
105 /** |
webmaster@1
|
106 * Role ID for authenticated users; should match what's in the "role" table. |
webmaster@1
|
107 */ |
webmaster@1
|
108 define('DRUPAL_AUTHENTICATED_RID', 2); |
webmaster@1
|
109 |
webmaster@1
|
110 /** |
webmaster@1
|
111 * No language negotiation. The default language is used. |
webmaster@1
|
112 */ |
webmaster@1
|
113 define('LANGUAGE_NEGOTIATION_NONE', 0); |
webmaster@1
|
114 |
webmaster@1
|
115 /** |
webmaster@1
|
116 * Path based negotiation with fallback to default language |
webmaster@1
|
117 * if no defined path prefix identified. |
webmaster@1
|
118 */ |
webmaster@1
|
119 define('LANGUAGE_NEGOTIATION_PATH_DEFAULT', 1); |
webmaster@1
|
120 |
webmaster@1
|
121 /** |
webmaster@1
|
122 * Path based negotiation with fallback to user preferences |
webmaster@1
|
123 * and browser language detection if no defined path prefix |
webmaster@1
|
124 * identified. |
webmaster@1
|
125 */ |
webmaster@1
|
126 define('LANGUAGE_NEGOTIATION_PATH', 2); |
webmaster@1
|
127 |
webmaster@1
|
128 /** |
webmaster@1
|
129 * Domain based negotiation with fallback to default language |
webmaster@1
|
130 * if no language identified by domain. |
webmaster@1
|
131 */ |
webmaster@1
|
132 define('LANGUAGE_NEGOTIATION_DOMAIN', 3); |
webmaster@1
|
133 |
webmaster@1
|
134 /** |
webmaster@1
|
135 * Start the timer with the specified name. If you start and stop |
webmaster@1
|
136 * the same timer multiple times, the measured intervals will be |
webmaster@1
|
137 * accumulated. |
webmaster@1
|
138 * |
webmaster@1
|
139 * @param name |
webmaster@1
|
140 * The name of the timer. |
webmaster@1
|
141 */ |
webmaster@1
|
142 function timer_start($name) { |
webmaster@1
|
143 global $timers; |
webmaster@1
|
144 |
webmaster@1
|
145 list($usec, $sec) = explode(' ', microtime()); |
webmaster@1
|
146 $timers[$name]['start'] = (float)$usec + (float)$sec; |
webmaster@1
|
147 $timers[$name]['count'] = isset($timers[$name]['count']) ? ++$timers[$name]['count'] : 1; |
webmaster@1
|
148 } |
webmaster@1
|
149 |
webmaster@1
|
150 /** |
webmaster@1
|
151 * Read the current timer value without stopping the timer. |
webmaster@1
|
152 * |
webmaster@1
|
153 * @param name |
webmaster@1
|
154 * The name of the timer. |
webmaster@1
|
155 * @return |
webmaster@1
|
156 * The current timer value in ms. |
webmaster@1
|
157 */ |
webmaster@1
|
158 function timer_read($name) { |
webmaster@1
|
159 global $timers; |
webmaster@1
|
160 |
webmaster@1
|
161 if (isset($timers[$name]['start'])) { |
webmaster@1
|
162 list($usec, $sec) = explode(' ', microtime()); |
webmaster@1
|
163 $stop = (float)$usec + (float)$sec; |
webmaster@1
|
164 $diff = round(($stop - $timers[$name]['start']) * 1000, 2); |
webmaster@1
|
165 |
webmaster@1
|
166 if (isset($timers[$name]['time'])) { |
webmaster@1
|
167 $diff += $timers[$name]['time']; |
webmaster@1
|
168 } |
webmaster@1
|
169 return $diff; |
webmaster@1
|
170 } |
webmaster@1
|
171 } |
webmaster@1
|
172 |
webmaster@1
|
173 /** |
webmaster@1
|
174 * Stop the timer with the specified name. |
webmaster@1
|
175 * |
webmaster@1
|
176 * @param name |
webmaster@1
|
177 * The name of the timer. |
webmaster@1
|
178 * @return |
webmaster@1
|
179 * A timer array. The array contains the number of times the |
webmaster@1
|
180 * timer has been started and stopped (count) and the accumulated |
webmaster@1
|
181 * timer value in ms (time). |
webmaster@1
|
182 */ |
webmaster@1
|
183 function timer_stop($name) { |
webmaster@1
|
184 global $timers; |
webmaster@1
|
185 |
webmaster@1
|
186 $timers[$name]['time'] = timer_read($name); |
webmaster@1
|
187 unset($timers[$name]['start']); |
webmaster@1
|
188 |
webmaster@1
|
189 return $timers[$name]; |
webmaster@1
|
190 } |
webmaster@1
|
191 |
webmaster@1
|
192 /** |
webmaster@1
|
193 * Find the appropriate configuration directory. |
webmaster@1
|
194 * |
webmaster@1
|
195 * Try finding a matching configuration directory by stripping the website's |
webmaster@1
|
196 * hostname from left to right and pathname from right to left. The first |
webmaster@1
|
197 * configuration file found will be used; the remaining will ignored. If no |
webmaster@1
|
198 * configuration file is found, return a default value '$confdir/default'. |
webmaster@1
|
199 * |
webmaster@1
|
200 * Example for a fictitious site installed at |
webmaster@1
|
201 * http://www.drupal.org:8080/mysite/test/ the 'settings.php' is searched in |
webmaster@1
|
202 * the following directories: |
webmaster@1
|
203 * |
webmaster@1
|
204 * 1. $confdir/8080.www.drupal.org.mysite.test |
webmaster@1
|
205 * 2. $confdir/www.drupal.org.mysite.test |
webmaster@1
|
206 * 3. $confdir/drupal.org.mysite.test |
webmaster@1
|
207 * 4. $confdir/org.mysite.test |
webmaster@1
|
208 * |
webmaster@1
|
209 * 5. $confdir/8080.www.drupal.org.mysite |
webmaster@1
|
210 * 6. $confdir/www.drupal.org.mysite |
webmaster@1
|
211 * 7. $confdir/drupal.org.mysite |
webmaster@1
|
212 * 8. $confdir/org.mysite |
webmaster@1
|
213 * |
webmaster@1
|
214 * 9. $confdir/8080.www.drupal.org |
webmaster@1
|
215 * 10. $confdir/www.drupal.org |
webmaster@1
|
216 * 11. $confdir/drupal.org |
webmaster@1
|
217 * 12. $confdir/org |
webmaster@1
|
218 * |
webmaster@1
|
219 * 13. $confdir/default |
webmaster@1
|
220 * |
webmaster@1
|
221 * @param $require_settings |
webmaster@1
|
222 * Only configuration directories with an existing settings.php file |
webmaster@1
|
223 * will be recognized. Defaults to TRUE. During initial installation, |
webmaster@1
|
224 * this is set to FALSE so that Drupal can detect a matching directory, |
webmaster@1
|
225 * then create a new settings.php file in it. |
webmaster@1
|
226 * @param reset |
webmaster@1
|
227 * Force a full search for matching directories even if one had been |
webmaster@1
|
228 * found previously. |
webmaster@1
|
229 * @return |
webmaster@1
|
230 * The path of the matching directory. |
webmaster@1
|
231 */ |
webmaster@1
|
232 function conf_path($require_settings = TRUE, $reset = FALSE) { |
webmaster@1
|
233 static $conf = ''; |
webmaster@1
|
234 |
webmaster@1
|
235 if ($conf && !$reset) { |
webmaster@1
|
236 return $conf; |
webmaster@1
|
237 } |
webmaster@1
|
238 |
webmaster@1
|
239 $confdir = 'sites'; |
webmaster@1
|
240 $uri = explode('/', $_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['SCRIPT_FILENAME']); |
webmaster@1
|
241 $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.'))))); |
webmaster@1
|
242 for ($i = count($uri) - 1; $i > 0; $i--) { |
webmaster@1
|
243 for ($j = count($server); $j > 0; $j--) { |
webmaster@1
|
244 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i)); |
webmaster@1
|
245 if (file_exists("$confdir/$dir/settings.php") || (!$require_settings && file_exists("$confdir/$dir"))) { |
webmaster@1
|
246 $conf = "$confdir/$dir"; |
webmaster@1
|
247 return $conf; |
webmaster@1
|
248 } |
webmaster@1
|
249 } |
webmaster@1
|
250 } |
webmaster@1
|
251 $conf = "$confdir/default"; |
webmaster@1
|
252 return $conf; |
webmaster@1
|
253 } |
webmaster@1
|
254 |
webmaster@1
|
255 /** |
webmaster@1
|
256 * Unsets all disallowed global variables. See $allowed for what's allowed. |
webmaster@1
|
257 */ |
webmaster@1
|
258 function drupal_unset_globals() { |
webmaster@1
|
259 if (ini_get('register_globals')) { |
webmaster@1
|
260 $allowed = array('_ENV' => 1, '_GET' => 1, '_POST' => 1, '_COOKIE' => 1, '_FILES' => 1, '_SERVER' => 1, '_REQUEST' => 1, 'GLOBALS' => 1); |
webmaster@1
|
261 foreach ($GLOBALS as $key => $value) { |
webmaster@1
|
262 if (!isset($allowed[$key])) { |
webmaster@1
|
263 unset($GLOBALS[$key]); |
webmaster@1
|
264 } |
webmaster@1
|
265 } |
webmaster@1
|
266 } |
webmaster@1
|
267 } |
webmaster@1
|
268 |
webmaster@1
|
269 /** |
franck@19
|
270 * Validate that a hostname (for example $_SERVER['HTTP_HOST']) is safe. |
webmaster@15
|
271 * |
webmaster@15
|
272 * As $_SERVER['HTTP_HOST'] is user input, ensure it only contains characters |
webmaster@15
|
273 * allowed in hostnames. See RFC 952 (and RFC 2181). $_SERVER['HTTP_HOST'] is |
webmaster@15
|
274 * lowercased. |
webmaster@15
|
275 * |
webmaster@15
|
276 * @return |
webmaster@15
|
277 * TRUE if only containing valid characters, or FALSE otherwise. |
webmaster@15
|
278 */ |
franck@19
|
279 function drupal_valid_http_host($host) { |
franck@19
|
280 return preg_match('/^\[?(?:[a-z0-9-:\]_]+\.?)+$/', $host); |
webmaster@15
|
281 } |
webmaster@15
|
282 |
webmaster@15
|
283 /** |
webmaster@1
|
284 * Loads the configuration and sets the base URL, cookie domain, and |
webmaster@1
|
285 * session name correctly. |
webmaster@1
|
286 */ |
webmaster@1
|
287 function conf_init() { |
webmaster@1
|
288 global $base_url, $base_path, $base_root; |
webmaster@1
|
289 |
webmaster@1
|
290 // Export the following settings.php variables to the global namespace |
webmaster@1
|
291 global $db_url, $db_prefix, $cookie_domain, $conf, $installed_profile, $update_free_access; |
webmaster@1
|
292 $conf = array(); |
webmaster@1
|
293 |
franck@19
|
294 if (isset($_SERVER['HTTP_HOST'])) { |
franck@19
|
295 // As HTTP_HOST is user input, ensure it only contains characters allowed |
franck@19
|
296 // in hostnames. See RFC 952 (and RFC 2181). |
franck@19
|
297 // $_SERVER['HTTP_HOST'] is lowercased here per specifications. |
franck@19
|
298 $_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']); |
franck@19
|
299 if (!drupal_valid_http_host($_SERVER['HTTP_HOST'])) { |
franck@19
|
300 // HTTP_HOST is invalid, e.g. if containing slashes it may be an attack. |
franck@19
|
301 header('HTTP/1.1 400 Bad Request'); |
franck@19
|
302 exit; |
franck@19
|
303 } |
franck@19
|
304 } |
franck@19
|
305 else { |
franck@19
|
306 // Some pre-HTTP/1.1 clients will not send a Host header. Ensure the key is |
franck@19
|
307 // defined for E_ALL compliance. |
franck@19
|
308 $_SERVER['HTTP_HOST'] = ''; |
webmaster@15
|
309 } |
webmaster@15
|
310 |
webmaster@1
|
311 if (file_exists('./'. conf_path() .'/settings.php')) { |
webmaster@1
|
312 include_once './'. conf_path() .'/settings.php'; |
webmaster@1
|
313 } |
webmaster@1
|
314 |
webmaster@7
|
315 // Ignore the placeholder url from default.settings.php. |
webmaster@7
|
316 if (isset($db_url) && $db_url == 'mysql://username:password@localhost/databasename') { |
webmaster@7
|
317 $db_url = ''; |
webmaster@7
|
318 } |
webmaster@7
|
319 |
webmaster@1
|
320 if (isset($base_url)) { |
webmaster@1
|
321 // Parse fixed base URL from settings.php. |
webmaster@1
|
322 $parts = parse_url($base_url); |
webmaster@1
|
323 if (!isset($parts['path'])) { |
webmaster@1
|
324 $parts['path'] = ''; |
webmaster@1
|
325 } |
webmaster@1
|
326 $base_path = $parts['path'] .'/'; |
webmaster@1
|
327 // Build $base_root (everything until first slash after "scheme://"). |
webmaster@1
|
328 $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path'])); |
webmaster@1
|
329 } |
webmaster@1
|
330 else { |
webmaster@1
|
331 // Create base URL |
webmaster@1
|
332 $base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; |
webmaster@1
|
333 |
webmaster@15
|
334 $base_url = $base_root .= '://'. $_SERVER['HTTP_HOST']; |
webmaster@1
|
335 |
webmaster@1
|
336 // $_SERVER['SCRIPT_NAME'] can, in contrast to $_SERVER['PHP_SELF'], not |
webmaster@1
|
337 // be modified by a visitor. |
webmaster@1
|
338 if ($dir = trim(dirname($_SERVER['SCRIPT_NAME']), '\,/')) { |
webmaster@1
|
339 $base_path = "/$dir"; |
webmaster@1
|
340 $base_url .= $base_path; |
webmaster@1
|
341 $base_path .= '/'; |
webmaster@1
|
342 } |
webmaster@1
|
343 else { |
webmaster@1
|
344 $base_path = '/'; |
webmaster@1
|
345 } |
webmaster@1
|
346 } |
webmaster@1
|
347 |
webmaster@1
|
348 if ($cookie_domain) { |
webmaster@1
|
349 // If the user specifies the cookie domain, also use it for session name. |
webmaster@1
|
350 $session_name = $cookie_domain; |
webmaster@1
|
351 } |
webmaster@1
|
352 else { |
webmaster@1
|
353 // Otherwise use $base_url as session name, without the protocol |
webmaster@1
|
354 // to use the same session identifiers across http and https. |
webmaster@1
|
355 list( , $session_name) = explode('://', $base_url, 2); |
webmaster@1
|
356 // We escape the hostname because it can be modified by a visitor. |
webmaster@1
|
357 if (!empty($_SERVER['HTTP_HOST'])) { |
webmaster@1
|
358 $cookie_domain = check_plain($_SERVER['HTTP_HOST']); |
webmaster@1
|
359 } |
webmaster@1
|
360 } |
webmaster@11
|
361 // To prevent session cookies from being hijacked, a user can configure the |
webmaster@11
|
362 // SSL version of their website to only transfer session cookies via SSL by |
webmaster@11
|
363 // using PHP's session.cookie_secure setting. The browser will then use two |
webmaster@11
|
364 // separate session cookies for the HTTPS and HTTP versions of the site. So we |
webmaster@11
|
365 // must use different session identifiers for HTTPS and HTTP to prevent a |
webmaster@11
|
366 // cookie collision. |
webmaster@11
|
367 if (ini_get('session.cookie_secure')) { |
webmaster@11
|
368 $session_name .= 'SSL'; |
webmaster@11
|
369 } |
webmaster@1
|
370 // Strip leading periods, www., and port numbers from cookie domain. |
webmaster@1
|
371 $cookie_domain = ltrim($cookie_domain, '.'); |
webmaster@1
|
372 if (strpos($cookie_domain, 'www.') === 0) { |
webmaster@1
|
373 $cookie_domain = substr($cookie_domain, 4); |
webmaster@1
|
374 } |
webmaster@1
|
375 $cookie_domain = explode(':', $cookie_domain); |
webmaster@1
|
376 $cookie_domain = '.'. $cookie_domain[0]; |
webmaster@1
|
377 // Per RFC 2109, cookie domains must contain at least one dot other than the |
webmaster@1
|
378 // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain. |
webmaster@1
|
379 if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) { |
webmaster@1
|
380 ini_set('session.cookie_domain', $cookie_domain); |
webmaster@1
|
381 } |
webmaster@1
|
382 session_name('SESS'. md5($session_name)); |
webmaster@1
|
383 } |
webmaster@1
|
384 |
webmaster@1
|
385 /** |
webmaster@1
|
386 * Returns and optionally sets the filename for a system item (module, |
webmaster@1
|
387 * theme, etc.). The filename, whether provided, cached, or retrieved |
webmaster@1
|
388 * from the database, is only returned if the file exists. |
webmaster@1
|
389 * |
webmaster@1
|
390 * This function plays a key role in allowing Drupal's resources (modules |
webmaster@1
|
391 * and themes) to be located in different places depending on a site's |
webmaster@1
|
392 * configuration. For example, a module 'foo' may legally be be located |
webmaster@1
|
393 * in any of these three places: |
webmaster@1
|
394 * |
webmaster@1
|
395 * modules/foo/foo.module |
webmaster@1
|
396 * sites/all/modules/foo/foo.module |
webmaster@1
|
397 * sites/example.com/modules/foo/foo.module |
webmaster@1
|
398 * |
webmaster@1
|
399 * Calling drupal_get_filename('module', 'foo') will give you one of |
webmaster@1
|
400 * the above, depending on where the module is located. |
webmaster@1
|
401 * |
webmaster@1
|
402 * @param $type |
webmaster@1
|
403 * The type of the item (i.e. theme, theme_engine, module). |
webmaster@1
|
404 * @param $name |
webmaster@1
|
405 * The name of the item for which the filename is requested. |
webmaster@1
|
406 * @param $filename |
webmaster@1
|
407 * The filename of the item if it is to be set explicitly rather |
webmaster@1
|
408 * than by consulting the database. |
webmaster@1
|
409 * |
webmaster@1
|
410 * @return |
webmaster@1
|
411 * The filename of the requested item. |
webmaster@1
|
412 */ |
webmaster@1
|
413 function drupal_get_filename($type, $name, $filename = NULL) { |
webmaster@1
|
414 static $files = array(); |
webmaster@1
|
415 |
webmaster@1
|
416 if (!isset($files[$type])) { |
webmaster@1
|
417 $files[$type] = array(); |
webmaster@1
|
418 } |
webmaster@1
|
419 |
webmaster@1
|
420 if (!empty($filename) && file_exists($filename)) { |
webmaster@1
|
421 $files[$type][$name] = $filename; |
webmaster@1
|
422 } |
webmaster@1
|
423 elseif (isset($files[$type][$name])) { |
webmaster@1
|
424 // nothing |
webmaster@1
|
425 } |
webmaster@1
|
426 // Verify that we have an active database connection, before querying |
webmaster@1
|
427 // the database. This is required because this function is called both |
webmaster@1
|
428 // before we have a database connection (i.e. during installation) and |
webmaster@1
|
429 // when a database connection fails. |
webmaster@1
|
430 elseif (db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) { |
webmaster@1
|
431 $files[$type][$name] = $file; |
webmaster@1
|
432 } |
webmaster@1
|
433 else { |
webmaster@1
|
434 // Fallback to searching the filesystem if the database connection is |
webmaster@1
|
435 // not established or the requested file is not found. |
webmaster@1
|
436 $config = conf_path(); |
webmaster@1
|
437 $dir = (($type == 'theme_engine') ? 'themes/engines' : "${type}s"); |
webmaster@1
|
438 $file = (($type == 'theme_engine') ? "$name.engine" : "$name.$type"); |
webmaster@1
|
439 |
webmaster@1
|
440 foreach (array("$config/$dir/$file", "$config/$dir/$name/$file", "$dir/$file", "$dir/$name/$file") as $file) { |
webmaster@1
|
441 if (file_exists($file)) { |
webmaster@1
|
442 $files[$type][$name] = $file; |
webmaster@1
|
443 break; |
webmaster@1
|
444 } |
webmaster@1
|
445 } |
webmaster@1
|
446 } |
webmaster@1
|
447 |
webmaster@1
|
448 if (isset($files[$type][$name])) { |
webmaster@1
|
449 return $files[$type][$name]; |
webmaster@1
|
450 } |
webmaster@1
|
451 } |
webmaster@1
|
452 |
webmaster@1
|
453 /** |
webmaster@1
|
454 * Load the persistent variable table. |
webmaster@1
|
455 * |
webmaster@1
|
456 * The variable table is composed of values that have been saved in the table |
webmaster@1
|
457 * with variable_set() as well as those explicitly specified in the configuration |
webmaster@1
|
458 * file. |
webmaster@1
|
459 */ |
webmaster@1
|
460 function variable_init($conf = array()) { |
webmaster@1
|
461 // NOTE: caching the variables improves performance by 20% when serving cached pages. |
webmaster@1
|
462 if ($cached = cache_get('variables', 'cache')) { |
webmaster@1
|
463 $variables = $cached->data; |
webmaster@1
|
464 } |
webmaster@1
|
465 else { |
webmaster@1
|
466 $result = db_query('SELECT * FROM {variable}'); |
webmaster@1
|
467 while ($variable = db_fetch_object($result)) { |
webmaster@1
|
468 $variables[$variable->name] = unserialize($variable->value); |
webmaster@1
|
469 } |
webmaster@1
|
470 cache_set('variables', $variables); |
webmaster@1
|
471 } |
webmaster@1
|
472 |
webmaster@1
|
473 foreach ($conf as $name => $value) { |
webmaster@1
|
474 $variables[$name] = $value; |
webmaster@1
|
475 } |
webmaster@1
|
476 |
webmaster@1
|
477 return $variables; |
webmaster@1
|
478 } |
webmaster@1
|
479 |
webmaster@1
|
480 /** |
webmaster@1
|
481 * Return a persistent variable. |
webmaster@1
|
482 * |
webmaster@1
|
483 * @param $name |
webmaster@1
|
484 * The name of the variable to return. |
webmaster@1
|
485 * @param $default |
webmaster@1
|
486 * The default value to use if this variable has never been set. |
webmaster@1
|
487 * @return |
webmaster@1
|
488 * The value of the variable. |
webmaster@1
|
489 */ |
webmaster@1
|
490 function variable_get($name, $default) { |
webmaster@1
|
491 global $conf; |
webmaster@1
|
492 |
webmaster@1
|
493 return isset($conf[$name]) ? $conf[$name] : $default; |
webmaster@1
|
494 } |
webmaster@1
|
495 |
webmaster@1
|
496 /** |
webmaster@1
|
497 * Set a persistent variable. |
webmaster@1
|
498 * |
webmaster@1
|
499 * @param $name |
webmaster@1
|
500 * The name of the variable to set. |
webmaster@1
|
501 * @param $value |
webmaster@1
|
502 * The value to set. This can be any PHP data type; these functions take care |
webmaster@1
|
503 * of serialization as necessary. |
webmaster@1
|
504 */ |
webmaster@1
|
505 function variable_set($name, $value) { |
webmaster@1
|
506 global $conf; |
webmaster@1
|
507 |
webmaster@1
|
508 $serialized_value = serialize($value); |
webmaster@1
|
509 db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name); |
webmaster@1
|
510 if (!db_affected_rows()) { |
webmaster@1
|
511 @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value); |
webmaster@1
|
512 } |
webmaster@1
|
513 |
webmaster@1
|
514 cache_clear_all('variables', 'cache'); |
webmaster@1
|
515 |
webmaster@1
|
516 $conf[$name] = $value; |
webmaster@1
|
517 } |
webmaster@1
|
518 |
webmaster@1
|
519 /** |
webmaster@1
|
520 * Unset a persistent variable. |
webmaster@1
|
521 * |
webmaster@1
|
522 * @param $name |
webmaster@1
|
523 * The name of the variable to undefine. |
webmaster@1
|
524 */ |
webmaster@1
|
525 function variable_del($name) { |
webmaster@1
|
526 global $conf; |
webmaster@1
|
527 |
webmaster@1
|
528 db_query("DELETE FROM {variable} WHERE name = '%s'", $name); |
webmaster@1
|
529 cache_clear_all('variables', 'cache'); |
webmaster@1
|
530 |
webmaster@1
|
531 unset($conf[$name]); |
webmaster@1
|
532 } |
webmaster@1
|
533 |
webmaster@1
|
534 |
webmaster@1
|
535 /** |
webmaster@1
|
536 * Retrieve the current page from the cache. |
webmaster@1
|
537 * |
webmaster@1
|
538 * Note: we do not serve cached pages when status messages are waiting (from |
webmaster@1
|
539 * a redirected form submission which was completed). |
webmaster@1
|
540 * |
webmaster@1
|
541 * @param $status_only |
webmaster@1
|
542 * When set to TRUE, retrieve the status of the page cache only |
webmaster@1
|
543 * (whether it was started in this request or not). |
webmaster@1
|
544 */ |
webmaster@1
|
545 function page_get_cache($status_only = FALSE) { |
webmaster@1
|
546 static $status = FALSE; |
webmaster@1
|
547 global $user, $base_root; |
webmaster@1
|
548 |
webmaster@1
|
549 if ($status_only) { |
webmaster@1
|
550 return $status; |
webmaster@1
|
551 } |
webmaster@1
|
552 $cache = NULL; |
webmaster@1
|
553 |
webmaster@1
|
554 if (!$user->uid && $_SERVER['REQUEST_METHOD'] == 'GET' && count(drupal_set_message()) == 0) { |
webmaster@1
|
555 $cache = cache_get($base_root . request_uri(), 'cache_page'); |
webmaster@1
|
556 |
webmaster@1
|
557 if (empty($cache)) { |
webmaster@1
|
558 ob_start(); |
webmaster@1
|
559 $status = TRUE; |
webmaster@1
|
560 } |
webmaster@1
|
561 } |
webmaster@1
|
562 |
webmaster@1
|
563 return $cache; |
webmaster@1
|
564 } |
webmaster@1
|
565 |
webmaster@1
|
566 /** |
webmaster@1
|
567 * Call all init or exit hooks without including all modules. |
webmaster@1
|
568 * |
webmaster@1
|
569 * @param $hook |
webmaster@1
|
570 * The name of the bootstrap hook we wish to invoke. |
webmaster@1
|
571 */ |
webmaster@1
|
572 function bootstrap_invoke_all($hook) { |
webmaster@1
|
573 foreach (module_list(TRUE, TRUE) as $module) { |
webmaster@1
|
574 drupal_load('module', $module); |
webmaster@1
|
575 module_invoke($module, $hook); |
webmaster@1
|
576 } |
webmaster@1
|
577 } |
webmaster@1
|
578 |
webmaster@1
|
579 /** |
webmaster@1
|
580 * Includes a file with the provided type and name. This prevents |
webmaster@1
|
581 * including a theme, engine, module, etc., more than once. |
webmaster@1
|
582 * |
webmaster@1
|
583 * @param $type |
webmaster@1
|
584 * The type of item to load (i.e. theme, theme_engine, module). |
webmaster@1
|
585 * @param $name |
webmaster@1
|
586 * The name of the item to load. |
webmaster@1
|
587 * |
webmaster@1
|
588 * @return |
webmaster@1
|
589 * TRUE if the item is loaded or has already been loaded. |
webmaster@1
|
590 */ |
webmaster@1
|
591 function drupal_load($type, $name) { |
webmaster@1
|
592 static $files = array(); |
webmaster@1
|
593 |
webmaster@1
|
594 if (isset($files[$type][$name])) { |
webmaster@1
|
595 return TRUE; |
webmaster@1
|
596 } |
webmaster@1
|
597 |
webmaster@1
|
598 $filename = drupal_get_filename($type, $name); |
webmaster@1
|
599 |
webmaster@1
|
600 if ($filename) { |
webmaster@1
|
601 include_once "./$filename"; |
webmaster@1
|
602 $files[$type][$name] = TRUE; |
webmaster@1
|
603 |
webmaster@1
|
604 return TRUE; |
webmaster@1
|
605 } |
webmaster@1
|
606 |
webmaster@1
|
607 return FALSE; |
webmaster@1
|
608 } |
webmaster@1
|
609 |
webmaster@1
|
610 /** |
webmaster@1
|
611 * Set HTTP headers in preparation for a page response. |
webmaster@1
|
612 * |
webmaster@1
|
613 * Authenticated users are always given a 'no-cache' header, and will |
webmaster@1
|
614 * fetch a fresh page on every request. This prevents authenticated |
webmaster@1
|
615 * users seeing locally cached pages that show them as logged out. |
webmaster@1
|
616 * |
webmaster@1
|
617 * @see page_set_cache() |
webmaster@1
|
618 */ |
webmaster@1
|
619 function drupal_page_header() { |
webmaster@1
|
620 header("Expires: Sun, 19 Nov 1978 05:00:00 GMT"); |
webmaster@1
|
621 header("Last-Modified: ". gmdate("D, d M Y H:i:s") ." GMT"); |
webmaster@1
|
622 header("Cache-Control: store, no-cache, must-revalidate"); |
webmaster@1
|
623 header("Cache-Control: post-check=0, pre-check=0", FALSE); |
webmaster@1
|
624 } |
webmaster@1
|
625 |
webmaster@1
|
626 /** |
webmaster@1
|
627 * Set HTTP headers in preparation for a cached page response. |
webmaster@1
|
628 * |
webmaster@1
|
629 * The general approach here is that anonymous users can keep a local |
webmaster@1
|
630 * cache of the page, but must revalidate it on every request. Then, |
webmaster@1
|
631 * they are given a '304 Not Modified' response as long as they stay |
webmaster@1
|
632 * logged out and the page has not been modified. |
webmaster@1
|
633 * |
webmaster@1
|
634 */ |
webmaster@1
|
635 function drupal_page_cache_header($cache) { |
webmaster@1
|
636 // Set default values: |
webmaster@1
|
637 $last_modified = gmdate('D, d M Y H:i:s', $cache->created) .' GMT'; |
webmaster@1
|
638 $etag = '"'. md5($last_modified) .'"'; |
webmaster@1
|
639 |
webmaster@1
|
640 // See if the client has provided the required HTTP headers: |
webmaster@1
|
641 $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE; |
webmaster@1
|
642 $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE; |
webmaster@1
|
643 |
webmaster@1
|
644 if ($if_modified_since && $if_none_match |
webmaster@1
|
645 && $if_none_match == $etag // etag must match |
webmaster@1
|
646 && $if_modified_since == $last_modified) { // if-modified-since must match |
webmaster@1
|
647 header('HTTP/1.1 304 Not Modified'); |
webmaster@1
|
648 // All 304 responses must send an etag if the 200 response for the same object contained an etag |
webmaster@1
|
649 header("Etag: $etag"); |
webmaster@13
|
650 return; |
webmaster@1
|
651 } |
webmaster@1
|
652 |
webmaster@1
|
653 // Send appropriate response: |
webmaster@1
|
654 header("Last-Modified: $last_modified"); |
webmaster@1
|
655 header("ETag: $etag"); |
webmaster@1
|
656 |
webmaster@1
|
657 // The following headers force validation of cache: |
webmaster@1
|
658 header("Expires: Sun, 19 Nov 1978 05:00:00 GMT"); |
webmaster@1
|
659 header("Cache-Control: must-revalidate"); |
webmaster@1
|
660 |
webmaster@1
|
661 if (variable_get('page_compression', TRUE)) { |
webmaster@1
|
662 // Determine if the browser accepts gzipped data. |
webmaster@1
|
663 if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE && function_exists('gzencode')) { |
webmaster@1
|
664 // Strip the gzip header and run uncompress. |
webmaster@1
|
665 $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8)); |
webmaster@1
|
666 } |
webmaster@1
|
667 elseif (function_exists('gzencode')) { |
webmaster@1
|
668 header('Content-Encoding: gzip'); |
webmaster@1
|
669 } |
webmaster@1
|
670 } |
webmaster@1
|
671 |
webmaster@1
|
672 // Send the original request's headers. We send them one after |
webmaster@1
|
673 // another so PHP's header() function can deal with duplicate |
webmaster@1
|
674 // headers. |
webmaster@1
|
675 $headers = explode("\n", $cache->headers); |
webmaster@1
|
676 foreach ($headers as $header) { |
webmaster@1
|
677 header($header); |
webmaster@1
|
678 } |
webmaster@1
|
679 |
webmaster@1
|
680 print $cache->data; |
webmaster@1
|
681 } |
webmaster@1
|
682 |
webmaster@1
|
683 /** |
webmaster@1
|
684 * Define the critical hooks that force modules to always be loaded. |
webmaster@1
|
685 */ |
webmaster@1
|
686 function bootstrap_hooks() { |
webmaster@1
|
687 return array('boot', 'exit'); |
webmaster@1
|
688 } |
webmaster@1
|
689 |
webmaster@1
|
690 /** |
webmaster@1
|
691 * Unserializes and appends elements from a serialized string. |
webmaster@1
|
692 * |
webmaster@1
|
693 * @param $obj |
webmaster@1
|
694 * The object to which the elements are appended. |
webmaster@1
|
695 * @param $field |
webmaster@1
|
696 * The attribute of $obj whose value should be unserialized. |
webmaster@1
|
697 */ |
webmaster@1
|
698 function drupal_unpack($obj, $field = 'data') { |
webmaster@1
|
699 if ($obj->$field && $data = unserialize($obj->$field)) { |
webmaster@1
|
700 foreach ($data as $key => $value) { |
webmaster@1
|
701 if (!isset($obj->$key)) { |
webmaster@1
|
702 $obj->$key = $value; |
webmaster@1
|
703 } |
webmaster@1
|
704 } |
webmaster@1
|
705 } |
webmaster@1
|
706 return $obj; |
webmaster@1
|
707 } |
webmaster@1
|
708 |
webmaster@1
|
709 /** |
webmaster@1
|
710 * Return the URI of the referring page. |
webmaster@1
|
711 */ |
webmaster@1
|
712 function referer_uri() { |
webmaster@1
|
713 if (isset($_SERVER['HTTP_REFERER'])) { |
webmaster@1
|
714 return $_SERVER['HTTP_REFERER']; |
webmaster@1
|
715 } |
webmaster@1
|
716 } |
webmaster@1
|
717 |
webmaster@1
|
718 /** |
webmaster@1
|
719 * Encode special characters in a plain-text string for display as HTML. |
webmaster@1
|
720 * |
webmaster@1
|
721 * Uses drupal_validate_utf8 to prevent cross site scripting attacks on |
webmaster@1
|
722 * Internet Explorer 6. |
webmaster@1
|
723 */ |
webmaster@1
|
724 function check_plain($text) { |
webmaster@1
|
725 return drupal_validate_utf8($text) ? htmlspecialchars($text, ENT_QUOTES) : ''; |
webmaster@1
|
726 } |
webmaster@1
|
727 |
webmaster@1
|
728 /** |
webmaster@1
|
729 * Checks whether a string is valid UTF-8. |
webmaster@1
|
730 * |
webmaster@1
|
731 * All functions designed to filter input should use drupal_validate_utf8 |
webmaster@1
|
732 * to ensure they operate on valid UTF-8 strings to prevent bypass of the |
webmaster@1
|
733 * filter. |
webmaster@1
|
734 * |
webmaster@1
|
735 * When text containing an invalid UTF-8 lead byte (0xC0 - 0xFF) is presented |
webmaster@1
|
736 * as UTF-8 to Internet Explorer 6, the program may misinterpret subsequent |
webmaster@1
|
737 * bytes. When these subsequent bytes are HTML control characters such as |
webmaster@1
|
738 * quotes or angle brackets, parts of the text that were deemed safe by filters |
webmaster@1
|
739 * end up in locations that are potentially unsafe; An onerror attribute that |
webmaster@1
|
740 * is outside of a tag, and thus deemed safe by a filter, can be interpreted |
webmaster@1
|
741 * by the browser as if it were inside the tag. |
webmaster@1
|
742 * |
webmaster@1
|
743 * This function exploits preg_match behaviour (since PHP 4.3.5) when used |
webmaster@1
|
744 * with the u modifier, as a fast way to find invalid UTF-8. When the matched |
webmaster@1
|
745 * string contains an invalid byte sequence, it will fail silently. |
webmaster@1
|
746 * |
webmaster@1
|
747 * preg_match may not fail on 4 and 5 octet sequences, even though they |
webmaster@1
|
748 * are not supported by the specification. |
webmaster@1
|
749 * |
webmaster@1
|
750 * The specific preg_match behaviour is present since PHP 4.3.5. |
webmaster@1
|
751 * |
webmaster@1
|
752 * @param $text |
webmaster@1
|
753 * The text to check. |
webmaster@1
|
754 * @return |
webmaster@1
|
755 * TRUE if the text is valid UTF-8, FALSE if not. |
webmaster@1
|
756 */ |
webmaster@1
|
757 function drupal_validate_utf8($text) { |
webmaster@1
|
758 if (strlen($text) == 0) { |
webmaster@1
|
759 return TRUE; |
webmaster@1
|
760 } |
webmaster@1
|
761 return (preg_match('/^./us', $text) == 1); |
webmaster@1
|
762 } |
webmaster@1
|
763 |
webmaster@1
|
764 /** |
webmaster@1
|
765 * Since $_SERVER['REQUEST_URI'] is only available on Apache, we |
webmaster@1
|
766 * generate an equivalent using other environment variables. |
webmaster@1
|
767 */ |
webmaster@1
|
768 function request_uri() { |
webmaster@1
|
769 |
webmaster@1
|
770 if (isset($_SERVER['REQUEST_URI'])) { |
webmaster@1
|
771 $uri = $_SERVER['REQUEST_URI']; |
webmaster@1
|
772 } |
webmaster@1
|
773 else { |
webmaster@1
|
774 if (isset($_SERVER['argv'])) { |
webmaster@1
|
775 $uri = $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['argv'][0]; |
webmaster@1
|
776 } |
webmaster@1
|
777 elseif (isset($_SERVER['QUERY_STRING'])) { |
webmaster@1
|
778 $uri = $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['QUERY_STRING']; |
webmaster@1
|
779 } |
webmaster@1
|
780 else { |
webmaster@1
|
781 $uri = $_SERVER['SCRIPT_NAME']; |
webmaster@1
|
782 } |
webmaster@1
|
783 } |
webmaster@1
|
784 |
webmaster@1
|
785 return $uri; |
webmaster@1
|
786 } |
webmaster@1
|
787 |
webmaster@1
|
788 /** |
webmaster@1
|
789 * Log a system message. |
webmaster@1
|
790 * |
webmaster@1
|
791 * @param $type |
webmaster@1
|
792 * The category to which this message belongs. |
webmaster@1
|
793 * @param $message |
webmaster@1
|
794 * The message to store in the log. See t() for documentation |
webmaster@1
|
795 * on how $message and $variables interact. Keep $message |
webmaster@1
|
796 * translatable by not concatenating dynamic values into it! |
webmaster@1
|
797 * @param $variables |
webmaster@1
|
798 * Array of variables to replace in the message on display or |
webmaster@1
|
799 * NULL if message is already translated or not possible to |
webmaster@1
|
800 * translate. |
webmaster@1
|
801 * @param $severity |
webmaster@1
|
802 * The severity of the message, as per RFC 3164 |
webmaster@1
|
803 * @param $link |
webmaster@1
|
804 * A link to associate with the message. |
webmaster@1
|
805 * |
webmaster@1
|
806 * @see watchdog_severity_levels() |
webmaster@1
|
807 */ |
webmaster@1
|
808 function watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) { |
webmaster@1
|
809 global $user, $base_root; |
webmaster@1
|
810 |
webmaster@1
|
811 // Prepare the fields to be logged |
webmaster@1
|
812 $log_message = array( |
webmaster@1
|
813 'type' => $type, |
webmaster@1
|
814 'message' => $message, |
webmaster@1
|
815 'variables' => $variables, |
webmaster@1
|
816 'severity' => $severity, |
webmaster@1
|
817 'link' => $link, |
webmaster@1
|
818 'user' => $user, |
webmaster@1
|
819 'request_uri' => $base_root . request_uri(), |
webmaster@1
|
820 'referer' => referer_uri(), |
webmaster@1
|
821 'ip' => ip_address(), |
webmaster@1
|
822 'timestamp' => time(), |
webmaster@1
|
823 ); |
webmaster@1
|
824 |
webmaster@1
|
825 // Call the logging hooks to log/process the message |
webmaster@1
|
826 foreach (module_implements('watchdog', TRUE) as $module) { |
webmaster@1
|
827 module_invoke($module, 'watchdog', $log_message); |
webmaster@1
|
828 } |
webmaster@1
|
829 } |
webmaster@1
|
830 |
webmaster@1
|
831 /** |
webmaster@1
|
832 * Set a message which reflects the status of the performed operation. |
webmaster@1
|
833 * |
webmaster@1
|
834 * If the function is called with no arguments, this function returns all set |
webmaster@1
|
835 * messages without clearing them. |
webmaster@1
|
836 * |
webmaster@1
|
837 * @param $message |
webmaster@1
|
838 * The message should begin with a capital letter and always ends with a |
webmaster@1
|
839 * period '.'. |
webmaster@1
|
840 * @param $type |
webmaster@1
|
841 * The type of the message. One of the following values are possible: |
webmaster@1
|
842 * - 'status' |
webmaster@1
|
843 * - 'warning' |
webmaster@1
|
844 * - 'error' |
webmaster@1
|
845 * @param $repeat |
webmaster@1
|
846 * If this is FALSE and the message is already set, then the message won't |
webmaster@1
|
847 * be repeated. |
webmaster@1
|
848 */ |
webmaster@1
|
849 function drupal_set_message($message = NULL, $type = 'status', $repeat = TRUE) { |
webmaster@1
|
850 if ($message) { |
webmaster@1
|
851 if (!isset($_SESSION['messages'])) { |
webmaster@1
|
852 $_SESSION['messages'] = array(); |
webmaster@1
|
853 } |
webmaster@1
|
854 |
webmaster@1
|
855 if (!isset($_SESSION['messages'][$type])) { |
webmaster@1
|
856 $_SESSION['messages'][$type] = array(); |
webmaster@1
|
857 } |
webmaster@1
|
858 |
webmaster@1
|
859 if ($repeat || !in_array($message, $_SESSION['messages'][$type])) { |
webmaster@1
|
860 $_SESSION['messages'][$type][] = $message; |
webmaster@1
|
861 } |
webmaster@1
|
862 } |
webmaster@1
|
863 |
webmaster@1
|
864 // messages not set when DB connection fails |
webmaster@1
|
865 return isset($_SESSION['messages']) ? $_SESSION['messages'] : NULL; |
webmaster@1
|
866 } |
webmaster@1
|
867 |
webmaster@1
|
868 /** |
webmaster@1
|
869 * Return all messages that have been set. |
webmaster@1
|
870 * |
webmaster@1
|
871 * @param $type |
webmaster@1
|
872 * (optional) Only return messages of this type. |
webmaster@1
|
873 * @param $clear_queue |
webmaster@1
|
874 * (optional) Set to FALSE if you do not want to clear the messages queue |
webmaster@1
|
875 * @return |
webmaster@1
|
876 * An associative array, the key is the message type, the value an array |
webmaster@1
|
877 * of messages. If the $type parameter is passed, you get only that type, |
webmaster@1
|
878 * or an empty array if there are no such messages. If $type is not passed, |
webmaster@1
|
879 * all message types are returned, or an empty array if none exist. |
webmaster@1
|
880 */ |
webmaster@1
|
881 function drupal_get_messages($type = NULL, $clear_queue = TRUE) { |
webmaster@1
|
882 if ($messages = drupal_set_message()) { |
webmaster@1
|
883 if ($type) { |
webmaster@1
|
884 if ($clear_queue) { |
webmaster@1
|
885 unset($_SESSION['messages'][$type]); |
webmaster@1
|
886 } |
webmaster@1
|
887 if (isset($messages[$type])) { |
webmaster@1
|
888 return array($type => $messages[$type]); |
webmaster@1
|
889 } |
webmaster@1
|
890 } |
webmaster@1
|
891 else { |
webmaster@1
|
892 if ($clear_queue) { |
webmaster@1
|
893 unset($_SESSION['messages']); |
webmaster@1
|
894 } |
webmaster@1
|
895 return $messages; |
webmaster@1
|
896 } |
webmaster@1
|
897 } |
webmaster@1
|
898 return array(); |
webmaster@1
|
899 } |
webmaster@1
|
900 |
webmaster@1
|
901 /** |
webmaster@1
|
902 * Perform an access check for a given mask and rule type. Rules are usually |
webmaster@1
|
903 * created via admin/user/rules page. |
webmaster@1
|
904 * |
webmaster@1
|
905 * If any allow rule matches, access is allowed. Otherwise, if any deny rule |
webmaster@1
|
906 * matches, access is denied. If no rule matches, access is allowed. |
webmaster@1
|
907 * |
webmaster@1
|
908 * @param $type string |
webmaster@1
|
909 * Type of access to check: Allowed values are: |
webmaster@1
|
910 * - 'host': host name or IP address |
webmaster@1
|
911 * - 'mail': e-mail address |
webmaster@1
|
912 * - 'user': username |
webmaster@1
|
913 * @param $mask string |
webmaster@1
|
914 * String or mask to test: '_' matches any character, '%' matches any |
webmaster@1
|
915 * number of characters. |
webmaster@1
|
916 * @return bool |
webmaster@1
|
917 * TRUE if access is denied, FALSE if access is allowed. |
webmaster@1
|
918 */ |
webmaster@1
|
919 function drupal_is_denied($type, $mask) { |
webmaster@1
|
920 // Because this function is called for every page request, both cached |
webmaster@1
|
921 // and non-cached pages, we tried to optimize it as much as possible. |
webmaster@1
|
922 // We deny access if the only matching records in the {access} table have |
webmaster@1
|
923 // status 0 (deny). If any have status 1 (allow), or if there are no |
webmaster@1
|
924 // matching records, we allow access. |
webmaster@1
|
925 $sql = "SELECT 1 FROM {access} WHERE type = '%s' AND LOWER('%s') LIKE LOWER(mask) AND status = %d"; |
webmaster@1
|
926 return db_result(db_query_range($sql, $type, $mask, 0, 0, 1)) && !db_result(db_query_range($sql, $type, $mask, 1, 0, 1)); |
webmaster@1
|
927 } |
webmaster@1
|
928 |
webmaster@1
|
929 /** |
webmaster@1
|
930 * Generates a default anonymous $user object. |
webmaster@1
|
931 * |
webmaster@1
|
932 * @return Object - the user object. |
webmaster@1
|
933 */ |
webmaster@1
|
934 function drupal_anonymous_user($session = '') { |
webmaster@1
|
935 $user = new stdClass(); |
webmaster@1
|
936 $user->uid = 0; |
webmaster@1
|
937 $user->hostname = ip_address(); |
webmaster@1
|
938 $user->roles = array(); |
webmaster@1
|
939 $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; |
webmaster@1
|
940 $user->session = $session; |
webmaster@1
|
941 $user->cache = 0; |
webmaster@1
|
942 return $user; |
webmaster@1
|
943 } |
webmaster@1
|
944 |
webmaster@1
|
945 /** |
webmaster@1
|
946 * A string describing a phase of Drupal to load. Each phase adds to the |
webmaster@1
|
947 * previous one, so invoking a later phase automatically runs the earlier |
webmaster@1
|
948 * phases too. The most important usage is that if you want to access the |
webmaster@1
|
949 * Drupal database from a script without loading anything else, you can |
webmaster@1
|
950 * include bootstrap.inc, and call drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE). |
webmaster@1
|
951 * |
webmaster@1
|
952 * @param $phase |
webmaster@1
|
953 * A constant. Allowed values are: |
webmaster@1
|
954 * DRUPAL_BOOTSTRAP_CONFIGURATION: initialize configuration. |
webmaster@1
|
955 * DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: try to call a non-database cache fetch routine. |
webmaster@1
|
956 * DRUPAL_BOOTSTRAP_DATABASE: initialize database layer. |
webmaster@1
|
957 * DRUPAL_BOOTSTRAP_ACCESS: identify and reject banned hosts. |
webmaster@1
|
958 * DRUPAL_BOOTSTRAP_SESSION: initialize session handling. |
webmaster@1
|
959 * DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: load bootstrap.inc and module.inc, start |
webmaster@1
|
960 * the variable system and try to serve a page from the cache. |
webmaster@1
|
961 * DRUPAL_BOOTSTRAP_LANGUAGE: identify the language used on the page. |
webmaster@1
|
962 * DRUPAL_BOOTSTRAP_PATH: set $_GET['q'] to Drupal path of request. |
webmaster@1
|
963 * DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data. |
webmaster@1
|
964 */ |
webmaster@1
|
965 function drupal_bootstrap($phase) { |
webmaster@1
|
966 static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_ACCESS, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE, DRUPAL_BOOTSTRAP_LANGUAGE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL), $phase_index = 0; |
webmaster@1
|
967 |
webmaster@1
|
968 while ($phase >= $phase_index && isset($phases[$phase_index])) { |
webmaster@1
|
969 $current_phase = $phases[$phase_index]; |
webmaster@1
|
970 unset($phases[$phase_index++]); |
webmaster@1
|
971 _drupal_bootstrap($current_phase); |
webmaster@1
|
972 } |
webmaster@1
|
973 } |
webmaster@1
|
974 |
webmaster@1
|
975 function _drupal_bootstrap($phase) { |
webmaster@1
|
976 global $conf; |
webmaster@1
|
977 |
webmaster@1
|
978 switch ($phase) { |
webmaster@1
|
979 |
webmaster@1
|
980 case DRUPAL_BOOTSTRAP_CONFIGURATION: |
webmaster@1
|
981 drupal_unset_globals(); |
webmaster@1
|
982 // Start a page timer: |
webmaster@1
|
983 timer_start('page'); |
webmaster@1
|
984 // Initialize the configuration |
webmaster@1
|
985 conf_init(); |
webmaster@1
|
986 break; |
webmaster@1
|
987 |
webmaster@1
|
988 case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: |
webmaster@1
|
989 // Allow specifying special cache handlers in settings.php, like |
webmaster@1
|
990 // using memcached or files for storing cache information. |
webmaster@1
|
991 require_once variable_get('cache_inc', './includes/cache.inc'); |
webmaster@1
|
992 // If the page_cache_fastpath is set to TRUE in settings.php and |
webmaster@1
|
993 // page_cache_fastpath (implemented in the special implementation of |
webmaster@1
|
994 // cache.inc) printed the page and indicated this with a returned TRUE |
webmaster@1
|
995 // then we are done. |
webmaster@1
|
996 if (variable_get('page_cache_fastpath', FALSE) && page_cache_fastpath()) { |
webmaster@1
|
997 exit; |
webmaster@1
|
998 } |
webmaster@1
|
999 break; |
webmaster@1
|
1000 |
webmaster@1
|
1001 case DRUPAL_BOOTSTRAP_DATABASE: |
webmaster@1
|
1002 // Initialize the default database. |
webmaster@1
|
1003 require_once './includes/database.inc'; |
webmaster@1
|
1004 db_set_active(); |
webmaster@1
|
1005 break; |
webmaster@1
|
1006 |
webmaster@1
|
1007 case DRUPAL_BOOTSTRAP_ACCESS: |
webmaster@1
|
1008 // Deny access to hosts which were banned - t() is not yet available. |
webmaster@1
|
1009 if (drupal_is_denied('host', ip_address())) { |
webmaster@1
|
1010 header('HTTP/1.1 403 Forbidden'); |
webmaster@1
|
1011 print 'Sorry, '. check_plain(ip_address()) .' has been banned.'; |
webmaster@1
|
1012 exit(); |
webmaster@1
|
1013 } |
webmaster@1
|
1014 break; |
webmaster@1
|
1015 |
webmaster@1
|
1016 case DRUPAL_BOOTSTRAP_SESSION: |
webmaster@1
|
1017 require_once variable_get('session_inc', './includes/session.inc'); |
webmaster@1
|
1018 session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc'); |
webmaster@1
|
1019 session_start(); |
webmaster@1
|
1020 break; |
webmaster@1
|
1021 |
webmaster@1
|
1022 case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: |
webmaster@1
|
1023 // Initialize configuration variables, using values from settings.php if available. |
webmaster@1
|
1024 $conf = variable_init(isset($conf) ? $conf : array()); |
webmaster@1
|
1025 $cache_mode = variable_get('cache', CACHE_DISABLED); |
webmaster@1
|
1026 // Get the page from the cache. |
webmaster@1
|
1027 $cache = $cache_mode == CACHE_DISABLED ? '' : page_get_cache(); |
webmaster@1
|
1028 // If the skipping of the bootstrap hooks is not enforced, call hook_boot. |
franck@19
|
1029 if (!$cache || $cache_mode != CACHE_AGGRESSIVE) { |
franck@19
|
1030 // Load module handling. |
franck@19
|
1031 require_once './includes/module.inc'; |
webmaster@1
|
1032 bootstrap_invoke_all('boot'); |
webmaster@1
|
1033 } |
webmaster@1
|
1034 // If there is a cached page, display it. |
webmaster@1
|
1035 if ($cache) { |
webmaster@1
|
1036 drupal_page_cache_header($cache); |
webmaster@1
|
1037 // If the skipping of the bootstrap hooks is not enforced, call hook_exit. |
webmaster@1
|
1038 if ($cache_mode != CACHE_AGGRESSIVE) { |
webmaster@1
|
1039 bootstrap_invoke_all('exit'); |
webmaster@1
|
1040 } |
webmaster@1
|
1041 // We are done. |
webmaster@1
|
1042 exit; |
webmaster@1
|
1043 } |
webmaster@1
|
1044 // Prepare for non-cached page workflow. |
webmaster@1
|
1045 drupal_page_header(); |
webmaster@1
|
1046 break; |
webmaster@1
|
1047 |
webmaster@1
|
1048 case DRUPAL_BOOTSTRAP_LANGUAGE: |
webmaster@1
|
1049 drupal_init_language(); |
webmaster@1
|
1050 break; |
webmaster@1
|
1051 |
webmaster@1
|
1052 case DRUPAL_BOOTSTRAP_PATH: |
webmaster@1
|
1053 require_once './includes/path.inc'; |
webmaster@1
|
1054 // Initialize $_GET['q'] prior to loading modules and invoking hook_init(). |
webmaster@1
|
1055 drupal_init_path(); |
webmaster@1
|
1056 break; |
webmaster@1
|
1057 |
webmaster@1
|
1058 case DRUPAL_BOOTSTRAP_FULL: |
webmaster@1
|
1059 require_once './includes/common.inc'; |
webmaster@1
|
1060 _drupal_bootstrap_full(); |
webmaster@1
|
1061 break; |
webmaster@1
|
1062 } |
webmaster@1
|
1063 } |
webmaster@1
|
1064 |
webmaster@1
|
1065 /** |
webmaster@1
|
1066 * Enables use of the theme system without requiring database access. |
webmaster@1
|
1067 * |
webmaster@1
|
1068 * Loads and initializes the theme system for site installs, updates and when |
webmaster@1
|
1069 * the site is in off-line mode. This also applies when the database fails. |
webmaster@1
|
1070 * |
webmaster@1
|
1071 * @see _drupal_maintenance_theme() |
webmaster@1
|
1072 */ |
webmaster@1
|
1073 function drupal_maintenance_theme() { |
webmaster@1
|
1074 require_once './includes/theme.maintenance.inc'; |
webmaster@1
|
1075 _drupal_maintenance_theme(); |
webmaster@1
|
1076 } |
webmaster@1
|
1077 |
webmaster@1
|
1078 /** |
webmaster@1
|
1079 * Return the name of the localisation function. Use in code that needs to |
webmaster@1
|
1080 * run both during installation and normal operation. |
webmaster@1
|
1081 */ |
webmaster@1
|
1082 function get_t() { |
webmaster@1
|
1083 static $t; |
webmaster@1
|
1084 if (is_null($t)) { |
webmaster@1
|
1085 $t = function_exists('install_main') ? 'st' : 't'; |
webmaster@1
|
1086 } |
webmaster@1
|
1087 return $t; |
webmaster@1
|
1088 } |
webmaster@1
|
1089 |
webmaster@1
|
1090 /** |
webmaster@1
|
1091 * Choose a language for the current page, based on site and user preferences. |
webmaster@1
|
1092 */ |
webmaster@1
|
1093 function drupal_init_language() { |
webmaster@1
|
1094 global $language, $user; |
webmaster@1
|
1095 |
webmaster@1
|
1096 // Ensure the language is correctly returned, even without multilanguage support. |
webmaster@1
|
1097 // Useful for eg. XML/HTML 'lang' attributes. |
webmaster@1
|
1098 if (variable_get('language_count', 1) == 1) { |
webmaster@1
|
1099 $language = language_default(); |
webmaster@1
|
1100 } |
webmaster@1
|
1101 else { |
webmaster@1
|
1102 include_once './includes/language.inc'; |
webmaster@1
|
1103 $language = language_initialize(); |
webmaster@1
|
1104 } |
webmaster@1
|
1105 } |
webmaster@1
|
1106 |
webmaster@1
|
1107 /** |
webmaster@1
|
1108 * Get a list of languages set up indexed by the specified key |
webmaster@1
|
1109 * |
webmaster@1
|
1110 * @param $field The field to index the list with. |
webmaster@1
|
1111 * @param $reset Boolean to request a reset of the list. |
webmaster@1
|
1112 */ |
webmaster@1
|
1113 function language_list($field = 'language', $reset = FALSE) { |
webmaster@1
|
1114 static $languages = NULL; |
webmaster@1
|
1115 |
webmaster@1
|
1116 // Reset language list |
webmaster@1
|
1117 if ($reset) { |
webmaster@1
|
1118 $languages = NULL; |
webmaster@1
|
1119 } |
webmaster@1
|
1120 |
webmaster@1
|
1121 // Init language list |
webmaster@1
|
1122 if (!isset($languages)) { |
webmaster@1
|
1123 if (variable_get('language_count', 1) > 1 || module_exists('locale')) { |
webmaster@1
|
1124 $result = db_query('SELECT * FROM {languages} ORDER BY weight ASC, name ASC'); |
webmaster@1
|
1125 while ($row = db_fetch_object($result)) { |
webmaster@1
|
1126 $languages['language'][$row->language] = $row; |
webmaster@1
|
1127 } |
webmaster@1
|
1128 } |
webmaster@1
|
1129 else { |
webmaster@1
|
1130 // No locale module, so use the default language only. |
webmaster@1
|
1131 $default = language_default(); |
webmaster@1
|
1132 $languages['language'][$default->language] = $default; |
webmaster@1
|
1133 } |
webmaster@1
|
1134 } |
webmaster@1
|
1135 |
webmaster@1
|
1136 // Return the array indexed by the right field |
webmaster@1
|
1137 if (!isset($languages[$field])) { |
webmaster@1
|
1138 $languages[$field] = array(); |
webmaster@1
|
1139 foreach ($languages['language'] as $lang) { |
webmaster@1
|
1140 // Some values should be collected into an array |
webmaster@1
|
1141 if (in_array($field, array('enabled', 'weight'))) { |
webmaster@1
|
1142 $languages[$field][$lang->$field][$lang->language] = $lang; |
webmaster@1
|
1143 } |
webmaster@1
|
1144 else { |
webmaster@1
|
1145 $languages[$field][$lang->$field] = $lang; |
webmaster@1
|
1146 } |
webmaster@1
|
1147 } |
webmaster@1
|
1148 } |
webmaster@1
|
1149 return $languages[$field]; |
webmaster@1
|
1150 } |
webmaster@1
|
1151 |
webmaster@1
|
1152 /** |
webmaster@1
|
1153 * Default language used on the site |
webmaster@1
|
1154 * |
webmaster@1
|
1155 * @param $property |
webmaster@1
|
1156 * Optional property of the language object to return |
webmaster@1
|
1157 */ |
webmaster@1
|
1158 function language_default($property = NULL) { |
webmaster@1
|
1159 $language = variable_get('language_default', (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => '')); |
webmaster@1
|
1160 return $property ? $language->$property : $language; |
webmaster@1
|
1161 } |
webmaster@1
|
1162 |
webmaster@1
|
1163 /** |
webmaster@1
|
1164 * If Drupal is behind a reverse proxy, we use the X-Forwarded-For header |
webmaster@1
|
1165 * instead of $_SERVER['REMOTE_ADDR'], which would be the IP address |
webmaster@1
|
1166 * of the proxy server, and not the client's. |
webmaster@1
|
1167 * |
webmaster@1
|
1168 * @return |
webmaster@1
|
1169 * IP address of client machine, adjusted for reverse proxy. |
webmaster@1
|
1170 */ |
webmaster@1
|
1171 function ip_address() { |
webmaster@1
|
1172 static $ip_address = NULL; |
webmaster@1
|
1173 |
webmaster@1
|
1174 if (!isset($ip_address)) { |
webmaster@1
|
1175 $ip_address = $_SERVER['REMOTE_ADDR']; |
webmaster@1
|
1176 if (variable_get('reverse_proxy', 0) && array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { |
webmaster@1
|
1177 // If an array of known reverse proxy IPs is provided, then trust |
webmaster@1
|
1178 // the XFF header if request really comes from one of them. |
webmaster@1
|
1179 $reverse_proxy_addresses = variable_get('reverse_proxy_addresses', array()); |
webmaster@1
|
1180 if (!empty($reverse_proxy_addresses) && in_array($ip_address, $reverse_proxy_addresses, TRUE)) { |
webmaster@1
|
1181 // If there are several arguments, we need to check the most |
webmaster@1
|
1182 // recently added one, i.e. the last one. |
webmaster@1
|
1183 $ip_address = array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])); |
webmaster@1
|
1184 } |
webmaster@1
|
1185 } |
webmaster@1
|
1186 } |
webmaster@1
|
1187 |
webmaster@1
|
1188 return $ip_address; |
webmaster@1
|
1189 } |