Code coverage for /20080809/includes/bootstrap.inc

Line #Times calledCode
1
<?php
2
// $Id: bootstrap.inc,v 1.218 2008/08/02 19:01:02 dries Exp $
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
 */
132027
define('CACHE_PERMANENT', 0);
14
15
/**
16
 * Indicates that the item should be removed at the next general cache
wipe.
17
 */
182027
define('CACHE_TEMPORARY', -1);
19
20
/**
21
 * Indicates that page caching is disabled.
22
 */
232027
define('CACHE_DISABLED', 0);
24
25
/**
26
 * Indicates that page caching is enabled, using "normal" mode.
27
 */
282027
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
 */
352027
define('CACHE_AGGRESSIVE', 2);
36
37
/**
38
 * Log message severity -- Emergency: system is unusable.
39
 *
40
 * @see watchdog()
41
 * @see watchdog_severity_levels()
42
 */
432027
define('WATCHDOG_EMERG', 0);
44
45
/**
46
 * Log message severity -- Alert: action must be taken immediately.
47
 *
48
 * @see watchdog()
49
 * @see watchdog_severity_levels()
50
 */
512027
define('WATCHDOG_ALERT', 1);
52
53
/**
54
 * Log message severity -- Critical: critical conditions.
55
 *
56
 * @see watchdog()
57
 * @see watchdog_severity_levels()
58
 */
592027
define('WATCHDOG_CRITICAL', 2);
60
61
/**
62
 * Log message severity -- Error: error conditions.
63
 *
64
 * @see watchdog()
65
 * @see watchdog_severity_levels()
66
 */
672027
define('WATCHDOG_ERROR', 3);
68
69
/**
70
 * Log message severity -- Warning: warning conditions.
71
 *
72
 * @see watchdog()
73
 * @see watchdog_severity_levels()
74
 */
752027
define('WATCHDOG_WARNING', 4);
76
77
/**
78
 * Log message severity -- Notice: normal but significant condition.
79
 *
80
 * @see watchdog()
81
 * @see watchdog_severity_levels()
82
 */
832027
define('WATCHDOG_NOTICE', 5);
84
85
/**
86
 * Log message severity -- Informational: informational messages.
87
 *
88
 * @see watchdog()
89
 * @see watchdog_severity_levels()
90
 */
912027
define('WATCHDOG_INFO', 6);
92
93
/**
94
 * Log message severity -- Debug: debug-level messages.
95
 *
96
 * @see watchdog()
97
 * @see watchdog_severity_levels()
98
 */
992027
define('WATCHDOG_DEBUG', 7);
100
101
/**
102
 * First bootstrap phase: initialize configuration.
103
 */
1042027
define('DRUPAL_BOOTSTRAP_CONFIGURATION', 0);
105
106
/**
107
 * Second bootstrap phase: try to call a non-database cache
108
 * fetch routine.
109
 */
1102027
define('DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE', 1);
111
112
/**
113
 * Third bootstrap phase: initialize database layer.
114
 */
1152027
define('DRUPAL_BOOTSTRAP_DATABASE', 2);
116
117
/**
118
 * Fourth bootstrap phase: identify and reject banned hosts.
119
 */
1202027
define('DRUPAL_BOOTSTRAP_ACCESS', 3);
121
122
/**
123
 * Fifth bootstrap phase: initialize session handling.
124
 */
1252027
define('DRUPAL_BOOTSTRAP_SESSION', 4);
126
127
/**
128
 * Sixth bootstrap phase: load bootstrap.inc and module.inc, start
129
 * the variable system and try to serve a page from the cache.
130
 */
1312027
define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 5);
132
133
/**
134
 * Seventh bootstrap phase: find out language of the page.
135
 */
1362027
define('DRUPAL_BOOTSTRAP_LANGUAGE', 6);
137
138
/**
139
 * Eighth bootstrap phase: set $_GET['q'] to Drupal path of request.
140
 */
1412027
define('DRUPAL_BOOTSTRAP_PATH', 7);
142
143
/**
144
 * Final bootstrap phase: Drupal is fully loaded; validate and fix
145
 * input data.
146
 */
1472027
define('DRUPAL_BOOTSTRAP_FULL', 8);
148
149
/**
150
 * Role ID for anonymous users; should match what's in the "role" table.
151
 */
1522027
define('DRUPAL_ANONYMOUS_RID', 1);
153
154
/**
155
 * Role ID for authenticated users; should match what's in the "role"
table.
156
 */
1572027
define('DRUPAL_AUTHENTICATED_RID', 2);
158
159
/**
160
 * No language negotiation. The default language is used.
161
 */
1622027
define('LANGUAGE_NEGOTIATION_NONE', 0);
163
164
/**
165
 * Path based negotiation with fallback to default language
166
 * if no defined path prefix identified.
167
 */
1682027
define('LANGUAGE_NEGOTIATION_PATH_DEFAULT', 1);
169
170
/**
171
 * Path based negotiation with fallback to user preferences
172
 * and browser language detection if no defined path prefix
173
 * identified.
174
 */
1752027
define('LANGUAGE_NEGOTIATION_PATH', 2);
176
177
/**
178
 * Domain based negotiation with fallback to default language
179
 * if no language identified by domain.
180
 */
1812027
define('LANGUAGE_NEGOTIATION_DOMAIN', 3);
182
183
/**
184
 * Start the timer with the specified name. If you start and stop
185
 * the same timer multiple times, the measured intervals will be
186
 * accumulated.
187
 *
188
 * @param name
189
 *   The name of the timer.
190
 */
1912027
function timer_start($name) {
1922027
  global $timers;
193
1942027
  list($usec, $sec) = explode(' ', microtime());
1952027
  $timers[$name]['start'] = (float)$usec + (float)$sec;
1962027
  $timers[$name]['count'] = isset($timers[$name]['count']) ?
++$timers[$name]['count'] : 1;
1972027
}
198
199
/**
200
 * Read the current timer value without stopping the timer.
201
 *
202
 * @param name
203
 *   The name of the timer.
204
 * @return
205
 *   The current timer value in ms.
206
 */
