1
by bzr
Drupal 6.6 |
1 |
<?php
|
1.1.13
by David Strauss
Drupal 6.19 |
2 |
// $Id: bootstrap.inc,v 1.206.2.29 2010/08/06 11:50:24 goba Exp $
|
1
by bzr
Drupal 6.6 |
3 |
|
4 |
/**
|
|
5 |
* @file
|
|
6 |
* Functions that need to be loaded on every Drupal request.
|
|
7 |
*/
|
|
8 |
||
9 |
/**
|
|
10 |
* Indicates that the item should never be removed unless explicitly told to
|
|
11 |
* using cache_clear_all() with a cache ID.
|
|
12 |
*/
|
|
13 |
define('CACHE_PERMANENT', 0); |
|
14 |
||
15 |
/**
|
|
16 |
* Indicates that the item should be removed at the next general cache wipe.
|
|
17 |
*/
|
|
18 |
define('CACHE_TEMPORARY', -1); |
|
19 |
||
20 |
/**
|
|
21 |
* Indicates that page caching is disabled.
|
|
22 |
*/
|
|
23 |
define('CACHE_DISABLED', 0); |
|
24 |
||
25 |
/**
|
|
26 |
* Indicates that page caching is enabled, using "normal" mode.
|
|
27 |
*/
|
|
28 |
define('CACHE_NORMAL', 1); |
|
29 |
||
30 |
/**
|
|
31 |
* Indicates that page caching is using "aggressive" mode. This bypasses
|
|
32 |
* loading any modules for additional speed, which may break functionality in
|
|
33 |
* modules that expect to be run on each page load.
|
|
34 |
*/
|
|
35 |
define('CACHE_AGGRESSIVE', 2); |
|
36 |
||
37 |
/**
|
|
63
by David Strauss
David Strauss: Add an 'external' caching mode that skips the built-in cache but still sends friendly headers downstream. |
38 |
* Indicates that page caching is using "external" mode. This disables the
|
39 |
* internal page cache but returns headers allowing downstream caches (such
|
|
40 |
* as Squid, Varnish, and other reverse proxies) to cache full pages. Like
|
|
41 |
* "aggressive" mode, this may break functionality in some modules.
|
|
42 |
*/
|
|
43 |
define('CACHE_EXTERNAL', 3); |
|
44 |
||
45 |
/**
|
|
1.1.11
by David Strauss
Drupal 6.17 |
46 |
* Log message severity -- Emergency: system is unusable.
|
47 |
*
|
|
48 |
* The WATCHDOG_* constant definitions correspond to the logging severity levels
|
|
49 |
* defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
|
|
50 |
*
|
|
51 |
* @see watchdog()
|
|
52 |
* @see watchdog_severity_levels()
|
|
53 |
*/
|
|
54 |
define('WATCHDOG_EMERG', 0); |
|
55 |
||
56 |
/**
|
|
57 |
* Log message severity -- Alert: action must be taken immediately.
|
|
58 |
*
|
|
59 |
* The WATCHDOG_* constant definitions correspond to the logging severity levels
|
|
60 |
* defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
|
|
61 |
*
|
|
62 |
* @see watchdog()
|
|
63 |
* @see watchdog_severity_levels()
|
|
64 |
*/
|
|
65 |
define('WATCHDOG_ALERT', 1); |
|
66 |
||
67 |
/**
|
|
68 |
* Log message severity -- Critical: critical conditions.
|
|
69 |
*
|
|
70 |
* The WATCHDOG_* constant definitions correspond to the logging severity levels
|
|
71 |
* defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
|
|
72 |
*
|
|
73 |
* @see watchdog()
|
|
74 |
* @see watchdog_severity_levels()
|
|
75 |
*/
|
|
76 |
define('WATCHDOG_CRITICAL', 2); |
|
77 |
||
78 |
/**
|
|
79 |
* Log message severity -- Error: error conditions.
|
|
80 |
*
|
|
81 |
* The WATCHDOG_* constant definitions correspond to the logging severity levels
|
|
82 |
* defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
|
|
83 |
*
|
|
84 |
* @see watchdog()
|
|
85 |
* @see watchdog_severity_levels()
|
|
86 |
*/
|
|
87 |
define('WATCHDOG_ERROR', 3); |
|
88 |
||
89 |
/**
|
|
90 |
* Log message severity -- Warning: warning conditions.
|
|
91 |
*
|
|
92 |
* The WATCHDOG_* constant definitions correspond to the logging severity levels
|
|
93 |
* defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
|
|
94 |
*
|
|
95 |
* @see watchdog()
|
|
96 |
* @see watchdog_severity_levels()
|
|
97 |
*/
|
|
98 |
define('WATCHDOG_WARNING', 4); |
|
99 |
||
100 |
/**
|
|
101 |
* Log message severity -- Notice: normal but significant condition.
|
|
102 |
*
|
|
103 |
* The WATCHDOG_* constant definitions correspond to the logging severity levels
|
|
104 |
* defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
|
|
105 |
*
|
|
106 |
* @see watchdog()
|
|
107 |
* @see watchdog_severity_levels()
|
|
108 |
*/
|
|
109 |
define('WATCHDOG_NOTICE', 5); |
|
110 |
||
111 |
/**
|
|
112 |
* Log message severity -- Informational: informational messages.
|
|
113 |
*
|
|
114 |
* The WATCHDOG_* constant definitions correspond to the logging severity levels
|
|
115 |
* defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
|
|
116 |
*
|
|
117 |
* @see watchdog()
|
|
118 |
* @see watchdog_severity_levels()
|
|
119 |
*/
|
|
120 |
define('WATCHDOG_INFO', 6); |
|
121 |
||
122 |
/**
|
|
123 |
* Log message severity -- Debug: debug-level messages.
|
|
124 |
*
|
|
125 |
* The WATCHDOG_* constant definitions correspond to the logging severity levels
|
|
126 |
* defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
|
|
127 |
*
|
|
128 |
* @see watchdog()
|
|
129 |
* @see watchdog_severity_levels()
|
|
130 |
*/
|
|
131 |
define('WATCHDOG_DEBUG', 7); |
|
1
by bzr
Drupal 6.6 |
132 |
|
133 |
/**
|
|
134 |
* First bootstrap phase: initialize configuration.
|
|
135 |
*/
|
|
136 |
define('DRUPAL_BOOTSTRAP_CONFIGURATION', 0); |
|
137 |
||
138 |
/**
|
|
139 |
* Second bootstrap phase: try to call a non-database cache
|
|
140 |
* fetch routine.
|
|
141 |
*/
|
|
142 |
define('DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE', 1); |
|
143 |
||
144 |
/**
|
|
145 |
* Third bootstrap phase: initialize database layer.
|
|
146 |
*/
|
|
147 |
define('DRUPAL_BOOTSTRAP_DATABASE', 2); |
|
148 |
||
149 |
/**
|
|
150 |
* Fourth bootstrap phase: identify and reject banned hosts.
|
|
151 |
*/
|
|
152 |
define('DRUPAL_BOOTSTRAP_ACCESS', 3); |
|
153 |
||
154 |
/**
|
|
155 |
* Fifth bootstrap phase: initialize session handling.
|
|
156 |
*/
|
|
157 |
define('DRUPAL_BOOTSTRAP_SESSION', 4); |
|
158 |
||
159 |
/**
|
|
160 |
* Sixth bootstrap phase: load bootstrap.inc and module.inc, start
|
|
161 |
* the variable system and try to serve a page from the cache.
|
|
162 |
*/
|
|
163 |
define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 5); |
|
164 |
||
165 |
/**
|
|
166 |
* Seventh bootstrap phase: find out language of the page.
|
|
167 |
*/
|
|
168 |
define('DRUPAL_BOOTSTRAP_LANGUAGE', 6); |
|
169 |
||
170 |
/**
|
|
171 |
* Eighth bootstrap phase: set $_GET['q'] to Drupal path of request.
|
|
172 |
*/
|
|
173 |
define('DRUPAL_BOOTSTRAP_PATH', 7); |
|
174 |
||
175 |
/**
|
|
176 |
* Final bootstrap phase: Drupal is fully loaded; validate and fix
|
|
177 |
* input data.
|
|
178 |
*/
|
|
179 |
define('DRUPAL_BOOTSTRAP_FULL', 8); |
|
180 |
||
181 |
/**
|
|
182 |
* Role ID for anonymous users; should match what's in the "role" table.
|
|
183 |
*/
|
|
184 |
define('DRUPAL_ANONYMOUS_RID', 1); |
|
185 |
||
186 |
/**
|
|
187 |
* Role ID for authenticated users; should match what's in the "role" table.
|
|
188 |
*/
|
|
189 |
define('DRUPAL_AUTHENTICATED_RID', 2); |
|
190 |
||
191 |
/**
|
|
192 |
* No language negotiation. The default language is used.
|
|
193 |
*/
|
|
194 |
define('LANGUAGE_NEGOTIATION_NONE', 0); |
|
195 |
||
196 |
/**
|
|
197 |
* Path based negotiation with fallback to default language
|
|
198 |
* if no defined path prefix identified.
|
|
199 |
*/
|
|
200 |
define('LANGUAGE_NEGOTIATION_PATH_DEFAULT', 1); |
|
201 |
||
202 |
/**
|
|
203 |
* Path based negotiation with fallback to user preferences
|
|
204 |
* and browser language detection if no defined path prefix
|
|
205 |
* identified.
|
|
206 |
*/
|
|
207 |
define('LANGUAGE_NEGOTIATION_PATH', 2); |
|
208 |
||
209 |
/**
|
|
210 |
* Domain based negotiation with fallback to default language
|
|
211 |
* if no language identified by domain.
|
|
212 |
*/
|
|
213 |
define('LANGUAGE_NEGOTIATION_DOMAIN', 3); |
|
214 |
||
215 |
/**
|
|
1.1.4
by bzr
Drupal 6.10 |
216 |
* Language written left to right. Possible value of $language->direction.
|
217 |
*/
|
|
218 |
define('LANGUAGE_LTR', 0); |
|
219 |
||
220 |
/**
|
|
221 |
* Language written right to left. Possible value of $language->direction.
|
|
222 |
*/
|
|
223 |
define('LANGUAGE_RTL', 1); |
|
224 |
||
1.1.13
by David Strauss
Drupal 6.19 |
225 |
// Hide E_DEPRECATED messages.
|
226 |
if (defined('E_DEPRECATED')) { |
|
227 |
error_reporting(error_reporting() & ~E_DEPRECATED); |
|
228 |
}
|
|
229 |
||
1.1.4
by bzr
Drupal 6.10 |
230 |
/**
|
1
by bzr
Drupal 6.6 |
231 |
* Start the timer with the specified name. If you start and stop
|
232 |
* the same timer multiple times, the measured intervals will be
|
|
233 |
* accumulated.
|
|
234 |
*
|
|
235 |
* @param name
|
|
236 |
* The name of the timer.
|
|
237 |
*/
|
|
238 |
function timer_start($name) { |
|
239 |
global $timers; |
|
240 |
||
241 |
list($usec, $sec) = explode(' ', microtime()); |
|
242 |
$timers[$name]['start'] = (float)$usec + (float)$sec; |
|
243 |
$timers[$name]['count'] = isset($timers[$name]['count']) ? ++$timers[$name]['count'] : 1; |
|
244 |
}
|
|
245 |
||
246 |
/**
|
|
247 |
* Read the current timer value without stopping the timer.
|
|
248 |
*
|
|
249 |
* @param name
|
|
250 |
* The name of the timer.
|
|
251 |
* @return
|
|
252 |
* The current timer value in ms.
|
|
253 |
*/
|
|
254 |
function timer_read($name) { |
|
255 |
global $timers; |
|
256 |
||
257 |
if (isset($timers[$name]['start'])) { |
|
258 |
list($usec, $sec) = explode(' ', microtime()); |
|
259 |
$stop = (float)$usec + (float)$sec; |
|
260 |
$diff = round(($stop - $timers[$name]['start']) * 1000, 2); |
|
261 |
||
262 |
if (isset($timers[$name]['time'])) { |
|
263 |
$diff += $timers[$name]['time']; |
|
264 |
}
|
|
265 |
return $diff; |
|
266 |
}
|
|
267 |
}
|
|
268 |
||
269 |
/**
|
|
270 |
* Stop the timer with the specified name.
|
|
271 |
*
|
|
272 |
* @param name
|
|
273 |
* The name of the timer.
|
|
274 |
* @return
|
|
275 |
* A timer array. The array contains the number of times the
|
|
276 |
* timer has been started and stopped (count) and the accumulated
|
|
277 |
* timer value in ms (time).
|
|
278 |
*/
|
|
279 |
function timer_stop($name) { |
|
280 |
global $timers; |
|
281 |
||
282 |
$timers[$name]['time'] = timer_read($name); |
|
283 |
unset($timers[$name]['start']); |
|
284 |
||
285 |
return $timers[$name]; |
|
286 |
}
|
|
287 |
||
288 |
/**
|
|
289 |
* Find the appropriate configuration directory.
|
|
290 |
*
|
|
291 |
* Try finding a matching configuration directory by stripping the website's
|
|
292 |
* hostname from left to right and pathname from right to left. The first
|
|
293 |
* configuration file found will be used; the remaining will ignored. If no
|
|
294 |
* configuration file is found, return a default value '$confdir/default'.
|
|
295 |
*
|
|
296 |
* Example for a fictitious site installed at
|
|
297 |
* http://www.drupal.org:8080/mysite/test/ the 'settings.php' is searched in
|
|
298 |
* the following directories:
|
|
299 |
*
|
|
300 |
* 1. $confdir/8080.www.drupal.org.mysite.test
|
|
301 |
* 2. $confdir/www.drupal.org.mysite.test
|
|
302 |
* 3. $confdir/drupal.org.mysite.test
|
|
303 |
* 4. $confdir/org.mysite.test
|
|
304 |
*
|
|
305 |
* 5. $confdir/8080.www.drupal.org.mysite
|
|
306 |
* 6. $confdir/www.drupal.org.mysite
|
|
307 |
* 7. $confdir/drupal.org.mysite
|
|
308 |
* 8. $confdir/org.mysite
|
|
309 |
*
|
|
310 |
* 9. $confdir/8080.www.drupal.org
|
|
311 |
* 10. $confdir/www.drupal.org
|
|
312 |
* 11. $confdir/drupal.org
|
|
313 |
* 12. $confdir/org
|
|
314 |
*
|
|
315 |
* 13. $confdir/default
|
|
316 |
*
|
|
317 |
* @param $require_settings
|
|
318 |
* Only configuration directories with an existing settings.php file
|
|
319 |
* will be recognized. Defaults to TRUE. During initial installation,
|
|
320 |
* this is set to FALSE so that Drupal can detect a matching directory,
|
|
321 |
* then create a new settings.php file in it.
|
|
322 |
* @param reset
|
|
323 |
* Force a full search for matching directories even if one had been
|
|
324 |
* found previously.
|
|
325 |
* @return
|
|
326 |
* The path of the matching directory.
|
|
327 |
*/
|
|
328 |
function conf_path($require_settings = TRUE, $reset = FALSE) { |
|
329 |
static $conf = ''; |
|
330 |
||
331 |
if ($conf && !$reset) { |
|
332 |
return $conf; |
|
333 |
}
|
|
334 |
||
335 |
$confdir = 'sites'; |
|
336 |
$uri = explode('/', $_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['SCRIPT_FILENAME']); |
|
337 |
$server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.'))))); |
|
338 |
for ($i = count($uri) - 1; $i > 0; $i--) { |
|
339 |
for ($j = count($server); $j > 0; $j--) { |
|
340 |
$dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i)); |
|
341 |
if (file_exists("$confdir/$dir/settings.php") || (!$require_settings && file_exists("$confdir/$dir"))) { |
|
342 |
$conf = "$confdir/$dir"; |
|
343 |
return $conf; |
|
344 |
}
|
|
345 |
}
|
|
346 |
}
|
|
347 |
$conf = "$confdir/default"; |
|
348 |
return $conf; |
|
349 |
}
|
|
350 |
||
351 |
/**
|
|
352 |
* Unsets all disallowed global variables. See $allowed for what's allowed.
|
|
353 |
*/
|
|
354 |
function drupal_unset_globals() { |
|
355 |
if (ini_get('register_globals')) { |
|
356 |
$allowed = array('_ENV' => 1, '_GET' => 1, '_POST' => 1, '_COOKIE' => 1, '_FILES' => 1, '_SERVER' => 1, '_REQUEST' => 1, 'GLOBALS' => 1); |
|
357 |
foreach ($GLOBALS as $key => $value) { |
|
358 |
if (!isset($allowed[$key])) { |
|
359 |
unset($GLOBALS[$key]); |
|
360 |
}
|
|
361 |
}
|
|
362 |
}
|
|
363 |
}
|
|
364 |
||
365 |
/**
|
|
1.1.3
by bzr
Drupal 6.9 |
366 |
* Validate that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
|
1.1.1
by bzr
Drupal 6.7 |
367 |
*
|
368 |
* As $_SERVER['HTTP_HOST'] is user input, ensure it only contains characters
|
|
369 |
* allowed in hostnames. See RFC 952 (and RFC 2181). $_SERVER['HTTP_HOST'] is
|
|
370 |
* lowercased.
|
|
371 |
*
|
|
372 |
* @return
|
|
373 |
* TRUE if only containing valid characters, or FALSE otherwise.
|
|
374 |
*/
|
|
1.1.3
by bzr
Drupal 6.9 |
375 |
function drupal_valid_http_host($host) { |
376 |
return preg_match('/^\[?(?:[a-z0-9-:\]_]+\.?)+$/', $host); |
|
1.1.1
by bzr
Drupal 6.7 |
377 |
}
|
378 |
||
379 |
/**
|
|
1
by bzr
Drupal 6.6 |
380 |
* Loads the configuration and sets the base URL, cookie domain, and
|
381 |
* session name correctly.
|
|
382 |
*/
|
|
383 |
function conf_init() { |
|
384 |
global $base_url, $base_path, $base_root; |
|
385 |
||
386 |
// Export the following settings.php variables to the global namespace
|
|
1.4.4
by David Strauss
Properly load from settings.php. |
387 |
global $db_url, $db_slave_url, $db_prefix, $cookie_domain, $conf, $installed_profile, $update_free_access; |
1
by bzr
Drupal 6.6 |
388 |
$conf = array(); |
389 |
||
1.1.3
by bzr
Drupal 6.9 |
390 |
if (isset($_SERVER['HTTP_HOST'])) { |
391 |
// As HTTP_HOST is user input, ensure it only contains characters allowed
|
|
392 |
// in hostnames. See RFC 952 (and RFC 2181).
|
|
393 |
// $_SERVER['HTTP_HOST'] is lowercased here per specifications.
|
|
394 |
$_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']); |
|
395 |
if (!drupal_valid_http_host($_SERVER['HTTP_HOST'])) { |
|
396 |
// HTTP_HOST is invalid, e.g. if containing slashes it may be an attack.
|
|
397 |
header('HTTP/1.1 400 Bad Request'); |
|
398 |
exit; |
|
399 |
}
|
|
400 |
}
|
|
401 |
else { |
|
402 |
// Some pre-HTTP/1.1 clients will not send a Host header. Ensure the key is
|
|
403 |
// defined for E_ALL compliance.
|
|
404 |
$_SERVER['HTTP_HOST'] = ''; |
|
1.1.1
by bzr
Drupal 6.7 |
405 |
}
|
406 |
||
1
by bzr
Drupal 6.6 |
407 |
if (file_exists('./'. conf_path() .'/settings.php')) { |
408 |
include_once './'. conf_path() .'/settings.php'; |
|
409 |
}
|
|
410 |
||
411 |
// Ignore the placeholder url from default.settings.php.
|
|
412 |
if (isset($db_url) && $db_url == 'mysql://username:password@localhost/databasename') { |
|
413 |
$db_url = ''; |
|
414 |
}
|
|
415 |
||
416 |
if (isset($base_url)) { |
|
417 |
// Parse fixed base URL from settings.php.
|
|
418 |
$parts = parse_url($base_url); |
|
419 |
if (!isset($parts['path'])) { |
|
420 |
$parts['path'] = ''; |
|
421 |
}
|
|
422 |
$base_path = $parts['path'] .'/'; |
|
423 |
// Build $base_root (everything until first slash after "scheme://").
|
|
424 |
$base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path'])); |
|
425 |
}
|
|
426 |
else { |
|
427 |
// Create base URL
|
|
428 |
$base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; |
|
429 |
||
1.1.1
by bzr
Drupal 6.7 |
430 |
$base_url = $base_root .= '://'. $_SERVER['HTTP_HOST']; |
1
by bzr
Drupal 6.6 |
431 |
|
432 |
// $_SERVER['SCRIPT_NAME'] can, in contrast to $_SERVER['PHP_SELF'], not
|
|
433 |
// be modified by a visitor.
|
|
434 |
if ($dir = trim(dirname($_SERVER['SCRIPT_NAME']), '\,/')) { |
|
435 |
$base_path = "/$dir"; |
|
436 |
$base_url .= $base_path; |
|
437 |
$base_path .= '/'; |
|
438 |
}
|
|
439 |
else { |
|
440 |
$base_path = '/'; |
|
441 |
}
|
|
442 |
}
|
|
443 |
||
444 |
if ($cookie_domain) { |
|
445 |
// If the user specifies the cookie domain, also use it for session name.
|
|
446 |
$session_name = $cookie_domain; |
|
447 |
}
|
|
448 |
else { |
|
449 |
// Otherwise use $base_url as session name, without the protocol
|
|
450 |
// to use the same session identifiers across http and https.
|
|
451 |
list( , $session_name) = explode('://', $base_url, 2); |
|
452 |
// We escape the hostname because it can be modified by a visitor.
|
|
453 |
if (!empty($_SERVER['HTTP_HOST'])) { |
|
454 |
$cookie_domain = check_plain($_SERVER['HTTP_HOST']); |
|
1.1.11
by David Strauss
Drupal 6.17 |
455 |
// Strip leading periods, www., and port numbers from cookie domain.
|
456 |
$cookie_domain = ltrim($cookie_domain, '.'); |
|
457 |
if (strpos($cookie_domain, 'www.') === 0) { |
|
458 |
$cookie_domain = substr($cookie_domain, 4); |
|
459 |
}
|
|
460 |
$cookie_domain = explode(':', $cookie_domain); |
|
461 |
$cookie_domain = '.'. $cookie_domain[0]; |
|
1
by bzr
Drupal 6.6 |
462 |
}
|
463 |
}
|
|
464 |
// To prevent session cookies from being hijacked, a user can configure the
|
|
465 |
// SSL version of their website to only transfer session cookies via SSL by
|
|
466 |
// using PHP's session.cookie_secure setting. The browser will then use two
|
|
467 |
// separate session cookies for the HTTPS and HTTP versions of the site. So we
|
|
468 |
// must use different session identifiers for HTTPS and HTTP to prevent a
|
|
469 |
// cookie collision.
|
|
470 |
if (ini_get('session.cookie_secure')) { |
|
471 |
$session_name .= 'SSL'; |
|
472 |
}
|
|
473 |
// Per RFC 2109, cookie domains must contain at least one dot other than the
|
|
474 |
// first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
|
|
475 |
if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) { |
|
476 |
ini_set('session.cookie_domain', $cookie_domain); |
|
477 |
}
|
|
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
478 |
|
479 |
// Use httponly session cookies.
|
|
480 |
ini_set('session.cookie_httponly', '1'); |
|
481 |
||
1
by bzr
Drupal 6.6 |
482 |
session_name('SESS'. md5($session_name)); |
483 |
}
|
|
484 |
||
485 |
/**
|
|
486 |
* Returns and optionally sets the filename for a system item (module,
|
|
487 |
* theme, etc.). The filename, whether provided, cached, or retrieved
|
|
488 |
* from the database, is only returned if the file exists.
|
|
489 |
*
|
|
490 |
* This function plays a key role in allowing Drupal's resources (modules
|
|
491 |
* and themes) to be located in different places depending on a site's
|
|
492 |
* configuration. For example, a module 'foo' may legally be be located
|
|
493 |
* in any of these three places:
|
|
494 |
*
|
|
495 |
* modules/foo/foo.module
|
|
496 |
* sites/all/modules/foo/foo.module
|
|
497 |
* sites/example.com/modules/foo/foo.module
|
|
498 |
*
|
|
499 |
* Calling drupal_get_filename('module', 'foo') will give you one of
|
|
500 |
* the above, depending on where the module is located.
|
|
501 |
*
|
|
502 |
* @param $type
|
|
503 |
* The type of the item (i.e. theme, theme_engine, module).
|
|
504 |
* @param $name
|
|
505 |
* The name of the item for which the filename is requested.
|
|
506 |
* @param $filename
|
|
507 |
* The filename of the item if it is to be set explicitly rather
|
|
508 |
* than by consulting the database.
|
|
509 |
*
|
|
510 |
* @return
|
|
511 |
* The filename of the requested item.
|
|
512 |
*/
|
|
513 |
function drupal_get_filename($type, $name, $filename = NULL) { |
|
514 |
static $files = array(); |
|
515 |
||
516 |
if (!isset($files[$type])) { |
|
517 |
$files[$type] = array(); |
|
518 |
}
|
|
519 |
||
520 |
if (!empty($filename) && file_exists($filename)) { |
|
521 |
$files[$type][$name] = $filename; |
|
522 |
}
|
|
523 |
elseif (isset($files[$type][$name])) { |
|
524 |
// nothing
|
|
525 |
}
|
|
526 |
// Verify that we have an active database connection, before querying
|
|
527 |
// the database. This is required because this function is called both
|
|
528 |
// before we have a database connection (i.e. during installation) and
|
|
529 |
// when a database connection fails.
|
|
530 |
elseif (db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) { |
|
531 |
$files[$type][$name] = $file; |
|
532 |
}
|
|
533 |
else { |
|
534 |
// Fallback to searching the filesystem if the database connection is
|
|
535 |
// not established or the requested file is not found.
|
|
536 |
$config = conf_path(); |
|
537 |
$dir = (($type == 'theme_engine') ? 'themes/engines' : "${type}s"); |
|
538 |
$file = (($type == 'theme_engine') ? "$name.engine" : "$name.$type"); |
|
539 |
||
540 |
foreach (array("$config/$dir/$file", "$config/$dir/$name/$file", "$dir/$file", "$dir/$name/$file") as $file) { |
|
541 |
if (file_exists($file)) { |
|
542 |
$files[$type][$name] = $file; |
|
543 |
break; |
|
544 |
}
|
|
545 |
}
|
|
546 |
}
|
|
547 |
||
548 |
if (isset($files[$type][$name])) { |
|
549 |
return $files[$type][$name]; |
|
550 |
}
|
|
551 |
}
|
|
552 |
||
553 |
/**
|
|
554 |
* Load the persistent variable table.
|
|
555 |
*
|
|
556 |
* The variable table is composed of values that have been saved in the table
|
|
557 |
* with variable_set() as well as those explicitly specified in the configuration
|
|
558 |
* file.
|
|
559 |
*/
|
|
82.1.6
by David Strauss
Jed Prentice: Avoid infinite loop when the database connection fails in the middle of a request. |
560 |
function variable_init($conf = array(), $regenerate = FALSE, $recursion_depth = 0) { |
1
by bzr
Drupal 6.6 |
561 |
// NOTE: caching the variables improves performance by 20% when serving cached pages.
|
66.1.1
by David Strauss
Initial implementation of write-through variable caching. |
562 |
if (!$regenerate && $cached = cache_get('variables', 'cache')) { |
1
by bzr
Drupal 6.6 |
563 |
$variables = $cached->data; |
564 |
}
|
|
565 |
else { |
|
76
by David Strauss
Merge Drupal 6.16. Provide migration path to using upstream lock.inc implementation. |
566 |
if (defined('MAINTENANCE_MODE') || lock_acquire('variable_cache_regenerate')) { |
66.1.6
by David Strauss
Take advantage of the updated cache item instead of serializing rebuilds. |
567 |
$result = db_query('SELECT * FROM {variable}'); |
568 |
while ($variable = db_fetch_object($result)) { |
|
569 |
$variables[$variable->name] = unserialize($variable->value); |
|
570 |
}
|
|
571 |
cache_set('variables', $variables); |
|
76
by David Strauss
Merge Drupal 6.16. Provide migration path to using upstream lock.inc implementation. |
572 |
if (!defined('MAINTENANCE_MODE')) { |
573 |
lock_release('variable_cache_regenerate'); |
|
574 |
}
|
|
66.1.6
by David Strauss
Take advantage of the updated cache item instead of serializing rebuilds. |
575 |
}
|
576 |
else { |
|
66.1.5
by David Strauss
Use locks to prevent stampedes on cache misses. |
577 |
// Wait for another request that is already doing this work.
|
578 |
lock_wait('variable_cache_regenerate'); |
|
66.1.6
by David Strauss
Take advantage of the updated cache item instead of serializing rebuilds. |
579 |
|
82.1.6
by David Strauss
Jed Prentice: Avoid infinite loop when the database connection fails in the middle of a request. |
580 |
// Run the function again. Try a limited number of times to avoid
|
581 |
// infinite recursion if the database connection is invalid for
|
|
582 |
// some reason, e.g., mysqld restart, loss of network, etc.
|
|
583 |
$recursion_depth++; |
|
584 |
if ($recursion_depth < 50) { |
|
585 |
return variable_init($conf, $regenerate, $recursion_depth); |
|
586 |
}
|
|
587 |
||
588 |
$variables = array(); |
|
66.1.6
by David Strauss
Take advantage of the updated cache item instead of serializing rebuilds. |
589 |
}
|
1
by bzr
Drupal 6.6 |
590 |
}
|
591 |
||
592 |
foreach ($conf as $name => $value) { |
|
593 |
$variables[$name] = $value; |
|
594 |
}
|
|
595 |
||
596 |
return $variables; |
|
597 |
}
|
|
598 |
||
599 |
/**
|
|
1.1.13
by David Strauss
Drupal 6.19 |
600 |
* Returns a persistent variable.
|
601 |
*
|
|
602 |
* Case-sensitivity of the variable_* functions depends on the database
|
|
603 |
* collation used. To avoid problems, always use lower case for persistent
|
|
604 |
* variable names.
|
|
1
by bzr
Drupal 6.6 |
605 |
*
|
606 |
* @param $name
|
|
607 |
* The name of the variable to return.
|
|
608 |
* @param $default
|
|
609 |
* The default value to use if this variable has never been set.
|
|
610 |
* @return
|
|
611 |
* The value of the variable.
|
|
1.1.8
by David Strauss
Drupal 6.14 |
612 |
*
|
613 |
* @see variable_del(), variable_set()
|
|
1
by bzr
Drupal 6.6 |
614 |
*/
|
615 |
function variable_get($name, $default) { |
|
616 |
global $conf; |
|
617 |
||
618 |
return isset($conf[$name]) ? $conf[$name] : $default; |
|
619 |
}
|
|
620 |
||
621 |
/**
|
|
1.1.13
by David Strauss
Drupal 6.19 |
622 |
* Sets a persistent variable.
|
623 |
*
|
|
624 |
* Case-sensitivity of the variable_* functions depends on the database
|
|
625 |
* collation used. To avoid problems, always use lower case for persistent
|
|
626 |
* variable names.
|
|
1
by bzr
Drupal 6.6 |
627 |
*
|
628 |
* @param $name
|
|
629 |
* The name of the variable to set.
|
|
630 |
* @param $value
|
|
631 |
* The value to set. This can be any PHP data type; these functions take care
|
|
632 |
* of serialization as necessary.
|
|
1.1.8
by David Strauss
Drupal 6.14 |
633 |
*
|
634 |
* @see variable_del(), variable_get()
|
|
1
by bzr
Drupal 6.6 |
635 |
*/
|
636 |
function variable_set($name, $value) { |
|
74.2.1
by David Strauss
SimpleTest 1.10 |
637 |
global $conf, $db_prefix; |
1
by bzr
Drupal 6.6 |
638 |
|
639 |
$serialized_value = serialize($value); |
|
640 |
db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name); |
|
641 |
if (!db_affected_rows()) { |
|
642 |
@db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value); |
|
643 |
}
|
|
644 |
||
645 |
$conf[$name] = $value; |
|
66.1.1
by David Strauss
Initial implementation of write-through variable caching. |
646 |
|
74.2.1
by David Strauss
SimpleTest 1.10 |
647 |
// The write-through rebuild optimization isn't compatible with SimpleTest.
|
88
by David Strauss
Don't assume is a string (versus array) when checking for SimpleTest. |
648 |
// Because array-based prefixes don't work with SimpleTest, we can assume
|
649 |
// that a non-string prefix indicates lack of SimpleTest operations.
|
|
650 |
if (is_string($db_prefix) && strpos($db_prefix, 'simpletest') === 0) { |
|
74.2.1
by David Strauss
SimpleTest 1.10 |
651 |
cache_clear_all('variables', 'cache'); |
652 |
}
|
|
653 |
||
66.1.1
by David Strauss
Initial implementation of write-through variable caching. |
654 |
variable_cache_rebuild(); |
1
by bzr
Drupal 6.6 |
655 |
}
|
656 |
||
657 |
/**
|
|
1.1.13
by David Strauss
Drupal 6.19 |
658 |
* Unsets a persistent variable.
|
659 |
*
|
|
660 |
* Case-sensitivity of the variable_* functions depends on the database
|
|
661 |
* collation used. To avoid problems, always use lower case for persistent
|
|
662 |
* variable names.
|
|
1
by bzr
Drupal 6.6 |
663 |
*
|
664 |
* @param $name
|
|
665 |
* The name of the variable to undefine.
|
|
1.1.8
by David Strauss
Drupal 6.14 |
666 |
*
|
667 |
* @see variable_get(), variable_set()
|
|
1
by bzr
Drupal 6.6 |
668 |
*/
|
669 |
function variable_del($name) { |
|
74.2.1
by David Strauss
SimpleTest 1.10 |
670 |
global $conf, $db_prefix; |
1
by bzr
Drupal 6.6 |
671 |
|
672 |
db_query("DELETE FROM {variable} WHERE name = '%s'", $name); |
|
673 |
||
674 |
unset($conf[$name]); |
|
26
by David Strauss
Use a write-through strategy for variable deletion. |
675 |
|
74.2.1
by David Strauss
SimpleTest 1.10 |
676 |
// The write-through rebuild optimization isn't compatible with SimpleTest.
|
94
by David Strauss
David Strauss: Fix variable_del() when using an array-based database prefix. |
677 |
// Because array-based prefixes don't work with SimpleTest, we can assume
|
678 |
// that a non-string prefix indicates lack of SimpleTest operations.
|
|
679 |
if (is_string($db_prefix) && strpos($db_prefix, 'simpletest') === 0) { |
|
74.2.1
by David Strauss
SimpleTest 1.10 |
680 |
cache_clear_all('variables', 'cache'); |
681 |
}
|
|
682 |
||
66.1.1
by David Strauss
Initial implementation of write-through variable caching. |
683 |
variable_cache_rebuild(); |
1
by bzr
Drupal 6.6 |
684 |
}
|
685 |
||
66.1.1
by David Strauss
Initial implementation of write-through variable caching. |
686 |
/**
|
687 |
* Schedules a rebuild of the variable cache on shutdown.
|
|
688 |
*/
|
|
689 |
function variable_cache_rebuild() { |
|
690 |
static $shutdown_registered = FALSE; |
|
691 |
if (!$shutdown_registered) { |
|
692 |
register_shutdown_function('variable_init', array(), TRUE); |
|
693 |
$shutdown_registered = TRUE; |
|
694 |
}
|
|
695 |
}
|
|
1
by bzr
Drupal 6.6 |
696 |
|
697 |
/**
|
|
698 |
* Retrieve the current page from the cache.
|
|
699 |
*
|
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
700 |
* Note: we do not serve cached pages to authenticated users, or to anonymous
|
701 |
* users when $_SESSION is non-empty. $_SESSION may contain status messages
|
|
702 |
* from a form submission, the contents of a shopping cart, or other user-
|
|
703 |
* specific content that should not be cached and displayed to other users.
|
|
1
by bzr
Drupal 6.6 |
704 |
*
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
705 |
* @return
|
1.5.17
by David Strauss
Integrate DamZ's updated work. |
706 |
* The cache object, if the page was found in the cache.
|
1
by bzr
Drupal 6.6 |
707 |
*/
|
1.5.17
by David Strauss
Integrate DamZ's updated work. |
708 |
function page_get_cache() { |
1
by bzr
Drupal 6.6 |
709 |
global $user, $base_root; |
710 |
||
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
711 |
if (drupal_page_is_cacheable()) { |
1
by bzr
Drupal 6.6 |
712 |
$cache = cache_get($base_root . request_uri(), 'cache_page'); |
1.5.17
by David Strauss
Integrate DamZ's updated work. |
713 |
|
714 |
// Unserialize the cached page headers
|
|
1.5.14
by David Strauss
Move serialization of headers out of cache.inc to improve cache.inc substitution support. |
715 |
if (isset($cache->headers)) { |
716 |
$cache->headers = unserialize($cache->headers); |
|
717 |
}
|
|
1.5.17
by David Strauss
Integrate DamZ's updated work. |
718 |
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
719 |
if ($cache) { |
720 |
return $cache; |
|
721 |
}
|
|
1.5.17
by David Strauss
Integrate DamZ's updated work. |
722 |
}
|
723 |
}
|
|
724 |
||
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
725 |
function drupal_page_is_cacheable($force = NULL) { |
1.5.17
by David Strauss
Integrate DamZ's updated work. |
726 |
static $forced_cache = TRUE; |
727 |
if (isset($force)) { |
|
728 |
$forced_cache = $force; |
|
729 |
}
|
|
730 |
||
731 |
$result = $forced_cache |
|
1.5.25
by David Strauss
Remove drupal_session_is_started() in favor of only drupal_session_started(). |
732 |
&& !drupal_session_started() |
1.5.17
by David Strauss
Integrate DamZ's updated work. |
733 |
&& ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') |
734 |
&& !count(drupal_get_messages(NULL, FALSE)) |
|
55
by David Strauss
To fix Drush (Drupal.org #487300 and LP #422516), apply Drupal.org #581286 by David Strauss, DamZ, and moshe weitzman |
735 |
&& !drupal_is_cli(); |
1.5.17
by David Strauss
Integrate DamZ's updated work. |
736 |
|
737 |
return $result; |
|
1
by bzr
Drupal 6.6 |
738 |
}
|
739 |
||
740 |
/**
|
|
741 |
* Call all init or exit hooks without including all modules.
|
|
742 |
*
|
|
743 |
* @param $hook
|
|
744 |
* The name of the bootstrap hook we wish to invoke.
|
|
745 |
*/
|
|
746 |
function bootstrap_invoke_all($hook) { |
|
747 |
foreach (module_list(TRUE, TRUE) as $module) { |
|
748 |
drupal_load('module', $module); |
|
749 |
module_invoke($module, $hook); |
|
750 |
}
|
|
751 |
}
|
|
752 |
||
753 |
/**
|
|
754 |
* Includes a file with the provided type and name. This prevents
|
|
755 |
* including a theme, engine, module, etc., more than once.
|
|
756 |
*
|
|
757 |
* @param $type
|
|
758 |
* The type of item to load (i.e. theme, theme_engine, module).
|
|
759 |
* @param $name
|
|
760 |
* The name of the item to load.
|
|
761 |
*
|
|
762 |
* @return
|
|
763 |
* TRUE if the item is loaded or has already been loaded.
|
|
764 |
*/
|
|
765 |
function drupal_load($type, $name) { |
|
766 |
static $files = array(); |
|
767 |
||
768 |
if (isset($files[$type][$name])) { |
|
769 |
return TRUE; |
|
770 |
}
|
|
771 |
||
772 |
$filename = drupal_get_filename($type, $name); |
|
773 |
||
774 |
if ($filename) { |
|
775 |
include_once "./$filename"; |
|
776 |
$files[$type][$name] = TRUE; |
|
777 |
||
778 |
return TRUE; |
|
779 |
}
|
|
780 |
||
781 |
return FALSE; |
|
782 |
}
|
|
783 |
||
784 |
/**
|
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
785 |
* Set an HTTP response header for the current page.
|
786 |
*
|
|
787 |
* Note: When sending a Content-Type header, always include a 'charset' type,
|
|
788 |
* too. This is necessary to avoid security bugs (e.g. UTF-7 XSS).
|
|
789 |
*
|
|
790 |
* @param $name
|
|
791 |
* The HTTP header name, or a status code followed by a reason phrase, e.g.
|
|
792 |
* "404 Not Found".
|
|
793 |
* @param $value
|
|
794 |
* The HTTP header value; if omitted, the specified header is unset.
|
|
795 |
* @param $append
|
|
796 |
* Whether to append the value to an existing header or to replace it.
|
|
797 |
*/
|
|
798 |
function drupal_set_header($name = NULL, $value = NULL, $append = FALSE) { |
|
799 |
// The headers as name/value pairs.
|
|
800 |
static $headers = array(); |
|
801 |
||
802 |
if (!isset($name)) { |
|
803 |
return $headers; |
|
804 |
}
|
|
1.5.30
by David Strauss
Fix Drupal 6 headers API. |
805 |
|
806 |
// Support the Drupal 6 header API
|
|
807 |
if (!isset($value)) { |
|
808 |
if (strpos($name, ':') !== FALSE) { |
|
77
by David Strauss
Damien Tournoud: Fix parsing of HTTP headers containing a colon in the value. |
809 |
$parts = explode(':', $name, 2); |
1.5.30
by David Strauss
Fix Drupal 6 headers API. |
810 |
$name = trim($parts[0]); |
811 |
$value = trim($parts[1]); |
|
812 |
}
|
|
813 |
}
|
|
814 |
if (substr($name, 0, 7) == 'HTTP/1.') { |
|
815 |
$name = substr($name, 9); |
|
816 |
}
|
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
817 |
|
818 |
// Save status codes using the special key ":status".
|
|
819 |
if (preg_match('/^\d{3} /', $name)) { |
|
820 |
$value = $name; |
|
821 |
$name = $name_lower = ':status'; |
|
822 |
}
|
|
823 |
else { |
|
824 |
$name_lower = strtolower($name); |
|
825 |
}
|
|
826 |
_drupal_set_preferred_header_name($name); |
|
827 |
||
828 |
if (!isset($value)) { |
|
829 |
$headers[$name_lower] = FALSE; |
|
830 |
}
|
|
831 |
elseif (isset($headers[$name_lower]) && $append) { |
|
832 |
// Multiple headers with identical names may be combined using comma (RFC
|
|
833 |
// 2616, section 4.2).
|
|
834 |
$headers[$name_lower] .= ',' . $value; |
|
835 |
}
|
|
836 |
else { |
|
837 |
$headers[$name_lower] = $value; |
|
838 |
}
|
|
839 |
drupal_send_headers(array($name => $headers[$name_lower]), TRUE); |
|
840 |
}
|
|
841 |
||
842 |
/**
|
|
843 |
* Get the HTTP response headers for the current page.
|
|
844 |
*
|
|
845 |
* @param $name
|
|
846 |
* An HTTP header name. If omitted, all headers are returned as name/value
|
|
847 |
* pairs. If an array value is FALSE, the header has been unset.
|
|
848 |
* @return
|
|
849 |
* A string containing the header value, or FALSE if the header has been set,
|
|
850 |
* or NULL if the header has not been set.
|
|
851 |
*/
|
|
852 |
function drupal_get_header($name = NULL) { |
|
853 |
$headers = drupal_set_header(); |
|
854 |
if (isset($name)) { |
|
855 |
$name = strtolower($name); |
|
856 |
return isset($headers[$name]) ? $headers[$name] : NULL; |
|
857 |
}
|
|
858 |
else { |
|
859 |
return $headers; |
|
860 |
}
|
|
861 |
}
|
|
862 |
||
863 |
/**
|
|
864 |
* Header names are case-insensitive, but for maximum compatibility they should
|
|
865 |
* follow "common form" (see RFC 2617, section 4.2).
|
|
866 |
*/
|
|
867 |
function _drupal_set_preferred_header_name($name = NULL) { |
|
868 |
static $header_names = array(); |
|
869 |
||
870 |
if (!isset($name)) { |
|
871 |
return $header_names; |
|
872 |
}
|
|
873 |
$header_names[strtolower($name)] = $name; |
|
874 |
}
|
|
875 |
||
876 |
/**
|
|
877 |
* Send the HTTP response headers previously set using drupal_set_header().
|
|
878 |
* Add default headers, unless they have been replaced or unset using
|
|
879 |
* drupal_set_header().
|
|
880 |
*
|
|
881 |
* @param $default_headers
|
|
882 |
* An array of headers as name/value pairs.
|
|
883 |
* @param $single
|
|
884 |
* If TRUE and headers have already be sent, send only the specified header.
|
|
885 |
*/
|
|
886 |
function drupal_send_headers($default_headers = array(), $only_default = FALSE) { |
|
887 |
static $headers_sent = FALSE; |
|
888 |
$headers = drupal_get_header(); |
|
889 |
if ($only_default && $headers_sent) { |
|
890 |
$headers = array(); |
|
891 |
}
|
|
892 |
$headers_sent = TRUE; |
|
893 |
||
894 |
$header_names = _drupal_set_preferred_header_name(); |
|
895 |
foreach ($default_headers as $name => $value) { |
|
896 |
$name_lower = strtolower($name); |
|
897 |
if (!isset($headers[$name_lower])) { |
|
898 |
$headers[$name_lower] = $value; |
|
899 |
$header_names[$name_lower] = $name; |
|
900 |
}
|
|
901 |
}
|
|
902 |
foreach ($headers as $name_lower => $value) { |
|
903 |
if ($name_lower == ':status') { |
|
904 |
header($_SERVER['SERVER_PROTOCOL'] . ' ' . $value); |
|
905 |
}
|
|
906 |
// Skip headers that have been unset.
|
|
907 |
elseif ($value) { |
|
908 |
header($header_names[$name_lower] . ': ' . $value); |
|
909 |
}
|
|
910 |
}
|
|
911 |
}
|
|
912 |
||
913 |
/**
|
|
1
by bzr
Drupal 6.6 |
914 |
* Set HTTP headers in preparation for a page response.
|
915 |
*
|
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
916 |
* Authenticated users are always given a 'no-cache' header, and will fetch a
|
917 |
* fresh page on every request. This prevents authenticated users from seeing
|
|
918 |
* locally cached pages.
|
|
919 |
*
|
|
920 |
* Also give each page a unique ETag. This will force clients to include both
|
|
921 |
* an If-Modified-Since header and an If-None-Match header when doing
|
|
922 |
* conditional requests for the page (required by RFC 2616, section 13.3.4),
|
|
923 |
* making the validation more robust. This is a workaround for a bug in Mozilla
|
|
924 |
* Firefox that is triggered when Drupal's caching is enabled and the user
|
|
925 |
* accesses Drupal via an HTTP proxy (see
|
|
926 |
* https://bugzilla.mozilla.org/show_bug.cgi?id=269303): When an authenticated
|
|
927 |
* user requests a page, and then logs out and requests the same page again,
|
|
928 |
* Firefox may send a conditional request based on the page that was cached
|
|
929 |
* locally when the user was logged in. If this page did not have an ETag
|
|
930 |
* header, the request only contains an If-Modified-Since header. The date will
|
|
931 |
* be recent, because with authenticated users the Last-Modified header always
|
|
932 |
* refers to the time of the request. If the user accesses Drupal via a proxy
|
|
933 |
* server, and the proxy already has a cached copy of the anonymous page with an
|
|
934 |
* older Last-Modified date, the proxy may respond with 304 Not Modified, making
|
|
935 |
* the client think that the anonymous and authenticated pageviews are
|
|
936 |
* identical.
|
|
1
by bzr
Drupal 6.6 |
937 |
*
|
938 |
* @see page_set_cache()
|
|
939 |
*/
|
|
940 |
function drupal_page_header() { |
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
941 |
static $headers_sent = FALSE; |
942 |
if ($headers_sent) { |
|
943 |
return TRUE; |
|
944 |
}
|
|
945 |
$headers_sent = TRUE; |
|
22
by David Strauss
Initial, untested support for reverse proxy caches. |
946 |
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
947 |
$default_headers = array( |
948 |
'Last-Modified' => gmdate(DATE_RFC1123, $_SERVER['REQUEST_TIME']), |
|
949 |
'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0', |
|
1.5.10
by David Strauss
Fix etag. |
950 |
'ETag' => '"' . $_SERVER['REQUEST_TIME'] . '"', |
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
951 |
);
|
952 |
drupal_send_headers($default_headers); |
|
1
by bzr
Drupal 6.6 |
953 |
}
|
954 |
||
955 |
/**
|
|
63
by David Strauss
David Strauss: Add an 'external' caching mode that skips the built-in cache but still sends friendly headers downstream. |
956 |
* Set HTTP headers in for downstream caching.
|
957 |
*
|
|
958 |
* The headers allow as much as possible in proxies and browsers without any
|
|
959 |
* particular knowledge about the pages. Used for the external caching mode.
|
|
960 |
*/
|
|
961 |
function drupal_page_cache_header_external() { |
|
962 |
// Get headers set in hook_boot(). Keys are lower-case.
|
|
963 |
$hook_boot_headers = drupal_get_header(); |
|
964 |
||
965 |
$max_age = variable_get('page_cache_max_age', 0); |
|
966 |
drupal_set_header('Cache-Control', 'public, max-age=' . $max_age); |
|
967 |
drupal_set_header('Last-Modified', gmdate(DATE_RFC1123, $_SERVER['REQUEST_TIME'])); |
|
968 |
||
969 |
// HTTP/1.0 proxies do not support the Vary header, so prevent any caching
|
|
970 |
// by sending an Expires date in the past. HTTP/1.1 clients ignores the
|
|
971 |
// Expires header if a Cache-Control: max-age= directive is specified (see RFC
|
|
972 |
// 2616, section 14.9.3).
|
|
973 |
drupal_set_header('Expires', 'Sun, 11 Mar 1984 12:00:00 GMT'); |
|
974 |
||
975 |
// Allow HTTP proxies to cache pages for anonymous users without a session
|
|
976 |
// cookie. The Vary header is used to indicates the set of request-header
|
|
977 |
// fields that fully determines whether a cache is permitted to use the
|
|
978 |
// response to reply to a subsequent request for a given URL without
|
|
979 |
// revalidation. If a Vary header has been set in hook_boot(), it is assumed
|
|
980 |
// that the module knows how to cache the page.
|
|
981 |
if (!isset($hook_boot_headers['vary']) && !variable_get('omit_vary_cookie', FALSE)) { |
|
982 |
drupal_set_header('Vary', 'Cookie'); |
|
983 |
}
|
|
984 |
}
|
|
985 |
||
986 |
||
987 |
/**
|
|
1
by bzr
Drupal 6.6 |
988 |
* Set HTTP headers in preparation for a cached page response.
|
989 |
*
|
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
990 |
* The headers allow as much as possible in proxies and browsers without any
|
991 |
* particular knowledge about the pages. Modules can override these headers
|
|
992 |
* using drupal_set_header().
|
|
1
by bzr
Drupal 6.6 |
993 |
*
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
994 |
* If the request is conditional (using If-Modified-Since and If-None-Match),
|
995 |
* and the conditions match those currently in the cache, a 304 Not Modified
|
|
996 |
* response is sent.
|
|
1
by bzr
Drupal 6.6 |
997 |
*/
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
998 |
function drupal_page_cache_header(stdClass $cache) { |
999 |
// Negotiate whether to use compression.
|
|
1000 |
$page_compression = variable_get('page_compression', TRUE) && extension_loaded('zlib'); |
|
1001 |
$return_compressed = $page_compression && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE; |
|
1002 |
||
1003 |
// Get headers set in hook_boot(). Keys are lower-case.
|
|
1004 |
$hook_boot_headers = drupal_get_header(); |
|
1005 |
||
1006 |
// Headers generated in this function, that may be replaced or unset using
|
|
1007 |
// drupal_set_headers(). Keys are mixed-case.
|
|
1008 |
$default_headers = array(); |
|
1009 |
||
1010 |
foreach ($cache->headers as $name => $value) { |
|
1011 |
// In the case of a 304 response, certain headers must be sent, and the
|
|
1012 |
// remaining may not (see RFC 2616, section 10.3.5). Do not override
|
|
1013 |
// headers set in hook_boot().
|
|
1014 |
$name_lower = strtolower($name); |
|
1015 |
if (in_array($name_lower, array('content-location', 'expires', 'cache-control', 'vary')) && !isset($hook_boot_headers[$name_lower])) { |
|
1016 |
drupal_set_header($name, $value); |
|
1017 |
unset($cache->headers[$name]); |
|
1018 |
}
|
|
1019 |
}
|
|
1020 |
||
1021 |
// If a cache is served from a HTTP proxy without hitting the web server,
|
|
1022 |
// the boot and exit hooks cannot be fired, so only allow caching in
|
|
1023 |
// proxies with aggressive caching. If the client send a session cookie, do
|
|
1024 |
// not bother caching the page in a public proxy, because the cached copy
|
|
1025 |
// will only be served to that particular user due to Vary: Cookie, unless
|
|
1026 |
// the Vary header has been replaced or unset in hook_boot() (see below).
|
|
1.5.29
by David Strauss
Fix undefined constant. |
1027 |
$max_age = variable_get('cache', CACHE_DISABLED) == CACHE_AGGRESSIVE && (!isset($_COOKIE[session_name()]) || isset($hook_boot_headers['vary'])) ? variable_get('page_cache_max_age', 0) : 0; |
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
1028 |
$default_headers['Cache-Control'] = 'public, max-age=' . $max_age; |
1029 |
||
1030 |
// Entity tag should change if the output changes.
|
|
1031 |
$etag = '"' . $cache->created . '-' . intval($return_compressed) . '"'; |
|
1032 |
header('Etag: ' . $etag); |
|
1033 |
||
1034 |
// See if the client has provided the required HTTP headers.
|
|
1035 |
$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE; |
|
1036 |
$if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE; |
|
1037 |
||
1038 |
if ($if_modified_since && $if_none_match |
|
1039 |
&& $if_none_match == $etag // etag must match |
|
1040 |
&& $if_modified_since == $cache->created) { // if-modified-since must match |
|
1041 |
header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified'); |
|
1042 |
drupal_send_headers($default_headers); |
|
1043 |
return; |
|
1044 |
}
|
|
1045 |
||
1046 |
// Send the remaining headers.
|
|
1047 |
foreach ($cache->headers as $name => $value) { |
|
1048 |
drupal_set_header($name, $value); |
|
1049 |
}
|
|
1050 |
||
1051 |
$default_headers['Last-Modified'] = gmdate(DATE_RFC1123, $cache->created); |
|
1052 |
||
1.5.17
by David Strauss
Integrate DamZ's updated work. |
1053 |
// HTTP/1.0 proxies do not support the Vary header, so prevent any caching
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
1054 |
// by sending an Expires date in the past. HTTP/1.1 clients ignores the
|
1055 |
// Expires header if a Cache-Control: max-age= directive is specified (see RFC
|
|
1056 |
// 2616, section 14.9.3).
|
|
35
by David Strauss
Initial merge of updated reverse proxy support. |
1057 |
$default_headers['Expires'] = 'Sun, 11 Mar 1984 12:00:00 GMT'; |
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
1058 |
|
1059 |
drupal_send_headers($default_headers); |
|
1060 |
||
1061 |
// Allow HTTP proxies to cache pages for anonymous users without a session
|
|
1062 |
// cookie. The Vary header is used to indicates the set of request-header
|
|
1063 |
// fields that fully determines whether a cache is permitted to use the
|
|
1064 |
// response to reply to a subsequent request for a given URL without
|
|
1065 |
// revalidation. If a Vary header has been set in hook_boot(), it is assumed
|
|
1066 |
// that the module knows how to cache the page.
|
|
1067 |
if (!isset($hook_boot_headers['vary']) && !variable_get('omit_vary_cookie', FALSE)) { |
|
1068 |
header('Vary: Cookie'); |
|
1069 |
}
|
|
1070 |
||
1071 |
if ($page_compression) { |
|
1072 |
header('Vary: Accept-Encoding', FALSE); |
|
1073 |
// If page_compression is enabled, the cache contains gzipped data.
|
|
1074 |
if ($return_compressed) { |
|
82.1.2
by David Strauss
Fix double output from page caching. Deliver proper gzip-compressed pages without double compression. |
1075 |
ini_set('zlib.output_compression', '0'); |
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
1076 |
header('Content-Encoding: gzip'); |
1077 |
}
|
|
1078 |
else { |
|
1079 |
// The client does not support compression, so unzip the data in the
|
|
1080 |
// cache. Strip the gzip header and run uncompress.
|
|
1
by bzr
Drupal 6.6 |
1081 |
$cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8)); |
82.1.2
by David Strauss
Fix double output from page caching. Deliver proper gzip-compressed pages without double compression. |
1082 |
header('X-PF-Uncompressing: 1'); |
1
by bzr
Drupal 6.6 |
1083 |
}
|
1084 |
}
|
|
1085 |
||
1086 |
print $cache->data; |
|
1087 |
}
|
|
1088 |
||
1089 |
/**
|
|
1090 |
* Define the critical hooks that force modules to always be loaded.
|
|
1091 |
*/
|
|
1092 |
function bootstrap_hooks() { |
|
1093 |
return array('boot', 'exit'); |
|
1094 |
}
|
|
1095 |
||
1096 |
/**
|
|
1097 |
* Unserializes and appends elements from a serialized string.
|
|
1098 |
*
|
|
1099 |
* @param $obj
|
|
1100 |
* The object to which the elements are appended.
|
|
1101 |
* @param $field
|
|
1102 |
* The attribute of $obj whose value should be unserialized.
|
|
1103 |
*/
|
|
1104 |
function drupal_unpack($obj, $field = 'data') { |
|
1105 |
if ($obj->$field && $data = unserialize($obj->$field)) { |
|
1106 |
foreach ($data as $key => $value) { |
|
1.1.13
by David Strauss
Drupal 6.19 |
1107 |
if (!empty($key) && !isset($obj->$key)) { |
1
by bzr
Drupal 6.6 |
1108 |
$obj->$key = $value; |
1109 |
}
|
|
1110 |
}
|
|
1111 |
}
|
|
1112 |
return $obj; |
|
1113 |
}
|
|
1114 |
||
1115 |
/**
|
|
1116 |
* Return the URI of the referring page.
|
|
1117 |
*/
|
|
1118 |
function referer_uri() { |
|
1119 |
if (isset($_SERVER['HTTP_REFERER'])) { |
|
1120 |
return $_SERVER['HTTP_REFERER']; |
|
1121 |
}
|
|
1122 |
}
|
|
1123 |
||
1124 |
/**
|
|
1125 |
* Encode special characters in a plain-text string for display as HTML.
|
|
1126 |
*
|
|
1.1.11
by David Strauss
Drupal 6.17 |
1127 |
* Also validates strings as UTF-8 to prevent cross site scripting attacks on
|
1
by bzr
Drupal 6.6 |
1128 |
* Internet Explorer 6.
|
1.1.11
by David Strauss
Drupal 6.17 |
1129 |
*
|
1130 |
* @param $text
|
|
1131 |
* The text to be checked or processed.
|
|
1132 |
* @return
|
|
1133 |
* An HTML safe version of $text, or an empty string if $text is not
|
|
1134 |
* valid UTF-8.
|
|
1135 |
*
|
|
1136 |
* @see drupal_validate_utf8().
|
|
1
by bzr
Drupal 6.6 |
1137 |
*/
|
1138 |
function check_plain($text) { |
|
1.1.11
by David Strauss
Drupal 6.17 |
1139 |
static $php525; |
1140 |
||
1141 |
if (!isset($php525)) { |
|
1142 |
$php525 = version_compare(PHP_VERSION, '5.2.5', '>='); |
|
1143 |
}
|
|
1144 |
// We duplicate the preg_match() to validate strings as UTF-8 from
|
|
1145 |
// drupal_validate_utf8() here. This avoids the overhead of an additional
|
|
1146 |
// function call, since check_plain() may be called hundreds of times during
|
|
1147 |
// a request. For PHP 5.2.5+, this check for valid UTF-8 should be handled
|
|
1148 |
// internally by PHP in htmlspecialchars().
|
|
1149 |
// @see http://www.php.net/releases/5_2_5.php
|
|
1150 |
// @todo remove this when support for either IE6 or PHP < 5.2.5 is dropped.
|
|
1151 |
||
1152 |
if ($php525) { |
|
1153 |
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); |
|
1154 |
}
|
|
1155 |
return (preg_match('/^./us', $text) == 1) ? htmlspecialchars($text, ENT_QUOTES, 'UTF-8') : ''; |
|
1
by bzr
Drupal 6.6 |
1156 |
}
|
1157 |
||
1158 |
/**
|
|
1159 |
* Checks whether a string is valid UTF-8.
|
|
1160 |
*
|
|
1161 |
* All functions designed to filter input should use drupal_validate_utf8
|
|
1162 |
* to ensure they operate on valid UTF-8 strings to prevent bypass of the
|
|
1163 |
* filter.
|
|
1164 |
*
|
|
1165 |
* When text containing an invalid UTF-8 lead byte (0xC0 - 0xFF) is presented
|
|
1166 |
* as UTF-8 to Internet Explorer 6, the program may misinterpret subsequent
|
|
1167 |
* bytes. When these subsequent bytes are HTML control characters such as
|
|
1168 |
* quotes or angle brackets, parts of the text that were deemed safe by filters
|
|
1169 |
* end up in locations that are potentially unsafe; An onerror attribute that
|
|
1170 |
* is outside of a tag, and thus deemed safe by a filter, can be interpreted
|
|
1171 |
* by the browser as if it were inside the tag.
|
|
1172 |
*
|
|
1173 |
* This function exploits preg_match behaviour (since PHP 4.3.5) when used
|
|
1174 |
* with the u modifier, as a fast way to find invalid UTF-8. When the matched
|
|
1175 |
* string contains an invalid byte sequence, it will fail silently.
|
|
1176 |
*
|
|
1177 |
* preg_match may not fail on 4 and 5 octet sequences, even though they
|
|
1178 |
* are not supported by the specification.
|
|
1179 |
*
|
|
1180 |
* The specific preg_match behaviour is present since PHP 4.3.5.
|
|
1181 |
*
|
|
1182 |
* @param $text
|
|
1183 |
* The text to check.
|
|
1184 |
* @return
|
|
1185 |
* TRUE if the text is valid UTF-8, FALSE if not.
|
|
1186 |
*/
|
|
1187 |
function drupal_validate_utf8($text) { |
|
1188 |
if (strlen($text) == 0) { |
|
1189 |
return TRUE; |
|
1190 |
}
|
|
1.1.11
by David Strauss
Drupal 6.17 |
1191 |
// For performance reasons this logic is duplicated in check_plain().
|
1
by bzr
Drupal 6.6 |
1192 |
return (preg_match('/^./us', $text) == 1); |
1193 |
}
|
|
1194 |
||
1195 |
/**
|
|
1196 |
* Since $_SERVER['REQUEST_URI'] is only available on Apache, we
|
|
1197 |
* generate an equivalent using other environment variables.
|
|
1198 |
*/
|
|
1199 |
function request_uri() { |
|
1200 |
||
1201 |
if (isset($_SERVER['REQUEST_URI'])) { |
|
1202 |
$uri = $_SERVER['REQUEST_URI']; |
|
1203 |
}
|
|
1204 |
else { |
|
1205 |
if (isset($_SERVER['argv'])) { |
|
1206 |
$uri = $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['argv'][0]; |
|
1207 |
}
|
|
1208 |
elseif (isset($_SERVER['QUERY_STRING'])) { |
|
1209 |
$uri = $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['QUERY_STRING']; |
|
1210 |
}
|
|
1211 |
else { |
|
1212 |
$uri = $_SERVER['SCRIPT_NAME']; |
|
1213 |
}
|
|
1214 |
}
|
|
1.1.5
by bzr
Drupal 6.11 |
1215 |
// Prevent multiple slashes to avoid cross site requests via the FAPI.
|
1216 |
$uri = '/'. ltrim($uri, '/'); |
|
1
by bzr
Drupal 6.6 |
1217 |
|
1218 |
return $uri; |
|
1219 |
}
|
|
1220 |
||
1221 |
/**
|
|
1222 |
* Log a system message.
|
|
1223 |
*
|
|
1224 |
* @param $type
|
|
1.1.13
by David Strauss
Drupal 6.19 |
1225 |
* The category to which this message belongs. Can be any string, but the
|
1226 |
* general practice is to use the name of the module calling watchdog().
|
|
1
by bzr
Drupal 6.6 |
1227 |
* @param $message
|
1228 |
* The message to store in the log. See t() for documentation
|
|
1229 |
* on how $message and $variables interact. Keep $message
|
|
1230 |
* translatable by not concatenating dynamic values into it!
|
|
1231 |
* @param $variables
|
|
1232 |
* Array of variables to replace in the message on display or
|
|
1233 |
* NULL if message is already translated or not possible to
|
|
1234 |
* translate.
|
|
1235 |
* @param $severity
|
|
1.1.13
by David Strauss
Drupal 6.19 |
1236 |
* The severity of the message, as per RFC 3164. Possible values are
|
1237 |
* WATCHDOG_ERROR, WATCHDOG_WARNING, etc.
|
|
1
by bzr
Drupal 6.6 |
1238 |
* @param $link
|
1239 |
* A link to associate with the message.
|
|
1240 |
*
|
|
1241 |
* @see watchdog_severity_levels()
|
|
1242 |
*/
|
|
1243 |
function watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) { |
|
1244 |
global $user, $base_root; |
|
1245 |
||
1246 |
// Prepare the fields to be logged
|
|
1247 |
$log_message = array( |
|
1248 |
'type' => $type, |
|
1249 |
'message' => $message, |
|
1250 |
'variables' => $variables, |
|
1251 |
'severity' => $severity, |
|
1252 |
'link' => $link, |
|
1253 |
'user' => $user, |
|
1254 |
'request_uri' => $base_root . request_uri(), |
|
1255 |
'referer' => referer_uri(), |
|
1256 |
'ip' => ip_address(), |
|
1257 |
'timestamp' => time(), |
|
1258 |
);
|
|
1259 |
||
1260 |
// Call the logging hooks to log/process the message
|
|
1.1.13
by David Strauss
Drupal 6.19 |
1261 |
foreach (module_implements('watchdog') as $module) { |
1
by bzr
Drupal 6.6 |
1262 |
module_invoke($module, 'watchdog', $log_message); |
1263 |
}
|
|
1264 |
}
|
|
1265 |
||
1266 |
/**
|
|
1267 |
* Set a message which reflects the status of the performed operation.
|
|
1268 |
*
|
|
1269 |
* If the function is called with no arguments, this function returns all set
|
|
1270 |
* messages without clearing them.
|
|
1271 |
*
|
|
1272 |
* @param $message
|
|
1273 |
* The message should begin with a capital letter and always ends with a
|
|
1274 |
* period '.'.
|
|
1275 |
* @param $type
|
|
1276 |
* The type of the message. One of the following values are possible:
|
|
1277 |
* - 'status'
|
|
1278 |
* - 'warning'
|
|
1279 |
* - 'error'
|
|
1280 |
* @param $repeat
|
|
1281 |
* If this is FALSE and the message is already set, then the message won't
|
|
1282 |
* be repeated.
|
|
1283 |
*/
|
|
1284 |
function drupal_set_message($message = NULL, $type = 'status', $repeat = TRUE) { |
|
1285 |
if ($message) { |
|
1286 |
if (!isset($_SESSION['messages'])) { |
|
1.5.12
by David Strauss
Allow errors during installation. |
1287 |
if (function_exists('drupal_set_session')) { |
1288 |
drupal_set_session('messages', array()); |
|
1289 |
}
|
|
1290 |
else { |
|
1291 |
$_SESSION['messages'] = array(); |
|
1292 |
}
|
|
1
by bzr
Drupal 6.6 |
1293 |
}
|
1294 |
||
1295 |
if (!isset($_SESSION['messages'][$type])) { |
|
1296 |
$_SESSION['messages'][$type] = array(); |
|
1297 |
}
|
|
1298 |
||
1299 |
if ($repeat || !in_array($message, $_SESSION['messages'][$type])) { |
|
1300 |
$_SESSION['messages'][$type][] = $message; |
|
1301 |
}
|
|
1302 |
}
|
|
1303 |
||
1304 |
// messages not set when DB connection fails
|
|
1305 |
return isset($_SESSION['messages']) ? $_SESSION['messages'] : NULL; |
|
1306 |
}
|
|
1307 |
||
1308 |
/**
|
|
1309 |
* Return all messages that have been set.
|
|
1310 |
*
|
|
1311 |
* @param $type
|
|
1312 |
* (optional) Only return messages of this type.
|
|
1313 |
* @param $clear_queue
|
|
1314 |
* (optional) Set to FALSE if you do not want to clear the messages queue
|
|
1315 |
* @return
|
|
1316 |
* An associative array, the key is the message type, the value an array
|
|
1317 |
* of messages. If the $type parameter is passed, you get only that type,
|
|
1318 |
* or an empty array if there are no such messages. If $type is not passed,
|
|
1319 |
* all message types are returned, or an empty array if none exist.
|
|
1320 |
*/
|
|
1321 |
function drupal_get_messages($type = NULL, $clear_queue = TRUE) { |
|
1322 |
if ($messages = drupal_set_message()) { |
|
1323 |
if ($type) { |
|
1324 |
if ($clear_queue) { |
|
1325 |
unset($_SESSION['messages'][$type]); |
|
1326 |
}
|
|
1327 |
if (isset($messages[$type])) { |
|
1328 |
return array($type => $messages[$type]); |
|
1329 |
}
|
|
1330 |
}
|
|
1331 |
else { |
|
1332 |
if ($clear_queue) { |
|
1333 |
unset($_SESSION['messages']); |
|
1334 |
}
|
|
1335 |
return $messages; |
|
1336 |
}
|
|
1337 |
}
|
|
1338 |
return array(); |
|
1339 |
}
|
|
1340 |
||
1341 |
/**
|
|
1342 |
* Perform an access check for a given mask and rule type. Rules are usually
|
|
1343 |
* created via admin/user/rules page.
|
|
1344 |
*
|
|
1345 |
* If any allow rule matches, access is allowed. Otherwise, if any deny rule
|
|
1346 |
* matches, access is denied. If no rule matches, access is allowed.
|
|
1347 |
*
|
|
1348 |
* @param $type string
|
|
1349 |
* Type of access to check: Allowed values are:
|
|
1350 |
* - 'host': host name or IP address
|
|
1351 |
* - 'mail': e-mail address
|
|
1352 |
* - 'user': username
|
|
1353 |
* @param $mask string
|
|
1354 |
* String or mask to test: '_' matches any character, '%' matches any
|
|
1355 |
* number of characters.
|
|
1356 |
* @return bool
|
|
1357 |
* TRUE if access is denied, FALSE if access is allowed.
|
|
1358 |
*/
|
|
1359 |
function drupal_is_denied($type, $mask) { |
|
1360 |
// Because this function is called for every page request, both cached
|
|
1361 |
// and non-cached pages, we tried to optimize it as much as possible.
|
|
1362 |
// We deny access if the only matching records in the {access} table have
|
|
1363 |
// status 0 (deny). If any have status 1 (allow), or if there are no
|
|
1364 |
// matching records, we allow access.
|
|
3
by David Strauss
Remove all instances of LOWER(). |
1365 |
$sql = "SELECT 1 FROM {access} WHERE type = '%s' AND '%s' LIKE mask AND status = %d"; |
1
by bzr
Drupal 6.6 |
1366 |
return db_result(db_query_range($sql, $type, $mask, 0, 0, 1)) && !db_result(db_query_range($sql, $type, $mask, 1, 0, 1)); |
1367 |
}
|
|
1368 |
||
1369 |
/**
|
|
1370 |
* Generates a default anonymous $user object.
|
|
1371 |
*
|
|
1372 |
* @return Object - the user object.
|
|
1373 |
*/
|
|
1374 |
function drupal_anonymous_user($session = '') { |
|
1375 |
$user = new stdClass(); |
|
1376 |
$user->uid = 0; |
|
1377 |
$user->hostname = ip_address(); |
|
1378 |
$user->roles = array(); |
|
1379 |
$user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; |
|
1380 |
$user->session = $session; |
|
1381 |
$user->cache = 0; |
|
1382 |
return $user; |
|
1383 |
}
|
|
1384 |
||
1385 |
/**
|
|
1386 |
* A string describing a phase of Drupal to load. Each phase adds to the
|
|
1387 |
* previous one, so invoking a later phase automatically runs the earlier
|
|
1388 |
* phases too. The most important usage is that if you want to access the
|
|
1389 |
* Drupal database from a script without loading anything else, you can
|
|
1390 |
* include bootstrap.inc, and call drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE).
|
|
1391 |
*
|
|
1392 |
* @param $phase
|
|
1393 |
* A constant. Allowed values are:
|
|
1394 |
* DRUPAL_BOOTSTRAP_CONFIGURATION: initialize configuration.
|
|
1395 |
* DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: try to call a non-database cache fetch routine.
|
|
1396 |
* DRUPAL_BOOTSTRAP_DATABASE: initialize database layer.
|
|
1397 |
* DRUPAL_BOOTSTRAP_ACCESS: identify and reject banned hosts.
|
|
1398 |
* DRUPAL_BOOTSTRAP_SESSION: initialize session handling.
|
|
1399 |
* DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: load bootstrap.inc and module.inc, start
|
|
1400 |
* the variable system and try to serve a page from the cache.
|
|
1401 |
* DRUPAL_BOOTSTRAP_LANGUAGE: identify the language used on the page.
|
|
1402 |
* DRUPAL_BOOTSTRAP_PATH: set $_GET['q'] to Drupal path of request.
|
|
1403 |
* DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data.
|
|
1404 |
*/
|
|
74.2.2
by David Strauss
Backport drupal_get_bootstrap_phase() from Drupal 7 to support SimpleTest. |
1405 |
function drupal_bootstrap($phase = NULL) { |
1
by bzr
Drupal 6.6 |
1406 |
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; |
1407 |
||
74.2.2
by David Strauss
Backport drupal_get_bootstrap_phase() from Drupal 7 to support SimpleTest. |
1408 |
if (isset($phase)) { |
1409 |
while ($phase >= $phase_index && isset($phases[$phase_index])) { |
|
1410 |
$current_phase = $phases[$phase_index]; |
|
1411 |
unset($phases[$phase_index++]); |
|
1412 |
_drupal_bootstrap($current_phase); |
|
1413 |
}
|
|
1
by bzr
Drupal 6.6 |
1414 |
}
|
74.2.2
by David Strauss
Backport drupal_get_bootstrap_phase() from Drupal 7 to support SimpleTest. |
1415 |
|
1416 |
return $phase_index; |
|
1
by bzr
Drupal 6.6 |
1417 |
}
|
1418 |
||
88.1.1
by David Strauss
Add "pressflow_smart_start" configuration option to enable redirecting to the installer when a valid settings.php is present but no site is installed. |
1419 |
/**
|
1420 |
* Redirect to the installer if an essential table is missing.
|
|
1421 |
*/
|
|
1422 |
function detect_installation_or_run_installer() { |
|
1423 |
if (variable_get('pressflow_smart_start', FALSE) && !db_table_exists('access')) { |
|
1424 |
include_once 'includes/install.inc'; |
|
1425 |
install_goto('install.php'); |
|
1426 |
}
|
|
1427 |
}
|
|
1428 |
||
1
by bzr
Drupal 6.6 |
1429 |
function _drupal_bootstrap($phase) { |
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1430 |
global $conf, $user, $db_prefix; |
1
by bzr
Drupal 6.6 |
1431 |
|
1432 |
switch ($phase) { |
|
1433 |
||
1434 |
case DRUPAL_BOOTSTRAP_CONFIGURATION: |
|
1435 |
drupal_unset_globals(); |
|
1436 |
// Start a page timer:
|
|
1437 |
timer_start('page'); |
|
1438 |
// Initialize the configuration
|
|
1439 |
conf_init(); |
|
1440 |
break; |
|
1441 |
||
1442 |
case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: |
|
1443 |
// Allow specifying special cache handlers in settings.php, like
|
|
1444 |
// using memcached or files for storing cache information.
|
|
1445 |
require_once variable_get('cache_inc', './includes/cache.inc'); |
|
1446 |
// If the page_cache_fastpath is set to TRUE in settings.php and
|
|
1447 |
// page_cache_fastpath (implemented in the special implementation of
|
|
1448 |
// cache.inc) printed the page and indicated this with a returned TRUE
|
|
1449 |
// then we are done.
|
|
1450 |
if (variable_get('page_cache_fastpath', FALSE) && page_cache_fastpath()) { |
|
1451 |
exit; |
|
1452 |
}
|
|
1453 |
break; |
|
1454 |
||
1455 |
case DRUPAL_BOOTSTRAP_DATABASE: |
|
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1456 |
// The user agent header is used to pass a database prefix in the request when
|
1457 |
// running tests. However, for security reasons, it is imperative that we
|
|
1458 |
// validate we ourselves made the request.
|
|
47.1.5
by Josh Koenig
merging in changes from Simpletest 6-2.9 |
1459 |
$GLOBALS['simpletest_installed'] = TRUE; |
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1460 |
if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);/", $_SERVER['HTTP_USER_AGENT'], $matches)) { |
74.2.1
by David Strauss
SimpleTest 1.10 |
1461 |
if (!drupal_valid_test_ua($_SERVER['HTTP_USER_AGENT'])) { |
1462 |
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); |
|
1463 |
exit; |
|
1464 |
}
|
|
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1465 |
$db_prefix .= $matches[1]; |
1466 |
}
|
|
1467 |
||
1
by bzr
Drupal 6.6 |
1468 |
// Initialize the default database.
|
1469 |
require_once './includes/database.inc'; |
|
1470 |
db_set_active(); |
|
1.1.11
by David Strauss
Drupal 6.17 |
1471 |
// Allow specifying alternate lock implementations in settings.php, like
|
1472 |
// those using APC or memcached.
|
|
1473 |
require_once variable_get('lock_inc', './includes/lock.inc'); |
|
1474 |
lock_init(); |
|
88.1.1
by David Strauss
Add "pressflow_smart_start" configuration option to enable redirecting to the installer when a valid settings.php is present but no site is installed. |
1475 |
|
1476 |
// Detect if an installation is present.
|
|
1477 |
detect_installation_or_run_installer(); |
|
1478 |
||
1
by bzr
Drupal 6.6 |
1479 |
break; |
1480 |
||
1481 |
case DRUPAL_BOOTSTRAP_ACCESS: |
|
1482 |
// Deny access to hosts which were banned - t() is not yet available.
|
|
1483 |
if (drupal_is_denied('host', ip_address())) { |
|
1484 |
header('HTTP/1.1 403 Forbidden'); |
|
1485 |
print 'Sorry, '. check_plain(ip_address()) .' has been banned.'; |
|
1486 |
exit(); |
|
1487 |
}
|
|
1488 |
break; |
|
1489 |
||
1490 |
case DRUPAL_BOOTSTRAP_SESSION: |
|
1491 |
require_once variable_get('session_inc', './includes/session.inc'); |
|
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1492 |
drupal_session_initialize(); |
1
by bzr
Drupal 6.6 |
1493 |
break; |
1494 |
||
1495 |
case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: |
|
1496 |
// Initialize configuration variables, using values from settings.php if available.
|
|
1497 |
$conf = variable_init(isset($conf) ? $conf : array()); |
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
1498 |
|
1
by bzr
Drupal 6.6 |
1499 |
$cache_mode = variable_get('cache', CACHE_DISABLED); |
63
by David Strauss
David Strauss: Add an 'external' caching mode that skips the built-in cache but still sends friendly headers downstream. |
1500 |
// Get the page from the cache, unless the cache is disabled or external.
|
1501 |
if ($cache_mode != CACHE_DISABLED && $cache_mode != CACHE_EXTERNAL) { |
|
1.5.17
by David Strauss
Integrate DamZ's updated work. |
1502 |
$cache = page_get_cache(); |
1503 |
}
|
|
1504 |
else { |
|
1505 |
$cache = FALSE; |
|
1506 |
}
|
|
1507 |
||
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
1508 |
// If the skipping of the bootstrap hooks is not enforced, call hook_init.
|
1509 |
if (!is_object($cache) || $cache_mode != CACHE_AGGRESSIVE) { |
|
1.1.3
by bzr
Drupal 6.9 |
1510 |
// Load module handling.
|
1511 |
require_once './includes/module.inc'; |
|
1.5.11
by David Strauss
Fix anon user bootstrap and changes for D6 boot phases. |
1512 |
bootstrap_invoke_all('boot'); |
1
by bzr
Drupal 6.6 |
1513 |
}
|
1.5.17
by David Strauss
Integrate DamZ's updated work. |
1514 |
|
1
by bzr
Drupal 6.6 |
1515 |
// If there is a cached page, display it.
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
1516 |
if (is_object($cache)) { |
1517 |
header('X-Drupal-Cache: HIT'); |
|
1
by bzr
Drupal 6.6 |
1518 |
drupal_page_cache_header($cache); |
1519 |
// If the skipping of the bootstrap hooks is not enforced, call hook_exit.
|
|
1520 |
if ($cache_mode != CACHE_AGGRESSIVE) { |
|
1521 |
bootstrap_invoke_all('exit'); |
|
1522 |
}
|
|
1523 |
// We are done.
|
|
1524 |
exit; |
|
1525 |
}
|
|
1.5.5
by David Strauss
Initial port of drupal.org #147310 and #201122. |
1526 |
|
63
by David Strauss
David Strauss: Add an 'external' caching mode that skips the built-in cache but still sends friendly headers downstream. |
1527 |
if (!$cache && drupal_page_is_cacheable() && $cache_mode != CACHE_EXTERNAL) { |
1.5.17
by David Strauss
Integrate DamZ's updated work. |
1528 |
header('X-Drupal-Cache: MISS'); |
1529 |
}
|
|
63
by David Strauss
David Strauss: Add an 'external' caching mode that skips the built-in cache but still sends friendly headers downstream. |
1530 |
|
1531 |
// If using an external cache and the page is cacheable, set headers.
|
|
1532 |
if ($cache_mode == CACHE_EXTERNAL && drupal_page_is_cacheable()) { |
|
1533 |
drupal_page_cache_header_external(); |
|
1534 |
}
|
|
1.5.17
by David Strauss
Integrate DamZ's updated work. |
1535 |
|
1
by bzr
Drupal 6.6 |
1536 |
// Prepare for non-cached page workflow.
|
55
by David Strauss
To fix Drush (Drupal.org #487300 and LP #422516), apply Drupal.org #581286 by David Strauss, DamZ, and moshe weitzman |
1537 |
if (!drupal_is_cli()) { |
50.1.1
by David Strauss
DamZ's fix for drupal.org #484610 |
1538 |
ob_start(); |
1539 |
drupal_page_header(); |
|
1540 |
}
|
|
1
by bzr
Drupal 6.6 |
1541 |
break; |
1542 |
||
1543 |
case DRUPAL_BOOTSTRAP_LANGUAGE: |
|
1544 |
drupal_init_language(); |
|
1545 |
break; |
|
1546 |
||
1547 |
case DRUPAL_BOOTSTRAP_PATH: |
|
1548 |
require_once './includes/path.inc'; |
|
1549 |
// Initialize $_GET['q'] prior to loading modules and invoking hook_init().
|
|
1550 |
drupal_init_path(); |
|
1551 |
break; |
|
1552 |
||
1553 |
case DRUPAL_BOOTSTRAP_FULL: |
|
1554 |
require_once './includes/common.inc'; |
|
1555 |
_drupal_bootstrap_full(); |
|
1556 |
break; |
|
1557 |
}
|
|
1558 |
}
|
|
1559 |
||
1560 |
/**
|
|
1561 |
* Enables use of the theme system without requiring database access.
|
|
1562 |
*
|
|
1563 |
* Loads and initializes the theme system for site installs, updates and when
|
|
1564 |
* the site is in off-line mode. This also applies when the database fails.
|
|
1565 |
*
|
|
1566 |
* @see _drupal_maintenance_theme()
|
|
1567 |
*/
|
|
1568 |
function drupal_maintenance_theme() { |
|
1569 |
require_once './includes/theme.maintenance.inc'; |
|
1570 |
_drupal_maintenance_theme(); |
|
1571 |
}
|
|
1572 |
||
1573 |
/**
|
|
1574 |
* Return the name of the localisation function. Use in code that needs to
|
|
1575 |
* run both during installation and normal operation.
|
|
1576 |
*/
|
|
1577 |
function get_t() { |
|
1578 |
static $t; |
|
1579 |
if (is_null($t)) { |
|
1580 |
$t = function_exists('install_main') ? 'st' : 't'; |
|
1581 |
}
|
|
1582 |
return $t; |
|
1583 |
}
|
|
1584 |
||
1585 |
/**
|
|
1586 |
* Choose a language for the current page, based on site and user preferences.
|
|
1587 |
*/
|
|
1588 |
function drupal_init_language() { |
|
1589 |
global $language, $user; |
|
1590 |
||
1591 |
// Ensure the language is correctly returned, even without multilanguage support.
|
|
1592 |
// Useful for eg. XML/HTML 'lang' attributes.
|
|
1593 |
if (variable_get('language_count', 1) == 1) { |
|
1594 |
$language = language_default(); |
|
1595 |
}
|
|
1596 |
else { |
|
1597 |
include_once './includes/language.inc'; |
|
1598 |
$language = language_initialize(); |
|
1599 |
}
|
|
1600 |
}
|
|
1601 |
||
1602 |
/**
|
|
1603 |
* Get a list of languages set up indexed by the specified key
|
|
1604 |
*
|
|
1605 |
* @param $field The field to index the list with.
|
|
1606 |
* @param $reset Boolean to request a reset of the list.
|
|
1607 |
*/
|
|
1608 |
function language_list($field = 'language', $reset = FALSE) { |
|
1609 |
static $languages = NULL; |
|
1610 |
||
1611 |
// Reset language list
|
|
1612 |
if ($reset) { |
|
1613 |
$languages = NULL; |
|
1614 |
}
|
|
1615 |
||
1616 |
// Init language list
|
|
1617 |
if (!isset($languages)) { |
|
1618 |
if (variable_get('language_count', 1) > 1 || module_exists('locale')) { |
|
1619 |
$result = db_query('SELECT * FROM {languages} ORDER BY weight ASC, name ASC'); |
|
1620 |
while ($row = db_fetch_object($result)) { |
|
1621 |
$languages['language'][$row->language] = $row; |
|
1622 |
}
|
|
1623 |
}
|
|
1624 |
else { |
|
1625 |
// No locale module, so use the default language only.
|
|
1626 |
$default = language_default(); |
|
1627 |
$languages['language'][$default->language] = $default; |
|
1628 |
}
|
|
1629 |
}
|
|
1630 |
||
1631 |
// Return the array indexed by the right field
|
|
1632 |
if (!isset($languages[$field])) { |
|
1633 |
$languages[$field] = array(); |
|
1634 |
foreach ($languages['language'] as $lang) { |
|
1635 |
// Some values should be collected into an array
|
|
1636 |
if (in_array($field, array('enabled', 'weight'))) { |
|
1637 |
$languages[$field][$lang->$field][$lang->language] = $lang; |
|
1638 |
}
|
|
1639 |
else { |
|
1640 |
$languages[$field][$lang->$field] = $lang; |
|
1641 |
}
|
|
1642 |
}
|
|
1643 |
}
|
|
1644 |
return $languages[$field]; |
|
1645 |
}
|
|
1646 |
||
1647 |
/**
|
|
1648 |
* Default language used on the site
|
|
1649 |
*
|
|
1650 |
* @param $property
|
|
1651 |
* Optional property of the language object to return
|
|
1652 |
*/
|
|
1653 |
function language_default($property = NULL) { |
|
1654 |
$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' => '')); |
|
1655 |
return $property ? $language->$property : $language; |
|
1656 |
}
|
|
1657 |
||
1658 |
/**
|
|
1659 |
* If Drupal is behind a reverse proxy, we use the X-Forwarded-For header
|
|
1660 |
* instead of $_SERVER['REMOTE_ADDR'], which would be the IP address
|
|
1661 |
* of the proxy server, and not the client's.
|
|
1662 |
*
|
|
1663 |
* @return
|
|
1664 |
* IP address of client machine, adjusted for reverse proxy.
|
|
1665 |
*/
|
|
1666 |
function ip_address() { |
|
1667 |
static $ip_address = NULL; |
|
1668 |
||
1669 |
if (!isset($ip_address)) { |
|
1670 |
$ip_address = $_SERVER['REMOTE_ADDR']; |
|
60.1.1
by David Strauss
Moshe's reverse proxy support patch. |
1671 |
|
60.1.3
by David Strauss
Optimize code to reduce load on non-proxied systems. |
1672 |
// Only use parts of the X-Forwarded-For (XFF) header that have followed a trusted route.
|
1673 |
// Specifically, identify the leftmost IP address in the XFF header that is not one of ours.
|
|
1674 |
// An XFF header is: X-Forwarded-For: client1, proxy1, proxy2
|
|
67
by David Strauss
Allow configuration of the header to use for X-Forwarded-For. Slightly optimize the processing order. |
1675 |
if (isset($_SERVER['HTTP_' . variable_get('x_forwarded_for_header', 'X_FORWARDED_FOR')]) && variable_get('reverse_proxy', 0)) { |
60.1.3
by David Strauss
Optimize code to reduce load on non-proxied systems. |
1676 |
// Load trusted reverse proxy server IPs.
|
1677 |
$reverse_proxy_addresses = variable_get('reverse_proxy_addresses', array()); |
|
60.1.1
by David Strauss
Moshe's reverse proxy support patch. |
1678 |
|
1679 |
// Turn XFF header into an array.
|
|
67
by David Strauss
Allow configuration of the header to use for X-Forwarded-For. Slightly optimize the processing order. |
1680 |
$forwarded = explode(',', $_SERVER['HTTP_' . variable_get('x_forwarded_for_header', 'X_FORWARDED_FOR')]); |
60.1.1
by David Strauss
Moshe's reverse proxy support patch. |
1681 |
|
67
by David Strauss
Allow configuration of the header to use for X-Forwarded-For. Slightly optimize the processing order. |
1682 |
// Trim the forwarded IPs; they may have been delimited by commas and spaces.
|
1683 |
$forwarded = array_map('trim', $forwarded); |
|
1684 |
||
60.1.1
by David Strauss
Moshe's reverse proxy support patch. |
1685 |
// Tack direct client IP onto end of forwarded array.
|
1686 |
$forwarded[] = $ip_address; |
|
60.1.2
by David Strauss
Trim forwarded IPs, which may have spaces. |
1687 |
|
60.1.1
by David Strauss
Moshe's reverse proxy support patch. |
1688 |
// Eliminate all trusted IPs.
|
1689 |
$untrusted = array_diff($forwarded, $reverse_proxy_addresses); |
|
1690 |
||
1691 |
// The right-most IP is the most specific we can trust.
|
|
1692 |
$ip_address = array_pop($untrusted); |
|
60.1.4
by David Strauss
Add missing closing brace. |
1693 |
}
|
1
by bzr
Drupal 6.6 |
1694 |
}
|
1695 |
||
1696 |
return $ip_address; |
|
1697 |
}
|
|
1.5.20
by David Strauss
Move new drupal_* functions from cache.inc to bootstrap.inc to preserve more of the D6 API. |
1698 |
|
1699 |
/**
|
|
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1700 |
* Initialize the session handler, starting a session if needed.
|
1701 |
*/
|
|
1702 |
function drupal_session_initialize() { |
|
1703 |
global $user; |
|
1704 |
||
1705 |
session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc'); |
|
1706 |
||
1707 |
if (isset($_COOKIE[session_name()])) { |
|
1708 |
// If a session cookie exists, initialize the session. Otherwise the
|
|
1709 |
// session is only started on demand in drupal_session_commit(), making
|
|
1710 |
// anonymous users not use a session cookie unless something is stored in
|
|
1711 |
// $_SESSION. This allows HTTP proxies to cache anonymous pageviews.
|
|
1712 |
drupal_session_start(); |
|
1713 |
if (!empty($user->uid) || !empty($_SESSION)) { |
|
1714 |
drupal_page_is_cacheable(FALSE); |
|
1715 |
}
|
|
1716 |
}
|
|
1717 |
else { |
|
1718 |
// Set a session identifier for this request. This is necessary because
|
|
1719 |
// we lazyly start sessions at the end of this request, and some
|
|
1720 |
// processes (like drupal_get_token()) needs to know the future
|
|
1721 |
// session ID in advance.
|
|
1722 |
$user = drupal_anonymous_user(); |
|
1723 |
session_id(md5(uniqid('', TRUE))); |
|
1724 |
}
|
|
1725 |
}
|
|
1726 |
||
1727 |
/**
|
|
1.5.26
by David Strauss
Backport newer drupal_start_session(). |
1728 |
* Forcefully start a session, preserving already set session data.
|
1.5.20
by David Strauss
Move new drupal_* functions from cache.inc to bootstrap.inc to preserve more of the D6 API. |
1729 |
*/
|
1.5.26
by David Strauss
Backport newer drupal_start_session(). |
1730 |
function drupal_session_start() { |
1731 |
if (!drupal_session_started()) { |
|
1732 |
// Save current session data before starting it, as PHP will destroy it.
|
|
1733 |
$session_data = isset($_SESSION) ? $_SESSION : NULL; |
|
1.5.20
by David Strauss
Move new drupal_* functions from cache.inc to bootstrap.inc to preserve more of the D6 API. |
1734 |
session_start(); |
1.5.26
by David Strauss
Backport newer drupal_start_session(). |
1735 |
drupal_session_started(TRUE); |
1.5.20
by David Strauss
Move new drupal_* functions from cache.inc to bootstrap.inc to preserve more of the D6 API. |
1736 |
// Restore session data.
|
1.5.26
by David Strauss
Backport newer drupal_start_session(). |
1737 |
if (!empty($session_data)) { |
1738 |
$_SESSION += $session_data; |
|
1.5.20
by David Strauss
Move new drupal_* functions from cache.inc to bootstrap.inc to preserve more of the D6 API. |
1739 |
}
|
1740 |
}
|
|
1741 |
}
|
|
1742 |
||
1743 |
/**
|
|
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1744 |
* Commit the current session, if necessary.
|
1745 |
*
|
|
1746 |
* If an anonymous user already has an empty session, destroy it.
|
|
1747 |
*/
|
|
1748 |
function drupal_session_commit() { |
|
1749 |
global $user; |
|
1750 |
||
1751 |
if (empty($user->uid) && empty($_SESSION)) { |
|
1752 |
if (drupal_session_started() && drupal_save_session()) { |
|
1753 |
// Destroy empty anonymous sessions.
|
|
87
by David Strauss
Brian Vuyk, Mark Sonnabaum, and more: Fix session management issue on logout. |
1754 |
drupal_session_destroy(); |
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1755 |
}
|
1756 |
}
|
|
1757 |
else if (drupal_save_session()) { |
|
1758 |
if (!drupal_session_started()) { |
|
1759 |
drupal_session_start(); |
|
1760 |
}
|
|
1761 |
// Write the session data.
|
|
1762 |
session_write_close(); |
|
1763 |
}
|
|
1764 |
}
|
|
1765 |
||
1766 |
/**
|
|
1767 |
* Return whether a session has been started.
|
|
1768 |
*/
|
|
1769 |
function drupal_session_started($set = NULL) { |
|
1770 |
static $session_started = FALSE; |
|
1771 |
if (isset($set)) { |
|
1772 |
$session_started = $set; |
|
1773 |
}
|
|
1774 |
return $session_started && session_id(); |
|
1775 |
}
|
|
1776 |
||
1777 |
/**
|
|
1778 |
* Called when an anonymous user becomes authenticated or vice-versa.
|
|
1779 |
*/
|
|
1780 |
function drupal_session_regenerate() { |
|
1781 |
global $user; |
|
1782 |
||
1783 |
// Set the session cookie "httponly" flag to reduce the risk of session
|
|
1784 |
// stealing via XSS.
|
|
1785 |
extract(session_get_cookie_params()); |
|
47
by David Strauss
Add compatibility with PHP 5.1 for cookie parameters. |
1786 |
|
1787 |
if (version_compare(PHP_VERSION, '5.2.0') === 1) { |
|
1788 |
session_set_cookie_params($lifetime, $path, $domain, $secure, TRUE); |
|
1789 |
}
|
|
1790 |
else { |
|
1791 |
session_set_cookie_params($lifetime, $path, $domain, $secure); |
|
1792 |
}
|
|
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1793 |
|
1794 |
if (drupal_session_started()) { |
|
1795 |
$old_session_id = session_id(); |
|
1796 |
session_regenerate_id(); |
|
1797 |
}
|
|
1798 |
else { |
|
1799 |
// Start the session when it doesn't exist yet.
|
|
1800 |
// Preserve the logged in user, as it will be reset to anonymous
|
|
1801 |
// by _sess_read.
|
|
1802 |
$account = $user; |
|
1.5.20
by David Strauss
Move new drupal_* functions from cache.inc to bootstrap.inc to preserve more of the D6 API. |
1803 |
drupal_session_start(); |
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1804 |
$user = $account; |
1.5.20
by David Strauss
Move new drupal_* functions from cache.inc to bootstrap.inc to preserve more of the D6 API. |
1805 |
}
|
1806 |
||
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1807 |
if (isset($old_session_id)) { |
52
by David Strauss
Fix quotes for PostgreSQL (even though Pressflow does not support PostgreSQL). |
1808 |
db_query("UPDATE {sessions} SET sid = '%s' WHERE sid = '%s'", session_id(), $old_session_id); |
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1809 |
}
|
1.5.20
by David Strauss
Move new drupal_* functions from cache.inc to bootstrap.inc to preserve more of the D6 API. |
1810 |
}
|
1811 |
||
1812 |
/**
|
|
1.5.22
by David Strauss
Initial backport of DamZ's latest reverse proxy code cleanup in D7. |
1813 |
* Determine whether to save session data of the current request.
|
1814 |
*
|
|
1815 |
* This function allows the caller to temporarily disable writing of
|
|
1816 |
* session data, should the request end while performing potentially
|
|
1817 |
* dangerous operations, such as manipulating the global $user object.
|
|
1818 |
* See http://drupal.org/node/218104 for usage.
|
|
1819 |
*
|
|
1820 |
* @param $status
|
|
1821 |
* Disables writing of session data when FALSE, (re-)enables
|
|
1822 |
* writing when TRUE.
|
|
1823 |
* @return
|
|
1824 |
* FALSE if writing session data has been disabled. Otherwise, TRUE.
|
|
1825 |
*/
|
|
1826 |
function drupal_save_session($status = NULL) { |
|
1827 |
static $save_session = TRUE; |
|
1828 |
if (isset($status)) { |
|
1829 |
$save_session = $status; |
|
1830 |
}
|
|
1831 |
return $save_session; |
|
1832 |
}
|
|
74.2.2
by David Strauss
Backport drupal_get_bootstrap_phase() from Drupal 7 to support SimpleTest. |
1833 |
|
1834 |
/**
|
|
1835 |
* Returns the current bootstrap phase for this Drupal process.
|
|
1836 |
*
|
|
1837 |
* The current phase is the one most recently completed by drupal_bootstrap().
|
|
1838 |
*
|
|
1839 |
* @see drupal_bootstrap()
|
|
1840 |
*/
|
|
1841 |
function drupal_get_bootstrap_phase() { |
|
1842 |
return drupal_bootstrap(); |
|
1843 |
}
|
|
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1844 |
|
1845 |
/**
|
|
1846 |
* Validate the HMAC and timestamp of a user agent header from simpletest.
|
|
1847 |
*/
|
|
1848 |
function drupal_valid_test_ua($user_agent) { |
|
74.2.1
by David Strauss
SimpleTest 1.10 |
1849 |
// global $dbatabases;
|
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1850 |
global $db_url; |
1851 |
||
1852 |
list($prefix, $time, $salt, $hmac) = explode(';', $user_agent); |
|
1853 |
$check_string = $prefix . ';' . $time . ';' . $salt; |
|
1854 |
// We use the database credentials from settings.php to make the HMAC key, since
|
|
1855 |
// the database is not yet initialized and we can't access any Drupal variables.
|
|
1856 |
// The file properties add more entropy not easily accessible to others.
|
|
74.2.1
by David Strauss
SimpleTest 1.10 |
1857 |
// $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc';
|
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1858 |
$filepath = './includes/bootstrap.inc'; |
74.2.1
by David Strauss
SimpleTest 1.10 |
1859 |
// $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE);
|
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1860 |
$key = sha1(serialize($db_url) . filectime($filepath) . fileinode($filepath), TRUE); |
1861 |
// The HMAC must match.
|
|
1862 |
return $hmac == base64_encode(hash_hmac('sha1', $check_string, $key, TRUE)); |
|
1863 |
}
|
|
1864 |
||
1865 |
/**
|
|
1866 |
* Generate a user agent string with a HMAC and timestamp for simpletest.
|
|
1867 |
*/
|
|
1868 |
function drupal_generate_test_ua($prefix) { |
|
1869 |
// global $dbatabases;
|
|
1870 |
global $db_url; |
|
1871 |
static $key; |
|
1872 |
||
1873 |
if (!isset($key)) { |
|
1874 |
// We use the database credentials to make the HMAC key, since we
|
|
1875 |
// check the HMAC before the database is initialized. filectime()
|
|
1876 |
// and fileinode() are not easily determined from remote.
|
|
74.2.1
by David Strauss
SimpleTest 1.10 |
1877 |
// $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc';
|
1878 |
$filepath = './includes/bootstrap.inc'; |
|
1879 |
// $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE);
|
|
47.1.1
by Josh Koenig
Merging in latest backport of simpletest from Drupal7, including the patch, some bugfixes around the user-agent, and simpletest cases. |
1880 |
$key = sha1(serialize($db_url) . filectime($filepath) . fileinode($filepath), TRUE); |
1881 |
}
|
|
1882 |
// Generate a moderately secure HMAC based on the database credentials.
|
|
1883 |
$salt = uniqid('', TRUE); |
|
1884 |
$check_string = $prefix . ';' . time() . ';' . $salt; |
|
1885 |
return $check_string . ';' . base64_encode(hash_hmac('sha1', $check_string, $key, TRUE)); |
|
1886 |
}
|
|
55
by David Strauss
To fix Drush (Drupal.org #487300 and LP #422516), apply Drupal.org #581286 by David Strauss, DamZ, and moshe weitzman |
1887 |
|
1888 |
/**
|
|
1889 |
* Detect whether the current script is running in a command-line environment.
|
|
1890 |
*/
|
|
1891 |
function drupal_is_cli() { |
|
1892 |
return ((!isset($_SERVER['SERVER_SOFTWARE']) || $_SERVER['SERVER_SOFTWARE'] == 'PHP CLI') |
|
1893 |
&& (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0))); |
|
1894 |
}
|
|
87
by David Strauss
Brian Vuyk, Mark Sonnabaum, and more: Fix session management issue on logout. |
1895 |
|
1896 |
/**
|
|
1897 |
* Destroys all data registered to a session.
|
|
1898 |
*
|
|
1899 |
* Placed in bootstrap.inc instead of session.inc as session.inc may be
|
|
1900 |
* overridden by other session persistance layers (eg., memcache).
|
|
1901 |
*
|
|
1902 |
* @ingroup php_wrappers
|
|
1903 |
*/
|
|
1904 |
function drupal_session_destroy() { |
|
1905 |
session_destroy(); |
|
1906 |
||
1907 |
// Workaround PHP 5.2 fatal error "Failed to initialize storage module".
|
|
1908 |
// @see http://bugs.php.net/bug.php?id=32330
|
|
1909 |
session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc'); |
|
1910 |
}
|