2072027
function timer_read($name) {
20814
  global $timers;
209
21014
  if (isset($timers[$name]['start'])) {
21114
    list($usec, $sec) = explode(' ', microtime());
21214
    $stop = (float)$usec + (float)$sec;
21314
    $diff = round(($stop - $timers[$name]['start']) * 1000, 2);
214
21514
    if (isset($timers[$name]['time'])) {
2160
      $diff += $timers[$name]['time'];
2170
    }
21814
    return $diff;
2190
  }
2200
}
221
222
/**
223
 * Stop the timer with the specified name.
224
 *
225
 * @param name
226
 *   The name of the timer.
227
 * @return
228
 *   A timer array. The array contains the number of times the
229
 *   timer has been started and stopped (count) and the accumulated
230
 *   timer value in ms (time).
231
 */
2322027
function timer_stop($name) {
2330
  global $timers;
234
2350
  $timers[$name]['time'] = timer_read($name);
2360
  unset($timers[$name]['start']);
237
2380
  return $timers[$name];
2390
}
240
241
/**
242
 * Find the appropriate configuration directory.
243
 *
244
 * Try finding a matching configuration directory by stripping the
website's
245
 * hostname from left to right and pathname from right to left. The first
246
 * configuration file found will be used; the remaining will ignored. If
no
247
 * configuration file is found, return a default value '$confdir/default'.
248
 *
249
 * Example for a fictitious site installed at
250
 * http://www.drupal.org:8080/mysite/test/ the 'settings.php' is searched
in
251
 * the following directories:
252
 *
253
 *  1. $confdir/8080.www.drupal.org.mysite.test
254
 *  2. $confdir/www.drupal.org.mysite.test
255
 *  3. $confdir/drupal.org.mysite.test
256
 *  4. $confdir/org.mysite.test
257
 *
258
 *  5. $confdir/8080.www.drupal.org.mysite
259
 *  6. $confdir/www.drupal.org.mysite
260
 *  7. $confdir/drupal.org.mysite
261
 *  8. $confdir/org.mysite
262
 *
263
 *  9. $confdir/8080.www.drupal.org
264
 * 10. $confdir/www.drupal.org
265
 * 11. $confdir/drupal.org
266
 * 12. $confdir/org
267
 *
268
 * 13. $confdir/default
269
 *
270
 * @param $require_settings
271
 *   Only configuration directories with an existing settings.php file
272
 *   will be recognized. Defaults to TRUE. During initial installation,
273
 *   this is set to FALSE so that Drupal can detect a matching directory,
274
 *   then create a new settings.php file in it.
275
 * @param reset
276
 *   Force a full search for matching directories even if one had been
277
 *   found previously.
278
 * @return
279
 *   The path of the matching directory.
280
 */
2812027
function conf_path($require_settings = TRUE, $reset = FALSE) {
2822087
  static $conf = '';
283
2842087
  if ($conf && !$reset) {
2852087
    return $conf;
2860
  }
287
2882027
  $confdir = 'sites';
2892027
  $uri = explode('/', $_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] :
$_SERVER['SCRIPT_FILENAME']);
2902027
  $server = explode('.', implode('.', array_reverse(explode(':',
rtrim($_SERVER['HTTP_HOST'], '.')))));
2912027
  for ($i = count($uri) - 1; $i > 0; $i--) {
2922027
    for ($j = count($server); $j > 0; $j--) {
2932027
      $dir = implode('.', array_slice($server, -$j)) . implode('.',
array_slice($uri, 0, $i));
2942027
      if (file_exists("$confdir/$dir/settings.php") || (!$require_settings
&& file_exists("$confdir/$dir"))) {
2950
        $conf = "$confdir/$dir";
2960
        return $conf;
2970
      }
2982027
    }
2992027
  }
3002027
  $conf = "$confdir/default";
3012027
  return $conf;
3020
}
303
304
/**
305
 * Unsets all disallowed global variables. See $allowed for what's
allowed.
306
 */
3072027
function drupal_unset_globals() {
3082027
  if (ini_get('register_globals')) {
3090
    $allowed = array('_ENV' => 1, '_GET' => 1, '_POST' => 1, '_COOKIE' =>
1, '_FILES' => 1, '_SERVER' => 1, '_REQUEST' => 1, 'GLOBALS' => 1);
3100
    foreach ($GLOBALS as $key => $value) {
3110
      if (!isset($allowed[$key])) {
3120
        unset($GLOBALS[$key]);
3130
      }
3140
    }
3150
  }
3162027
}
317
318
/**
319
 * Loads the configuration and sets the base URL, cookie domain, and
320
 * session name correctly.
321
 */
3222027
function conf_init() {
3232027
  global $base_url, $base_path, $base_root;
324
325
  // Export the following settings.php variables to the global namespace
3262027
  global $db_url, $db_prefix, $cookie_domain, $conf, $installed_profile,
$update_free_access;
3272027
  $conf = array();
328
3292027
  if (file_exists('./' . conf_path() . '/settings.php')) {
3302027
    include_once './' . conf_path() . '/settings.php';
3312027
  }
332
3332027
  if (isset($base_url)) {
334
    // Parse fixed base URL from settings.php.
3350
    $parts = parse_url($base_url);
3360
    if (!isset($parts['path'])) {
3370
      $parts['path'] = '';
3380
    }
3390
    $base_path = $parts['path'] . '/';
340
    // Build $base_root (everything until first slash after "scheme://").
3410
    $base_root = substr($base_url, 0, strlen($base_url) -
strlen($parts['path']));
3420
  }
343
  else {
344
    // Create base URL
3452027
    $base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ?
'https' : 'http';
346
347
    // As $_SERVER['HTTP_HOST'] is user input, ensure it only contains
348
    // characters allowed in hostnames.
3492027
    $base_url = $base_root .= '://' . preg_replace('/[^a-z0-9-:._]/i', '',
$_SERVER['HTTP_HOST']);
350
351
    // $_SERVER['SCRIPT_NAME'] can, in contrast to $_SERVER['PHP_SELF'],
not
352
    // be modified by a visitor.
3532027
    if ($dir = trim(dirname($_SERVER['SCRIPT_NAME']), '\,/')) {
3540
      $base_path = "/$dir";
3550
      $base_url .= $base_path;
3560
      $base_path .= '/';
3570
    }
358
    else {
3592027
      $base_path = '/';
360
    }
361
  }
362
3632027
  if ($cookie_domain) {
364
    // If the user specifies the cookie domain, also use it for session
name.
3650
    $session_name = $cookie_domain;
3660
  }
367
  else {
368
    // Otherwise use $base_url as session name, without the protocol
369
    // to use the same session identifiers across http and https.
3702027
    list( , $session_name) = explode('://', $base_url, 2);
371
    // We escape the hostname because it can be modified by a visitor.
3722027
    if (!empty($_SERVER['HTTP_HOST'])) {
3732027
      $cookie_domain = check_plain($_SERVER['HTTP_HOST']);
3742027
    }
375
  }
376
  // Strip leading periods, www., and port numbers from cookie domain.
3772027
  $cookie_domain = ltrim($cookie_domain, '.');
3782027
  if (strpos($cookie_domain, 'www.') === 0) {
3790
    $cookie_domain = substr($cookie_domain, 4);
3800
  }
3812027
  $cookie_domain = explode(':', $cookie_domain);
3822027
  $cookie_domain = '.' . $cookie_domain[0];
383
  // Per RFC 2109, cookie domains must contain at least one dot other than
the
384
  // first. For hosts such as 'localhost' or IP Addresses we don't set a
cookie domain.
3852027
  if (count(explode('.', $cookie_domain)) > 2 &&
!is_numeric(str_replace('.', '', $cookie_domain))) {
3862027
    ini_set('session.cookie_domain', $cookie_domain);
3872027
  }
3882027
  session_name('SESS' . md5($session_name));
3892027
}
390
391
/**
392
 * Returns and optionally sets the filename for a system item (module,
393
 * theme, etc.). The filename, whether provided, cached, or retrieved
394
 * from the database, is only returned if the file exists.
395
 *
396
 * This function plays a key role in allowing Drupal's resources (modules
397
 * and themes) to be located in different places depending on a site's
398
 * configuration. For example, a module 'foo' may legally be be located
399
 * in any of these three places:
400
 *
401
 * modules/foo/foo.module
402
 * sites/all/modules/foo/foo.module
403
 * sites/example.com/modules/foo/foo.module
404
 *
405
 * Calling drupal_get_filename('module', 'foo') will give you one of
406
 * the above, depending on where the module is located.
407
 *
408
 * @param $type
409
 *   The type of the item (i.e. theme, theme_engine, module).
410
 * @param $name
411
 *   The name of the item for which the filename is requested.
412
 * @param $filename
413
 *   The filename of the item if it is to be set explicitly rather
414
 *   than by consulting the database.
415
 *
416
 * @return
417
 *   The filename of the requested item.
418
 */
4192027
function drupal_get_filename($type, $name, $filename = NULL) {
4202087
  static $files = array();
421
4222087
  if (!isset($files[$type])) {
4232027
    $files[$type] = array();
4242027
  }
425
4262087
  if (!empty($filename) && file_exists($filename)) {
4272087
    $files[$type][$name] = $filename;
4282087
  }
4292087
  elseif (isset($files[$type][$name])) {
430
    // nothing
4312087
  }
432
  // Verify that we have an active database connection, before querying
433
  // the database.  This is required because this function is called both
434
  // before we have a database connection (i.e. during installation) and
435
  // when a database connection fails.
43610
  elseif (db_is_active() && (($file = db_result(db_query("SELECT filename
FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) &&
file_exists($file))) {
43710
    $files[$type][$name] = $file;
43810
  }
439
  else {
440
    // Fallback to searching the filesystem if the database connection is
441
    // not established or the requested file is not found.
4420
    $config = conf_path();
4430
    $dir = (($type == 'theme_engine') ? 'themes/engines' : "${type}s");
4440
    $file = (($type == 'theme_engine') ? "$name.engine" : "$name.$type");
445
4460
    foreach (array("$config/$dir/$file", "$config/$dir/$name/$file",
"$dir/$file", "$dir/$name/$file") as $file) {
4470
      if (file_exists($file)) {
4480
        $files[$type][$name] = $file;
4490
        break;
4500
      }
4510
    }
452
  }
453
4542087
  if (isset($files[$type][$name])) {
4552087
    return $files[$type][$name];
4560
  }
4570
}
458
459
/**
460
 * Load the persistent variable table.
461
 *
462
 * The variable table is composed of values that have been saved in the
table
463
 * with variable_set() as well as those explicitly specified in the
configuration
464
 * file.
465
 */
4662027
function variable_init($conf = array()) {
467
  // NOTE: caching the variables improves performance by 20% when serving
cached pages.
4682087
  if ($cached = cache_get('variables', 'cache')) {
4692087
    $variables = $cached->data;
4702087
  }
471
  else {
472167
    $result = db_query('SELECT * FROM {variable}');
473167
    while ($variable = db_fetch_object($result)) {
474167
      $variables[$variable->name] = unserialize($variable->value);
475167
    }
476167
    cache_set('variables', $variables);
477
  }
478
4792087
  foreach ($conf as $name => $value) {
4800
    $variables[$name] = $value;
4810
  }
482
4832087
  return $variables;
4840
}
485
486
/**
487
 * Return a persistent variable.
488
 *
489
 * @param $name
490
 *   The name of the variable to return.
491
 * @param $default
492
 *   The default value to use if this variable has never been set.
493
 * @return
494
 *   The value of the variable.
495
 */
4962027
function variable_get($name, $default) {
4972087
  global $conf;
498
4992087
  return isset($conf[$name]) ? $conf[$name] : $default;
5000
}
501
502
/**
503
 * Set a persistent variable.
504
 *
505
 * @param $name
506
 *   The name of the variable to set.
507
 * @param $value
508
 *   The value to set. This can be any PHP data type; these functions take
care
509
 *   of serialization as necessary.
510
 */
5112027
function variable_set($name, $value) {
512203
  global $conf;
513
514203
  $serialized_value = serialize($value);
515203
  db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'",
$serialized_value, $name);
516203
  if (!db_affected_rows()) {
517145
    @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')",
$name, $serialized_value);
518145
  }
519
520203
  cache_clear_all('variables', 'cache');
521
522203
  $conf[$name] = $value;
523203
}
524
525
/**
526
 * Unset a persistent variable.
527
 *
528
 * @param $name
529
 *   The name of the variable to undefine.
530
 */
5312027
function variable_del($name) {
53283
  global $conf;
533
53483
  db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
53583
  cache_clear_all('variables', 'cache');
536
53783
  unset($conf[$name]);
53883
}
539
540
541
/**
542
 * Retrieve the current page from the cache.
543
 *
544
 * Note: we do not serve cached pages when status messages are waiting
(from
545
 * a redirected form submission which was completed).
546
 */
5472027
function page_get_cache() {
5480
  global $user, $base_root;
549
5500
  $cache = NULL;
551
5520
  if (!$user->uid && ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') && count(drupal_set_message()) == 0)
{
5530
    $cache = cache_get($base_root . request_uri(), 'cache_page');
554
5550
    if (empty($cache)) {
5560
      ob_start();
5570
    }
5580
  }
559
5600
  return $cache;
5610
}
562
563
/**
564
 * Call all init or exit hooks without including all modules.
565
 *
566
 * @param $hook
567
 *   The name of the bootstrap hook we wish to invoke.
568
 */
5692027
function bootstrap_invoke_all($hook) {
5702027
  foreach (module_list(TRUE, TRUE) as $module) {
5710
    module_invoke($module, $hook);
5720
  }
5732027
}
574
575
/**
576
 * Includes a file with the provided type and name. This prevents
577
 * including a theme, engine, module, etc., more than once.
578
 *
579
 * @param $type
580
 *   The type of item to load (i.e. theme, theme_engine, module).
581
 * @param $name
582
 *   The name of the item to load.
583
 *
584
 * @return
585
 *   TRUE if the item is loaded or has already been loaded.
586
 */
5872027
function drupal_load($type, $name) {
5882087
  static $files = array();
589
5902087
  if (isset($files[$type][$name])) {
59162
    return TRUE;
5920
  }
593
5942061
  $filename = drupal_get_filename($type, $name);
595
5962061
  if ($filename) {
5972061
    include_once "./$filename";
5982061
    $files[$type][$name] = TRUE;
599
6002061
    return TRUE;
6010
  }
602
6030
  return FALSE;
6040
}
605
606
/**
607
 * Set HTTP headers in preparation for a page response.
608
 *
609
 * Authenticated users are always given a 'no-cache' header, and will
610
 * fetch a fresh page on every request.  This prevents authenticated
611
 * users seeing locally cached pages that show them as logged out.
612
 *
613
 * @see page_set_cache()
614
 */
6152027
function drupal_page_header() {
6162027
  header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
6172027
  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
6182027
  header("Cache-Control: store, no-cache, must-revalidate");
6192027
  header("Cache-Control: post-check=0, pre-check=0", FALSE);
6202027
}
621
622
/**
623
 * Set HTTP headers in preparation for a cached page response.
624
 *
625
 * The general approach here is that anonymous users can keep a local
626
 * cache of the page, but must revalidate it on every request.  Then,
627
 * they are given a '304 Not Modified' response as long as they stay
628
 * logged out and the page has not been modified.
629
 *
630
 */
6312027
function drupal_page_cache_header($cache) {
632
  // Set default values:
6330
  $last_modified = gmdate('D, d M Y H:i:s', $cache->created) . ' GMT';
6340
  $etag = '"' . md5($last_modified) . '"';
635
636
  // See if the client has provided the required HTTP headers:
6370
  $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ?
stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE;
6380
  $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ?
stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE;
639
6400
  if ($if_modified_since && $if_none_match
6410
      && $if_none_match == $etag // etag must match
6420
      && $if_modified_since == $last_modified) {  // if-modified-since must
match
6430
    header('HTTP/1.1 304 Not Modified');
644
    // All 304 responses must send an etag if the 200 response for the same
object contained an etag
6450
    header("Etag: $etag");
6460
    exit();
6470
  }
648
649
  // Send appropriate response:
6500
  header("Last-Modified: $last_modified");
6510
  header("ETag: $etag");
652
653
  // The following headers force validation of cache:
6540
  header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
6550
  header("Cache-Control: must-revalidate");
656
6570
  if (variable_get('page_compression', TRUE)) {
658
    // Determine if the browser accepts gzipped data.
6590
    if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE &&
function_exists('gzencode')) {
660
      // Strip the gzip header and run uncompress.
6610
      $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
6620
    }
6630
    elseif (function_exists('gzencode')) {
6640
      header('Content-Encoding: gzip');
6650
    }
6660
  }
667
668
  // Send the original request's headers. We send them one after
669
  // another so PHP's header() function can deal with duplicate
670
  // headers.
6710
  $headers = explode("\n", $cache->headers);
6720
  foreach ($headers as $header) {
6730
    header($header);
6740
  }
675
6760
  print $cache->data;
6770
}
678
679
/**
680
 * Define the critical hooks that force modules to always be loaded.
681
 */
6822027
function bootstrap_hooks() {
68376
  return array('boot', 'exit');
6840
}
685
686
/**
687
 * Unserializes and appends elements from a serialized string.
688
 *
689
 * @param $obj
690
 *   The object to which the elements are appended.
691
 * @param $field
692
 *   The attribute of $obj whose value should be unserialized.
693
 */
6942027
function drupal_unpack($obj, $field = 'data') {
6952059
  if ($obj->$field && $data = unserialize($obj->$field)) {
69677
    foreach ($data as $key => $value) {
69777
      if (!isset($obj->$key)) {
69877
        $obj->$key = $value;
69977
      }
70077
    }
70177
  }
7022059
  return $obj;
7030
}
704
705
/**
706
 * Return the URI of the referring page.
707
 */
7082027
function referer_uri() {
709552
  if (isset($_SERVER['HTTP_REFERER'])) {
71060
    return $_SERVER['HTTP_REFERER'];
7110
  }
712492
}
713
714
/**
715
 * Encode special characters in a plain-text string for display as HTML.
716
 *
717
 * Uses drupal_validate_utf8 to prevent cross site scripting attacks on
718
 * Internet Explorer 6.
719
 */
7202027
function check_plain($text) {
7212087
  return drupal_validate_utf8($text) ? htmlspecialchars($text, ENT_QUOTES)
: '';
7220
}
723
724
/**
725
 * Checks whether a string is valid UTF-8.
726
 *
727
 * All functions designed to filter input should use drupal_validate_utf8
728
 * to ensure they operate on valid UTF-8 strings to prevent bypass of the
729
 * filter.
730
 *
731
 * When text containing an invalid UTF-8 lead byte (0xC0 - 0xFF) is
presented
732
 * as UTF-8 to Internet Explorer 6, the program may misinterpret
subsequent
733
 * bytes. When these subsequent bytes are HTML control characters such as
734
 * quotes or angle brackets, parts of the text that were deemed safe by
filters
735
 * end up in locations that are potentially unsafe; An onerror attribute
that
736
 * is outside of a tag, and thus deemed safe by a filter, can be
interpreted
737
 * by the browser as if it were inside the tag.
738
 *
739
 * This function exploits preg_match behaviour (since PHP 4.3.5) when used
740
 * with the u modifier, as a fast way to find invalid UTF-8. When the
matched
741
 * string contains an invalid byte sequence, it will fail silently.
742
 *
743
 * preg_match may not fail on 4 and 5 octet sequences, even though they
744
 * are not supported by the specification.
745
 *
746
 * The specific preg_match behaviour is present since PHP 4.3.5.
747
 *
748
 * @param $text
749
 *   The text to check.
750
 * @return
751
 *   TRUE if the text is valid UTF-8, FALSE if not.
752
 */
7532027
function drupal_validate_utf8($text) {
7542087
  if (strlen($text) == 0) {
7551507
    return TRUE;
7560
  }
7572087
  return (preg_match('/^./us', $text) == 1);
7580
}
759
760
/**
761
 * Since $_SERVER['REQUEST_URI'] is only available on Apache, we
762
 * generate an equivalent using other environment variables.
763
 */
7642027
function request_uri() {
765
7661781
  if (isset($_SERVER['REQUEST_URI'])) {
7671781
    $uri = $_SERVER['REQUEST_URI'];
7681781
  }
769
  else {
7700
    if (isset($_SERVER['argv'])) {
7710
      $uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['argv'][0];
7720
    }
7730
    elseif (isset($_SERVER['QUERY_STRING'])) {
7740
      $uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
7750
    }
776
    else {
7770
      $uri = $_SERVER['SCRIPT_NAME'];
778
    }
779
  }
780
7811781
  return $uri;
7820
}
783
784
/**
785
 * Log a system message.
786
 *
787
 * @param $type
788
 *   The category to which this message belongs.
789
 * @param $message
790
 *   The message to store in the log. See t() for documentation
791
 *   on how $message and $variables interact. Keep $message
792
 *   translatable by not concatenating dynamic values into it!
793
 * @param $variables
794
 *   Array of variables to replace in the message on display or
795
 *   NULL if message is already translated or not possible to
796
 *   translate.
797
 * @param $severity
798
 *   The severity of the message, as per RFC 3164
799
 * @param $link
800
 *   A link to associate with the message.
801
 *
802
 * @see watchdog_severity_levels()
803
 */
8042027
function watchdog($type, $message, $variables = array(), $severity =
WATCHDOG_NOTICE, $link = NULL) {
805540
  global $user, $base_root;
806
807
  // Prepare the fields to be logged
808
  $log_message = array(
809540
    'type'        => $type,
810540
    'message'     => $message,
811540
    'variables'   => $variables,
812540
    'severity'    => $severity,
813540
    'link'        => $link,
814540
    'user'        => $user,
815540
    'request_uri' => $base_root . request_uri(),
816540
    'referer'     => referer_uri(),
817540
    'ip'          => ip_address(),
818540
    'timestamp'   => time(),
819540
    );
820
821
  // Call the logging hooks to log/process the message
822540
  foreach (module_implements('watchdog', TRUE) as $module) {
823540
    module_invoke($module, 'watchdog', $log_message);
824540
  }
825540
}
826
827
/**
828
 * Set a message which reflects the status of the performed operation.
829
 *
830
 * If the function is called with no arguments, this function returns all
set
831
 * messages without clearing them.
832
 *
833
 * @param $message
834
 *   The message should begin with a capital letter and always ends with a
835
 *   period '.'.
836
 * @param $type
837
 *   The type of the message. One of the following values are possible:
838
 *   - 'status'
839
 *   - 'warning'
840
 *   - 'error'
841
 * @param $repeat
842
 *   If this is FALSE and the message is already set, then the message
won't
843
 *   be repeated.
844
 */
8452027
function drupal_set_message($message = NULL, $type = 'status', $repeat =
TRUE) {
8461752
  if ($message) {
847311
    if (!isset($_SESSION['messages'])) {
848309
      $_SESSION['messages'] = array();
849309
    }
850
851311
    if (!isset($_SESSION['messages'][$type])) {
852309
      $_SESSION['messages'][$type] = array();
853309
    }
854
855311
    if ($repeat || !in_array($message, $_SESSION['messages'][$type])) {
856311
      $_SESSION['messages'][$type][] = $message;
857311
    }
858311
  }
859
860
  // messages not set when DB connection fails
8611752
  return isset($_SESSION['messages']) ? $_SESSION['messages'] : NULL;
8620
}
863
864
/**
865
 * Return all messages that have been set.
866
 *
867
 * @param $type
868
 *   (optional) Only return messages of this type.
869
 * @param $clear_queue
870
 *   (optional) Set to FALSE if you do not want to clear the messages
queue
871
 * @return
872
 *   An associative array, the key is the message type, the value an array
873
 *   of messages. If the $type parameter is passed, you get only that
type,
874
 *   or an empty array if there are no such messages. If $type is not
passed,
875
 *   all message types are returned, or an empty array if none exist.
876
 */
8772027
function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
8781489
  if ($messages = drupal_set_message()) {
879291
    if ($type) {
8800
      if ($clear_queue) {
8810
        unset($_SESSION['messages'][$type]);
8820
      }
8830
      if (isset($messages[$type])) {
8840
        return array($type => $messages[$type]);
8850
      }
8860
    }
887
    else {
888291
      if ($clear_queue) {
889291
        unset($_SESSION['messages']);
890291
      }
891291
      return $messages;
892
    }
8930
  }
8941198
  return array();
8950
}
896
897
/**
898
 * Check to see if an IP address has been blocked.
899
 *
900
 * Blocked IP addresses are stored in the database by default. However for
901
 * performance reasons we allow an override in settings.php. This allows
us
902
 * to avoid querying the database at this critical stage of the bootstrap
if
903
 * an administrative interface for IP address blocking is not required.
904
 *
905
 * @param $ip string
906
 *   IP address to check.
907
 * @return bool
908
 *   TRUE if access is denied, FALSE if access is allowed.
909
 */
9102027
function drupal_is_denied($ip) {
911
  // Because this function is called on every page request, we first check
912
  // for an array of IP addresses in settings.php before querying the
913
  // database.
9142027
  $blocked_ips = variable_get('blocked_ips', NULL);
9152027
  if (isset($blocked_ips) && is_array($blocked_ips)) {
9160
    return in_array($ip, $blocked_ips);
9170
  }
918
  else {
9192027
    $sql = "SELECT 1 FROM {blocked_ips} WHERE ip = '%s'";
9202027
    return (bool) db_result(db_query($sql, $ip));
921
  }
9220
}
923
924
/**
925
 * Generates a default anonymous $user object.
926
 *
927
 * @return Object - the user object.
928
 */
9292027
function drupal_anonymous_user($session = '') {
930708
  $user = new stdClass();
931708
  $user->uid = 0;
932708
  $user->hostname = ip_address();
933708
  $user->roles = array();
934708
  $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
935708
  $user->session = $session;
936708
  $user->cache = 0;
937708
  return $user;
9380
}
939
940
/**
941
 * A string describing a phase of Drupal to load. Each phase adds to the
942
 * previous one, so invoking a later phase automatically runs the earlier
943
 * phases too. The most important usage is that if you want to access the
944
 * Drupal database from a script without loading anything else, you can
945
 * include bootstrap.inc, and call
drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE).
946
 *
947
 * @param $phase
948
 *   A constant. Allowed values are:
949
 *     DRUPAL_BOOTSTRAP_CONFIGURATION: initialize configuration.
950
 *     DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: try to call a non-database cache
fetch routine.
951
 *     DRUPAL_BOOTSTRAP_DATABASE: initialize database layer.
952
 *     DRUPAL_BOOTSTRAP_ACCESS: identify and reject banned hosts.
953
 *     DRUPAL_BOOTSTRAP_SESSION: initialize session handling.
954
 *     DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: load bootstrap.inc and module.inc,
start
955
 *       the variable system and try to serve a page from the cache.
956
 *     DRUPAL_BOOTSTRAP_LANGUAGE: identify the language used on the page.
957
 *     DRUPAL_BOOTSTRAP_PATH: set $_GET['q'] to Drupal path of request.
958
 *     DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix
input data.
959
 */
9602027
function drupal_bootstrap($phase) {
9612087
  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;
962
9632087
  while ($phase >= $phase_index && isset($phases[$phase_index])) {
9642027
    $current_phase = $phases[$phase_index];
9652027
    unset($phases[$phase_index++]);
9662027
    _drupal_bootstrap($current_phase);
9672027
  }
9682087
}
969
9702027
function _drupal_bootstrap($phase) {
9712027
  global $conf;
972
973
  switch ($phase) {
974
9752027
    case DRUPAL_BOOTSTRAP_CONFIGURATION:
9762027
      drupal_unset_globals();
977
      // Start a page timer:
9782027
      timer_start('page');
979
      // Initialize the configuration
9802027
      conf_init();
9812027
      break;
982
9832027
    case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE:
984
      // Allow specifying special cache handlers in settings.php, like
985
      // using memcached or files for storing cache information.
9862027
      require_once variable_get('cache_inc', './includes/cache.inc');
987
      // If the page_cache_fastpath is set to TRUE in settings.php and
988
      // page_cache_fastpath (implemented in the special implementation of
989
      // cache.inc) printed the page and indicated this with a returned
TRUE
990
      // then we are done.
9912027
      if (variable_get('page_cache_fastpath', FALSE) &&
page_cache_fastpath()) {
9920
        exit;
9930
      }
9942027
      break;
995
9962027
    case DRUPAL_BOOTSTRAP_DATABASE:
997
      // Initialize the default database.
9982027
      require_once './includes/database.inc';
9992027
      db_set_active();
1000
      // Register autoload functions so that we can access classes and
interfaces.
10012027
      spl_autoload_register('drupal_autoload_class');
10022027
      spl_autoload_register('drupal_autoload_interface');
10032027
      break;
1004
10052027
    case DRUPAL_BOOTSTRAP_ACCESS:
1006
      // Deny access to blocked IP addresses - t() is not yet available.
10072027
      if (drupal_is_denied(ip_address())) {
10080
        header('HTTP/1.1 403 Forbidden');
10090
        print 'Sorry, ' . check_plain(ip_address()) . ' has been banned.';
10100
        exit();
10110
      }
10122027
      break;
1013
10142027
    case DRUPAL_BOOTSTRAP_SESSION:
10152027
      require_once variable_get('session_inc', './includes/session.inc');
10162027
      session_set_save_handler('sess_open', 'sess_close', 'sess_read',
'sess_write', 'sess_destroy_sid', 'sess_gc');
10172027
      session_start();
10182027
      break;
1019
10202027
    case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE:
1021
      // Initialize configuration variables, using values from settings.php
if available.
10222027
      $conf = variable_init(isset($conf) ? $conf : array());
1023
      // Load module handling.
10242027
      require_once './includes/module.inc';
10252027
      $cache_mode = variable_get('cache', CACHE_DISABLED);
1026
      // Get the page from the cache.
10272027
      $cache = $cache_mode == CACHE_DISABLED ? '' : page_get_cache();
1028
      // If the skipping of the bootstrap hooks is not enforced, call
hook_boot.
10292027
      if ($cache_mode != CACHE_AGGRESSIVE) {
10302027
        bootstrap_invoke_all('boot');
10312027
      }
1032
      // If there is a cached page, display it.
10332027
      if ($cache) {
10340
        drupal_page_cache_header($cache);
1035
        // If the skipping of the bootstrap hooks is not enforced, call
hook_exit.
10360
        if ($cache_mode != CACHE_AGGRESSIVE) {
10370
          bootstrap_invoke_all('exit');
10380
        }
1039
        // We are done.
10400
        exit;
10410
      }
1042
      // Prepare for non-cached page workflow.
10432027
      drupal_page_header();
10442027
      break;
1045
10462027
    case DRUPAL_BOOTSTRAP_LANGUAGE:
10472027
      drupal_init_language();
10482027
      break;
1049
10502027
    case DRUPAL_BOOTSTRAP_PATH:
10512027
      require_once './includes/path.inc';
1052
      // Initialize $_GET['q'] prior to loading modules and invoking
hook_init().
10532027
      drupal_init_path();
10542027
      break;
1055
10562027
    case DRUPAL_BOOTSTRAP_FULL:
10572027
      require_once './includes/common.inc';
10582027
      _drupal_bootstrap_full();
10592027
      break;
10600
  }
10612027
}
1062
1063
/**
1064
 * Enables use of the theme system without requiring database access.
1065
 *
1066
 * Loads and initializes the theme system for site installs, updates and
when
1067
 * the site is in offline mode. This also applies when the database fails.
1068
 *
1069
 * @see _drupal_maintenance_theme()
1070
 */
10712027
function drupal_maintenance_theme() {
10720
  require_once './includes/theme.maintenance.inc';
10730
  _drupal_maintenance_theme();
10740
}
1075
1076
/**
1077
 * Return the name of the localisation function. Use in code that needs to
1078
 * run both during installation and normal operation.
1079
 */
10802027
function get_t() {
10812087
  static $t;
10822087
  if (is_null($t)) {
10832027
    $t = function_exists('install_main') ? 'st' : 't';
10842027
  }
10852087
  return $t;
10860
}
1087
1088
/**
1089
 *  Choose a language for the current page, based on site and user
preferences.
1090
 */
10912027
function drupal_init_language() {
10922027
  global $language, $user;
1093
1094
  // Ensure the language is correctly returned, even without multilanguage
support.
1095
  // Useful for eg. XML/HTML 'lang' attributes.
10962027
  if (variable_get('language_count', 1) == 1) {
10971965
    $language = language_default();
10981965
  }
1099
  else {
110062
    include_once './includes/language.inc';
110162
    $language = language_initialize();
1102
  }
11032027
}
1104
1105
/**
1106
 * Get a list of languages set up indexed by the specified key
1107
 *
1108
 * @param $field The field to index the list with.
1109
 * @param $reset Boolean to request a reset of the list.
1110
 */
11112027
function language_list($field = 'language', $reset = FALSE) {
111278
  static $languages = NULL;
1113
1114
  // Reset language list
111578
  if ($reset) {
11168
    $languages = NULL;
11178
  }
1118
1119
  // Init language list
112078
  if (!isset($languages)) {
112178
    if (variable_get('language_count', 1) > 1 || module_exists('locale'))
{
112275
      $result = db_query('SELECT * FROM {languages} ORDER BY weight ASC,
name ASC');
112375
      while ($row = db_fetch_object($result)) {
112475
        $languages['language'][$row->language] = $row;
112575
      }
112675
    }
1127
    else {
1128
      // No locale module, so use the default language only.
11293
      $default = language_default();
11303
      $languages['language'][$default->language] = $default;
1131
    }
113278
  }
1133
1134
  // Return the array indexed by the right field
113578
  if (!isset($languages[$field])) {
113663
    $languages[$field] = array();
113763
    foreach ($languages['language'] as $lang) {
1138
      // Some values should be collected into an array
113963
      if (in_array($field, array('enabled', 'weight'))) {
114063
        $languages[$field][$lang->$field][$lang->language] = $lang;
114163
      }
1142
      else {
11430
        $languages[$field][$lang->$field] = $lang;
1144
      }
114563
    }
114663
  }
114778
  return $languages[$field];
11480
}
1149
1150
/**
1151
 * Default language used on the site
1152
 *
1153
 * @param $property
1154
 *   Optional property of the language object to return
1155
 */
11562027
function language_default($property = NULL) {
11572027
  $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' => ''));
11582027
  return $property ? $language->$property : $language;
11590
}
1160
1161
/**
1162
 * If Drupal is behind a reverse proxy, we use the X-Forwarded-For header
1163
 * instead of $_SERVER['REMOTE_ADDR'], which would be the IP address of
1164
 * the proxy server, and not the client's.  If Drupal is run in a cluster
1165
 * we use the X-Cluster-Client-Ip header instead.
1166
 *
1167
 * @param $reset
1168
 *   Reset the current IP address saved in static.
1169
 * @return
1170
 *   IP address of client machine, adjusted for reverse proxy and/or
cluster
1171
 *   environments.
1172
 */
11732027
function ip_address($reset = false) {
11742087
  static $ip_address = NULL;
1175
11762087
  if (!isset($ip_address) || $reset) {
11772027
    $ip_address = $_SERVER['REMOTE_ADDR'];
1178
11792027
    if (variable_get('reverse_proxy', 0)) {
11800
      if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
1181
        // If an array of known reverse proxy IPs is provided, then trust
1182
        // the XFF header if request really comes from one of them.
11830
        $reverse_proxy_addresses = variable_get('reverse_proxy_addresses',
array());
11840
        if (!empty($reverse_proxy_addresses) && in_array($ip_address,
$reverse_proxy_addresses, TRUE)) {
1185
          // If there are several arguments, we need to check the most
1186
          // recently added one, i.e. the last one.
11870
          $ip_address = array_pop(explode(',',
$_SERVER['HTTP_X_FORWARDED_FOR']));
11880
        }
11890
      }
1190
1191
      // When Drupal is run in a cluster environment, REMOTE_ADDR contains
the IP
1192
      // address of a server in the cluster, while the IP address of the
client is
1193
      // stored in HTTP_X_CLUSTER_CLIENT_IP.
11940
      if (array_key_exists('HTTP_X_CLUSTER_CLIENT_IP', $_SERVER)) {
11950
        $ip_address = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
11960
      }
11970
    }
11982027
  }
1199
12002087
  return $ip_address;
12010
}
1202
1203
/**
1204
 * @ingroup registry
1205
 * @{
1206
 */
1207
1208
/**
1209
 * Confirm that a function is available.
1210
 *
1211
 * If the function is already available, this function does nothing.
1212
 * If the function is not available, it tries to load the file where the
1213
 * function lives. If the file is not available, it returns false, so that
it
1214
 * can be used as a drop-in replacement for function_exists().
1215
 *
1216
 * @param $function
1217
 *   The name of the function to check or load.
1218
 * @return
1219
 *   TRUE if the function is now available, FALSE otherwise.
1220
 */
12212027
function drupal_function_exists($function) {
12222087
  static $checked = array();
1223
12242087
  if (defined('MAINTENANCE_MODE')) {
12250
    return function_exists($function);
12260
  }
1227
12282087
  if (isset($checked[$function])) {
12292076
    return $checked[$function];
12300
  }
12312087
  $checked[$function] = FALSE;
1232
12332087
  if (function_exists($function)) {
12342087
    registry_mark_code('function', $function);
12352087
    $checked[$function] = TRUE;
12362087
    return TRUE;
12370
  }
1238
12391808
  $file = db_result(db_query("SELECT filename FROM {registry} WHERE name =
'%s' AND type = '%s'", $function, 'function'));
12401808
  if ($file) {
1241450
    require_once($file);
1242450
    $checked[$function] = function_exists($function);
1243450
    if ($checked[$function]) {
1244450
      registry_mark_code('function', $function);
1245450
    }
1246450
  }
1247
12481808
  return $checked[$function];
12490
}
1250
1251
/**
1252
 * Confirm that an interface is available.
1253
 *
1254
 * This function parallels drupal_function_exists(), but is rarely
1255
 * called directly. Instead, it is registered as an spl_autoload()
1256
 * handler, and PHP calls it for us when necessary.
1257
 *
1258
 * @param $interface
1259
 *   The name of the interface to check or load.
1260
 * @return
1261
 *   TRUE if the interface is currently available, FALSE otherwise.
1262
 */
12632027
function drupal_autoload_interface($interface) {
12642
  return _registry_check_code('interface', $interface);
12650
}
1266
1267
/**
1268
 * Confirm that a class is available.
1269
 *
1270
 * This function parallels drupal_function_exists(), but is rarely
1271
 * called directly. Instead, it is registered as an spl_autoload()
1272
 * handler, and PHP calls it for us when necessary.
1273
 *
1274
 * @param $class
1275
 *   The name of the class to check or load.
1276
 * @return
1277
 *   TRUE if the class is currently available, FALSE otherwise.
1278
 */
12792027
function drupal_autoload_class($class) {
12802
  return _registry_check_code('class', $class);
12810
}
1282
1283
/**
1284
 * Helper for registry_check_{interface, class}.
1285
 */
12862027
function _registry_check_code($type, $name) {
12872
  $file = db_result(db_query("SELECT filename FROM {registry} WHERE name =
'%s' AND type = '%s'", $name, $type));
12882
  if ($file) {
12890
    require_once($file);
12900
    registry_mark_code($type, $name);
12910
    return TRUE;
12920
  }
12932
}
1294
1295
/**
1296
 * Collect the resources used for this request.
1297
 *
1298
 * @param $type
1299
 *   The type of resource.
1300
 * @param $name
1301
 *   The name of the resource.
1302
 * @param $return
1303
 *   Boolean flag to indicate whether to return the resources.
1304
 */
13052027
function registry_mark_code($type, $name, $return = FALSE) {
13062087
  static $resources = array();
1307
13082087
  if ($type && $name) {
13092087
    if (!isset($resources[$type])) {
13102027
      $resources[$type] = array();
13112027
    }
13122087
    if (!in_array($name, $resources[$type])) {
13132087
      $resources[$type][] = $name;
13142087
    }
13152087
  }
1316
13172087
  if ($return) {
13181505
    return $resources;
13190
  }
13202087
}
1321
1322
/**
1323
 * Rescan all enabled modules and rebuild the registry.
1324
 *
1325
 * Rescans all code in modules or includes directory, storing a mapping of
1326
 * each function, file, and hook implementation in the database.
1327
 */
13282027
function registry_rebuild() {
132965
  require_once './includes/registry.inc';
133065
  _registry_rebuild();
133165
}
1332
1333
/**
1334
 * Save hook implementations cache.
1335
 *
1336
 * @param $hook
1337
 *   Array with the hook name and list of modules that implement it.
1338
 * @param $write_to_persistent_cache
1339
 *   Whether to write to the persistent cache.
1340
 */
13412027
function registry_cache_hook_implementations($hook,
$write_to_persistent_cache = FALSE) {
13422087
  static $implementations;
1343
13442087
  if ($hook) {
1345
    // Newer is always better, so overwrite anything that's come before.
13462087
    $implementations[$hook['hook']] = $hook['modules'];
13472087
  }
1348
13492087
  if ($write_to_persistent_cache === TRUE) {
1350
    // Only write this to cache if the implementations data we are going to
cache
1351
    // is different to what we loaded earlier in the request.
13521505
    if ($implementations != registry_get_hook_implementations_cache()) {
13531123
      cache_set('hooks', $implementations, 'cache_registry');
13541123
    }
13551505
  }
13562087
}
1357
1358
/**
1359
 * Save the files required by the registry for this path.
1360
 */
13612027
function registry_cache_path_files() {
13621505
  if ($used_code = registry_mark_code(NULL, NULL, TRUE)) {
13631505
    $files = array();
13641505
    $type_sql = array();
13651505
    $params = array();
13661505
    foreach ($used_code as $type => $names) {
13671505
      $type_sql[] = "(name IN (" . db_placeholders($names, 'varchar') . ")
AND type = '%s')";
13681505
      $params = array_merge($params, $names);
13691505
      $params[] = $type;
13701505
    }
13711505
    $res = db_query("SELECT DISTINCT filename FROM {registry} WHERE " .
implode(' OR ', $type_sql), $params);
13721505
    while ($row = db_fetch_object($res)) {
13731505
      $files[] = $row->filename;
13741505
    }
13751505
    if ($files) {
13761505
      sort($files);
1377
      // Only write this to cache if the file list we are going to cache
1378
      // is different to what we loaded earlier in the request.
13791505
      if ($files != registry_load_path_files(TRUE)) {
1380558
        $menu = menu_get_item();
1381558
        cache_set('registry:' . $menu['path'], implode(';', $files),
'cache_registry');
1382558
      }
13831505
    }
13841505
  }
13851505
}
1386
1387
/**
1388
 * registry_load_path_files
1389
 */
13902027
function registry_load_path_files($return = FALSE) {
13912010
  static $file_cache_data = array();
13922010
  if ($return) {
13931505
    sort($file_cache_data);
13941505
    return $file_cache_data;
13950
  }
13961999
  $menu = menu_get_item();
13971999
  $cache = cache_get('registry:' . $menu['path'], 'cache_registry');
13981999
  if (!empty($cache->data)) {
13991442
    foreach(explode(';', $cache->data) as $file) {
14001442
      require_once($file);
14011442
      $file_cache_data[] = $file;
14021442
    }
14031442
  }
14041999
}
1405
1406
/**
1407
 * registry_get_hook_implementations_cache
1408
 */
14092027
function registry_get_hook_implementations_cache() {
14102027
  static $implementations;
14112027
  if ($implementations === NULL) {
14122027
    if ($cache = cache_get('hooks', 'cache_registry')) {
14131946
      $implementations = $cache->data;
14141946
    }
1415
    else {
141681
      $implementations = array();
1417
    }
14182027
  }
14192027
  return $implementations;
14200
}
1421
1422
/**
1423
 * @} End of "ingroup registry".
1424
 */
1425
14262027