bootstrap.inc 24.1 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
Dries's avatar
   
Dries committed
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
   
Dries committed
4
5
6
7
/**
 * @file
 * Functions that need to be loaded on every Drupal request.
 */
Dries's avatar
   
Dries committed
8

9
10
define('CACHE_PERMANENT', 0);
define('CACHE_TEMPORARY', -1);
Dries's avatar
 
Dries committed
11

12
13
14
15
define('CACHE_DISABLED', 0);
define('CACHE_ENABLED_STRICT', 1);
define('CACHE_ENABLED_LOOSE', 2);

16
17
18
19
define('WATCHDOG_NOTICE', 0);
define('WATCHDOG_WARNING', 1);
define('WATCHDOG_ERROR', 2);

Dries's avatar
   
Dries committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
 * Start the timer with the specified name.  If you start and stop
 * the same timer multiple times, the measured intervals will be
 * accumulated.
 *
 * @param name
 *   The name of the timer.
 */
function timer_start($name) {
  global $timers;

  list($usec, $sec) = explode(' ', microtime());
  $timers[$name]['start'] = (float)$usec + (float)$sec;
  $timers[$name]['count']++;
}

/**
 * Read the current timer value without stopping the timer.
 *
 * @param name
 *   The name of the timer.
 * @return
 *   The current timer value in ms.
 */
function timer_read($name) {
  global $timers;

  list($usec, $sec) = explode(' ', microtime());
  $stop = (float)$usec + (float)$sec;
  $diff = round(($stop - $timers[$name]['start']) * 1000, 2);

  return $timers[$name]['time'] + $diff;
}

/**
 * Stop the timer with the specified name.
 *
 * @param name
 *   The name of the timer.
 * @return
 *   A timer array.  The array contains the number of times the
 *   timer has been started and stopped (count) and the accumulated
 *   timer value in ms (time).
 */
function timer_stop($name) {
  global $timers;

  list($usec, $sec) = explode(' ', microtime());
  $stop = (float)$usec + (float)$sec;
  $diff = round(($stop - $timers[$name]['start']) * 1000, 2);

  $timers[$name]['time'] += $diff;

  unset($timers[$name]['start']);

  return $timers[$name];
}
77

Dries's avatar
   
Dries committed
78
79
80
/**
 * Locate the appropriate configuration file.
 *
Dries's avatar
Dries committed
81
82
 * Try finding a matching configuration directory by stripping the
 * website's hostname from left to right and pathname from right to
Dries's avatar
   
Dries committed
83
84
85
 * left.  The first configuration file found will be used, the
 * remaining will ignored.  If no configuration file is found,
 * return a default value '$confdir/default'.
Dries's avatar
Dries committed
86
 *
87
 * Example for a fictitious site installed at
Dries's avatar
   
Dries committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
 * http://www.drupal.org/mysite/test/ the 'settings.php' is
 * searched in the following directories:
 *
 *  1. $confdir/www.drupal.org.mysite.test
 *  2. $confdir/drupal.org.mysite.test
 *  3. $confdir/org.mysite.test
 *
 *  4. $confdir/www.drupal.org.mysite
 *  5. $confdir/drupal.org.mysite
 *  6. $confdir/org.mysite
 *
 *  7. $confdir/www.drupal.org
 *  8. $confdir/drupal.org
 *  9. $confdir/org
 *
 * 10. $confdir/default
Dries's avatar
   
Dries committed
104
105
 */
function conf_init() {
Dries's avatar
Dries committed
106
  static $conf = '';
Dries's avatar
 
Dries committed
107

Dries's avatar
Dries committed
108
109
110
  if ($conf) {
    return $conf;
  }
Dries's avatar
 
Dries committed
111

Dries's avatar
   
Dries committed
112
  $confdir = 'sites';
Dries's avatar
Dries committed
113
  $uri = explode('/', $_SERVER['PHP_SELF']);
114
  $server = explode('.', rtrim($_SERVER['HTTP_HOST'], '.'));
Dries's avatar
Dries committed
115
116
117
118
119
120
121
  for ($i = count($uri) - 1; $i > 0; $i--) {
    for ($j = count($server); $j > 0; $j--) {
      $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
      if (file_exists("$confdir/$dir/settings.php")) {
        $conf = "$confdir/$dir";
        return $conf;
      }
Dries's avatar
 
Dries committed
122
123
    }
  }
Dries's avatar
Dries committed
124
125
  $conf = "$confdir/default";
  return $conf;
Dries's avatar
 
Dries committed
126
127
}

Dries's avatar
Dries committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/**
 * Returns and optionally sets the filename for a system item (module,
 * theme, etc.).  The filename, whether provided, cached, or retrieved
 * from the database, is only returned if the file exists.
 *
 * @param $type
 *   The type of the item (i.e. theme, theme_engine, module).
 * @param $name
 *   The name of the item for which the filename is requested.
 * @param $filename
 *   The filename of the item if it is to be set explicitly rather
 *   than by consulting the database.
 *
 * @return
 *   The filename of the requested item.
 */
function drupal_get_filename($type, $name, $filename = NULL) {
  static $files = array();

  if (!$files[$type]) {
    $files[$type] = array();
  }

  if ($filename && file_exists($filename)) {
    $files[$type][$name] = $filename;
  }
  elseif ($files[$type][$name]) {
    // nothing
  }
  elseif (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file)) {
    $files[$type][$name] = $file;
  }
  else {
    $config = conf_init();
    $dir = (($type == 'theme_engine') ? 'themes/engines' : "${type}s");
Dries's avatar
   
Dries committed
163
    $file = (($type == 'theme_engine') ? "$name.engine" : "$name.$type");
Dries's avatar
Dries committed
164
165
166
167
168
169
170
171
172
173
174
175

    foreach (array("$config/$dir/$file", "$config/$dir/$name/$file", "$dir/$file", "$dir/$name/$file") as $file) {
      if (file_exists($file)) {
        $files[$type][$name] = $file;
        break;
      }
    }
  }

  return $files[$type][$name];
}

Dries's avatar
   
Dries committed
176
177
178
179
180
181
182
/**
 * Load the persistent variable table.
 *
 * The variable table is composed of values that have been saved in the table
 * with variable_set() as well as those explicitly specified in the configuration
 * file.
 */
Dries's avatar
 
Dries committed
183
function variable_init($conf = array()) {
Dries's avatar
   
Dries committed
184
185
186
187
188
189
190
191
  // NOTE: caching the variables improves performance with 20% when serving cached pages.
  if ($cached = cache_get('variables')) {
    $variables = unserialize($cached->data);
  }
  else {
    $result = db_query('SELECT * FROM {variable}');
    while ($variable = db_fetch_object($result)) {
      $variables[$variable->name] = unserialize($variable->value);
Dries's avatar
 
Dries committed
192
    }
Dries's avatar
   
Dries committed
193
194
195
196
197
    cache_set('variables', serialize($variables));
  }

  foreach ($conf as $name => $value) {
    $variables[$name] = $value;
Dries's avatar
 
Dries committed
198
199
  }

Dries's avatar
   
Dries committed
200
  return $variables;
Dries's avatar
 
Dries committed
201
202
}

Dries's avatar
   
Dries committed
203
204
205
206
207
208
209
210
211
212
/**
 * Return a persistent variable.
 *
 * @param $name
 *   The name of the variable to return.
 * @param $default
 *   The default value to use if this variable has never been set.
 * @return
 *   The value of the variable.
 */
Dries's avatar
 
Dries committed
213
214
215
216
217
218
function variable_get($name, $default) {
  global $conf;

  return isset($conf[$name]) ? $conf[$name] : $default;
}

Dries's avatar
   
Dries committed
219
220
221
222
223
224
225
226
227
/**
 * Set a persistent variable.
 *
 * @param $name
 *   The name of the variable to set.
 * @param $value
 *   The value to set. This can be any PHP data type; these functions take care
 *   of serialization as necessary.
 */
Dries's avatar
 
Dries committed
228
229
230
function variable_set($name, $value) {
  global $conf;

Dries's avatar
   
Dries committed
231
  db_query('LOCK TABLES {variable} WRITE');
Dries's avatar
 
Dries committed
232
233
  db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
  db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, serialize($value));
Dries's avatar
   
Dries committed
234
235
  db_query('UNLOCK TABLES');

Dries's avatar
   
Dries committed
236
  cache_clear_all('variables');
Dries's avatar
 
Dries committed
237
238
239
240

  $conf[$name] = $value;
}

Dries's avatar
   
Dries committed
241
242
243
244
245
246
/**
 * Unset a persistent variable.
 *
 * @param $name
 *   The name of the variable to undefine.
 */
Dries's avatar
 
Dries committed
247
248
249
250
function variable_del($name) {
  global $conf;

  db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
Dries's avatar
   
Dries committed
251
  cache_clear_all('variables');
Dries's avatar
 
Dries committed
252
253
254
255

  unset($conf[$name]);
}

Dries's avatar
   
Dries committed
256
257
258
259
260
261
/**
 * Return data from the persistent cache.
 *
 * @param $key
 *   The cache ID of the data to retrieve.
 */
Dries's avatar
 
Dries committed
262
function cache_get($key) {
263
264
265
266
267
268
269
270
271
272
273
  global $user;

  // CACHE_ENABLED_LOOSE garbage collection
  $cache_flush = variable_get('cache_flush', 0);
  if ($cache_flush && ($cache_flush + variable_get('cache_flush_delay', 300) <= time())) {
    // Time to flush old cache data
    db_query("DELETE FROM {cache} WHERE expire != %d AND expire <= %d", CACHE_PERMANENT, $cache_flush);
    variable_set('cache_flush', 0);
  }

  $cache = db_fetch_object(db_query("SELECT data, created, headers, expire FROM {cache} WHERE cid = '%s'", $key));
Dries's avatar
   
Dries committed
274
  if (isset($cache->data)) {
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
    // If data is permanent or using strict caching, always return data.
    if ($cache->expire == CACHE_PERMANENT || variable_get('cache', CACHE_DISABLED) == CACHE_ENABLED_STRICT) {
      $cache->data = db_decode_blob($cache->data);
    }
    // If using loose caching, validate data is current before we return it by
    // making sure the cache entry was created before the timestamp in the
    // current session's cache timer.  The cache variable is already loaded
    // into the $user object by sess_read in session.inc.
    else {
      if ($user->cache > $cache->created) {
        // This cache data is too old and thus not valid for us, ignore it.
        return 0;
      }
      else {
        $cache->data = db_decode_blob($cache->data);
      }
    }
Dries's avatar
   
Dries committed
292
293
294
    return $cache;
  }
  return 0;
Dries's avatar
 
Dries committed
295
296
}

Dries's avatar
   
Dries committed
297
298
299
300
301
302
303
304
/**
 * Store data in the persistent cache.
 *
 * @param $cid
 *   The cache ID of the data to store.
 * @param $data
 *   The data to store in the cache. Complex data types must be serialized first.
 * @param $expire
305
306
307
308
309
310
311
 *   One of the following values:
 *   - CACHE_PERMANENT: Indicates that the item should never be removed unless
 *     explicitly told to using cache_clear_all() with a cache ID.
 *   - CACHE_TEMPORARY: Indicates that the item should be removed at the next
 *     general cache wipe.
 *   - A Unix timestamp: Indicates that the item should be kept at least until
 *     the given time, after which it behaves like CACHE_TEMPORARY.
Dries's avatar
   
Dries committed
312
313
314
 * @param $headers
 *   A string containing HTTP header information for cached pages.
 */
315
function cache_set($cid, $data, $expire = CACHE_PERMANENT, $headers = NULL) {
Dries's avatar
   
Dries committed
316
317
  $data = db_encode_blob($data);

Dries's avatar
   
Dries committed
318
  db_query('LOCK TABLES {cache} WRITE');
319
  db_query("UPDATE {cache} SET data = '%s', created = %d, expire = %d, headers = '%s' WHERE cid = '%s'", $data, time(), $expire, $headers, $cid);
Dries's avatar
 
Dries committed
320
  if (!db_affected_rows()) {
Dries's avatar
   
Dries committed
321
    @db_query("INSERT INTO {cache} (cid, data, created, expire, headers) VALUES ('%s', '%s', %d, %d, '%s')", $cid, $data, time(), $expire, $headers);
322
  }
Dries's avatar
   
Dries committed
323
  db_query('UNLOCK TABLES');
Dries's avatar
 
Dries committed
324
325
}

Dries's avatar
   
Dries committed
326
327
328
329
/**
 * Expire data from the cache.
 *
 * @param $cid
330
331
 *   If set, the cache ID to delete. Otherwise, all cache entries that can
 *   expire are deleted.
332
333
334
335
 *
 * @param $wildcard
 *   If set to true, the $cid is treated as a substring to match rather than a
 *   complete ID.
Dries's avatar
   
Dries committed
336
 */
337
function cache_clear_all($cid = NULL, $wildcard = false) {
338
339
  global $user;

Dries's avatar
 
Dries committed
340
  if (empty($cid)) {
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
    if (variable_get('cache', CACHE_DISABLED) == CACHE_ENABLED_STRICT) {
      // Strict caching, flush all temporary cache entries:
      db_query("DELETE FROM {cache} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time());
    }
    else {
      $cache_flush = variable_get('cache_flush', 0);
      // Loose caching, only flush temporary cache entries that have been
      // invalidated for more than maximum allowable time.
      if ($cache_flush && ($cache_flush + variable_get('cache_flush_delay', 300) <= time())) {
        // Only flush cache data older than $cache_flush, as newer data may
        // now be valid.
        db_query("DELETE FROM {cache} WHERE expire != %d AND expire <= %d", CACHE_PERMANENT, $cache_flush);
        variable_set('cache_flush', 0);
      }
      // Invalidate temporary cache data only for current user/session.  We
      // set $user->cache, which gets saved into the sessions table by
      // sess_write() in session.inc.
      $user->cache = time();
      if (variable_get('cache_flush', 0) == 0) {
        // Set timestamp to know which cache entries we eventually clear:
        variable_set('cache_flush', time());
      }
    }
Dries's avatar
 
Dries committed
364
365
  }
  else {
366
367
368
369
370
371
    if ($wildcard) {
      db_query("DELETE FROM {cache} WHERE cid LIKE '%%%s%%'", $cid);
    }
    else {
      db_query("DELETE FROM {cache} WHERE cid = '%s'", $cid);
    }
Dries's avatar
 
Dries committed
372
373
374
  }
}

Dries's avatar
   
Dries committed
375
376
377
/**
 * Store the current page in the cache.
 */
Dries's avatar
 
Dries committed
378
function page_set_cache() {
Dries's avatar
   
Dries committed
379
  global $user, $base_url;
Dries's avatar
 
Dries committed
380

381
382
  if (!$user->uid && $_SERVER['REQUEST_METHOD'] == 'GET') {
    // This will fail in some cases, see page_get_cache() for the explanation.
Dries's avatar
 
Dries committed
383
    if ($data = ob_get_contents()) {
Dries's avatar
   
Dries committed
384
385
386
387
388
389
390
391
      if (function_exists('gzencode')) {
        if (version_compare(phpversion(), '4.2', '>=')) {
          $data = gzencode($data, 9, FORCE_GZIP);
        }
        else {
          $data = gzencode($data, FORCE_GZIP);
        }
      }
392
      ob_end_flush();
393
      cache_set($base_url . request_uri(), $data, CACHE_TEMPORARY, drupal_get_headers());
Dries's avatar
 
Dries committed
394
395
396
397
    }
  }
}

Dries's avatar
   
Dries committed
398
399
400
401
402
403
404
405
/**
 * Retrieve the current page from the cache.
 *
 * Note, we do not serve cached pages when status messages are waiting (from
 * a redirected form submission which was completed).
 * Because the output handler is not activated, the resulting page will not
 * get cached either.
 */
Dries's avatar
 
Dries committed
406
function page_get_cache() {
Dries's avatar
   
Dries committed
407
  global $user, $base_url;
Dries's avatar
 
Dries committed
408
409

  $cache = NULL;
410

411
  if (!$user->uid && $_SERVER['REQUEST_METHOD'] == 'GET' && count(drupal_set_message()) == 0) {
Dries's avatar
   
Dries committed
412
    $cache = cache_get($base_url . request_uri());
Dries's avatar
 
Dries committed
413
414
415
416
417
418
419
420
421

    if (empty($cache)) {
      ob_start();
    }
  }

  return $cache;
}

Dries's avatar
Dries committed
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/**
 * Call all init or exit hooks without including all modules.
 *
 * @param $op
 *   The name of the bootstrap hook we wish to invoke.
 */
function bootstrap_invoke_all($op) {
  foreach (module_list(FALSE, TRUE) as $module) {
    drupal_load('module', $module);
    module_invoke($module, $op);
 }
}

/**
 * Includes a file with the provided type and name.  This prevents
 * including a theme, engine, module, etc., more than once.
 *
 * @param $type
 *   The type of item to load (i.e. theme, theme_engine, module).
 * @param $name
 *   The name of the item to load.
 *
 * @return
 *   TRUE if the item is loaded or has already been loaded.
 */
function drupal_load($type, $name) {
  // print $name. '<br />';
  static $files = array();

451
  if (isset($files[$type][$name])) {
Dries's avatar
Dries committed
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
    return TRUE;
  }

  $filename = drupal_get_filename($type, $name);

  if ($filename) {
    include_once($filename);
    $files[$type][$name] = TRUE;

    return TRUE;
  }

  return FALSE;
}

/**
468
469
470
471
472
473
474
475
476
477
 * Given an alias, return its Drupal system URL if one exists. Given a Drupal
 * system URL return its alias if one exists.
 *
 * @param $action
 *   One of the following values:
 *   - wipe: delete the alias cache.
 *   - source: indicates that given a Drupal system URL, return an alias if one exists.
 *   - alias: indicates that given an path alias, return the Drupal system URL if one exists.
 * @param $path
 *   The path to investigate for corresponding aliases or system URLs.
Dries's avatar
Dries committed
478
 */
479
480
481
function drupal_lookup_path($action, $path = '') {
  static $map = array();
  static $count = NULL;
Dries's avatar
Dries committed
482

483
484
  if ($count === NULL) {
    $count = db_result(db_query('SELECT COUNT(pid) FROM {url_alias}'));
Dries's avatar
Dries committed
485
486
  }

487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  if ($action == 'wipe') {
    $map = array();
  }
  elseif ($count > 0 && $path != '') {
    if ($action == 'source') {
      if (isset($map[$path])) {
        return $map[$path];
      }
      if ($alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s'", $path))) {
        $map[$path] = $alias;
        return $alias;
      }
      else {
        $map[$path] = $path;
      }
    }
    elseif ($action == 'alias') {
      if ($alias = array_search($path, $map)) {
        return $alias;
      }
      if (!isset($map[$path])) {
        if ($src = db_result(db_query("SELECT src FROM {url_alias} WHERE dst = '%s'", $path))) {
          $map[$src] = $path;
          return $src;
        }
        else {
          $map[$path] = $path;
        }
      }
Dries's avatar
Dries committed
516
517
518
    }
  }

519
  return FALSE;
Dries's avatar
Dries committed
520
521
522
523
524
525
}

/**
 * Given an internal Drupal path, return the alias set by the administrator.
 */
function drupal_get_path_alias($path) {
526
527
  if ($alias = drupal_lookup_path('source', $path)) {
    return $alias;
Dries's avatar
Dries committed
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
  }
  elseif (function_exists('conf_url_rewrite')) {
    return conf_url_rewrite($path, 'outgoing');
  }
  else {
    // No alias found. Return the normal path.
    return $path;
  }
}

/**
 * Get the title of the current page, for display on the page and in the title bar.
 */
function drupal_get_title() {
  $title = drupal_set_title();

  if (!isset($title)) {
    // during a bootstrap, menu.inc is not included and thus we cannot provide a title
    if (function_exists('menu_get_active_title')) {
547
      $title = check_plain(menu_get_active_title());
Dries's avatar
Dries committed
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
    }
  }

  return $title;
}

/**
 * Set the title of the current page, for display on the page and in the title bar.
 */
function drupal_set_title($title = NULL) {
  static $stored_title;

  if (isset($title)) {
    $stored_title = $title;
  }
  return $stored_title;
}

Dries's avatar
   
Dries committed
566
567
568
/**
 * Set HTTP headers in preparation for a page response.
 */
Dries's avatar
 
Dries committed
569
function drupal_page_header() {
570
  if (variable_get('cache', 0)) {
Dries's avatar
 
Dries committed
571
    if ($cache = page_get_cache()) {
572
      bootstrap_invoke_all('init');
Dries's avatar
 
Dries committed
573
      // Set default values:
574
      $date = gmdate('D, d M Y H:i:s', $cache->created) .' GMT';
Dries's avatar
 
Dries committed
575
576
577
      $etag = '"'. md5($date) .'"';

      // Check http headers:
578
579
      $modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $date : NULL;
      if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && ($timestamp = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) != -1) {
Dries's avatar
Dries committed
580
581
582
583
584
        $modified_since = $cache->created <= $timestamp;
      }
      else {
        $modified_since = NULL;
      }
585
      $none_match = !empty($_SERVER['HTTP_IF_NONE_MATCH']) ? $_SERVER['HTTP_IF_NONE_MATCH'] == $etag : NULL;
Dries's avatar
 
Dries committed
586
587
588

      // The type checking here is very important, be careful when changing entries.
      if (($modified_since !== NULL || $none_match !== NULL) && $modified_since !== false && $none_match !== false) {
589
        header('HTTP/1.0 304 Not Modified');
Dries's avatar
 
Dries committed
590
591
592
593
594
595
        exit();
      }

      // Send appropriate response:
      header("Last-Modified: $date");
      header("ETag: $etag");
Dries's avatar
   
Dries committed
596

Dries's avatar
   
Dries committed
597
      // Determine if the browser accepts gzipped data.
Dries's avatar
   
Dries committed
598
      if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === false && function_exists('gzencode')) {
Dries's avatar
   
Dries committed
599
        // Strip the gzip header and run uncompress.
Dries's avatar
   
Dries committed
600
601
602
603
604
605
        $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
      }
      elseif (function_exists('gzencode')) {
        header('Content-Encoding: gzip');
      }

Dries's avatar
   
Dries committed
606
607
608
      // Send the original request's headers.  We send them one after
      // another so PHP's header() function can deal with duplicate
      // headers.
609
      $headers = explode("\n", $cache->headers);
Dries's avatar
   
Dries committed
610
611
612
613
      foreach ($headers as $header) {
        header($header);
      }

Dries's avatar
   
Dries committed
614
      print $cache->data;
Dries's avatar
Dries committed
615
      bootstrap_invoke_all('exit');
Dries's avatar
 
Dries committed
616
617
      exit();
    }
618
619
620
621
622
623
624
    else {
      header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
      header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
      header("Cache-Control: no-store, no-cache, must-revalidate");
      header("Cache-Control: post-check=0, pre-check=0", false);
      header("Pragma: no-cache");
    }
Dries's avatar
 
Dries committed
625
626
627
  }
}

Dries's avatar
   
Dries committed
628
629
630
/**
 * Define the critical hooks that force modules to always be loaded.
 */
Dries's avatar
 
Dries committed
631
632
633
634
function bootstrap_hooks() {
  return array('init', 'exit');
}

Dries's avatar
   
Dries committed
635
636
637
638
639
640
641
642
/**
 * Unserializes and appends elements from a serialized string.
 *
 * @param $obj
 *   The object to which the elements are appended.
 * @param $field
 *   The attribute of $obj whose value should be unserialized.
 */
Dries's avatar
   
Dries committed
643
644
645
646
647
648
649
650
651
652
653
function drupal_unpack($obj, $field = 'data') {
  if ($obj->$field && $data = unserialize($obj->$field)) {
    foreach ($data as $key => $value) {
      if (!isset($obj->$key)) {
        $obj->$key = $value;
      }
    }
  }
  return $obj;
}

Dries's avatar
   
Dries committed
654
655
656
/**
 * Return the URI of the referring page.
 */
Dries's avatar
 
Dries committed
657
function referer_uri() {
658
  if (isset($_SERVER['HTTP_REFERER'])) {
659
    return $_SERVER['HTTP_REFERER'];
Dries's avatar
 
Dries committed
660
661
662
  }
}

Dries's avatar
   
Dries committed
663
664
665
666
667
668
669
670
671
672
673
/**
 * Return a component of the current Drupal path.
 *
 * When viewing a page at the path "admin/node/configure", for example, arg(0)
 * would return "admin", arg(1) would return "node", and arg(2) would return
 * "configure".
 *
 * Avoid use of this function where possible, as resulting code is hard to read.
 * Instead, attempt to use named arguments in menu callback functions. See the
 * explanation in menu.inc for how to construct callbacks that take arguments.
 */
Dries's avatar
 
Dries committed
674
function arg($index) {
Dries's avatar
   
Dries committed
675
  static $arguments, $q;
Dries's avatar
 
Dries committed
676

677
678
  if (empty($arguments) || $q != $_GET['q']) {
    $arguments = explode('/', $_GET['q']);
Dries's avatar
 
Dries committed
679
680
  }

681
  if (isset($arguments[$index])) {
Dries's avatar
   
Dries committed
682
683
    return $arguments[$index];
  }
Dries's avatar
 
Dries committed
684
685
}

Dries's avatar
   
Dries committed
686
/**
687
 * Prepare a URL for use in an HTML attribute.
Dries's avatar
   
Dries committed
688
 *
689
 * We replace ( and ) with their url-encoded equivalents to prevent XSS attacks.
Dries's avatar
   
Dries committed
690
 */
Dries's avatar
 
Dries committed
691
692
693
function check_url($uri) {
  $uri = htmlspecialchars($uri, ENT_QUOTES);

694
  $uri = strtr($uri, array('(' => '%28', ')' => '%29'));
Dries's avatar
 
Dries committed
695
696
697
698

  return $uri;
}

Dries's avatar
   
Dries committed
699
700
701
702
/**
 * Since request_uri() is only available on Apache, we generate an
 * equivalent using other environment vars.
 */
Dries's avatar
 
Dries committed
703
704
function request_uri() {

705
706
  if (isset($_SERVER['REQUEST_URI'])) {
    $uri = $_SERVER['REQUEST_URI'];
Dries's avatar
 
Dries committed
707
708
  }
  else {
709
710
711
712
713
714
    if (isset($_SERVER['argv'])) {
      $uri = $_SERVER['PHP_SELF'] .'?'. $_SERVER['argv'][0];
    }
    else {
      $uri = $_SERVER['PHP_SELF'] .'?'. $_SERVER['QUERY_STRING'];
    }
Dries's avatar
 
Dries committed
715
  }
716

717
  return $uri;
Dries's avatar
 
Dries committed
718
}
Dries's avatar
Dries committed
719

Dries's avatar
   
Dries committed
720
721
722
723
724
725
726
/**
 * Log a system message.
 *
 * @param $type
 *   The category to which this message belongs.
 * @param $message
 *   The message to store in the log.
727
728
729
730
731
 * @param $severity
 *   The severity of the message. One of the following values:
 *   - WATCHDOG_NOTICE
 *   - WATCHDOG_WARNING
 *   - WATCHDOG_ERROR
Dries's avatar
   
Dries committed
732
733
734
 * @param $link
 *   A link to associate with the message.
 */
735
function watchdog($type, $message, $severity = WATCHDOG_NOTICE, $link = NULL) {
Dries's avatar
   
Dries committed
736
  global $user;
737
  db_query("INSERT INTO {watchdog} (uid, type, message, severity, link, location, hostname, timestamp) VALUES (%d, '%s', '%s', %d, '%s', '%s', '%s', %d)", $user->uid, $type, $message, $severity, $link, request_uri(), $_SERVER['REMOTE_ADDR'], time());
Dries's avatar
   
Dries committed
738
739
}

Dries's avatar
   
Dries committed
740
/**
741
 * Set a message which reflects the status of the performed operation.
Dries's avatar
   
Dries committed
742
 *
743
744
 * If the function is called with no arguments, this function returns all set
 * messages without clearing them.
Dries's avatar
   
Dries committed
745
 *
746
747
748
749
750
751
752
 * @param $message
 *   The message should begin with a capital letter and always ends with a
 *   period '.'.
 * @param $type
 *   The type of the message. One of the following values are possible:
 *   - 'status'
 *   - 'error'
Dries's avatar
   
Dries committed
753
754
 */
function drupal_set_message($message = NULL, $type = 'status') {
755
  if (isset($message)) {
Dries's avatar
   
Dries committed
756
757
758
759
760
761
762
763
764
    if (!isset($_SESSION['messages'])) {
      $_SESSION['messages'] = array();
    }

    if (!isset($_SESSION['messages'][$type])) {
      $_SESSION['messages'][$type] = array();
    }

    $_SESSION['messages'][$type][] = $message;
765
766
767
768
769
  }

  return $_SESSION['messages'];
}

Dries's avatar
   
Dries committed
770
771
772
773
774
/**
 * Return all messages that have been set.
 *
 * As a side effect, this function clears the message queue.
 */
775
776
777
778
779
780
781
function drupal_get_messages() {
  $messages = drupal_set_message();
  $_SESSION['messages'] = array();

  return $messages;
}

Dries's avatar
   
Dries committed
782
783
784
/**
 * Perform an access check for a given mask and rule type. Rules are usually created via admin/access/rules page.
 */
785
function drupal_is_denied($type, $mask) {
Dries's avatar
   
Dries committed
786
787
788
789
790
791
  $allow = db_fetch_object(db_query("SELECT * FROM {access} WHERE status = 1 AND type = '%s' AND LOWER('%s') LIKE LOWER(mask)", $type, $mask));
  $deny = db_fetch_object(db_query("SELECT * FROM {access} WHERE status = 0 AND type = '%s' AND LOWER('%s') LIKE LOWER(mask)", $type, $mask));

  return $deny && !$allow;
}

792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
/**
 * A string describing a phase of Drupal to load. Each phase adds to the
 * previous one, so invoking a later phase automatically runs the earlier
 * phases too. The most important usage is that if you want to access
 * Drupal database from a script without loading anything else, you can
 * include bootstrap.inc, and call drupal_bootstrap('database').
 *
 * @param $phase
 *   A string. Allowed values are:
 *    'database': initialize database layer.
 *    'session': initialize session handling.
 *    'page cache': load bootstrap.inc and module.inc, start the variable
 *                  system and try to serve a page from the cache.
 *    'full': Drupal is fully loaded, validate and fix input data.
 */
function drupal_bootstrap($phase) {
  static $phases = array('database', 'session', 'page cache', 'full');

  while ($current_phase = array_shift($phases)) {
    _drupal_bootstrap($current_phase);
    if ($phase == $current_phase) {
      return;
    }
  }
}
Dries's avatar
   
Dries committed
817

818
819
function _drupal_bootstrap($phase) {
  global $conf;
Dries's avatar
 
Dries committed
820

821
822
  switch ($phase) {
    case 'database':
823
824
      global $db_url, $db_prefix, $base_url;
      $conf = array();
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
      require_once conf_init() .'/settings.php';
      require_once './includes/database.inc';
      // Initialize the default database.
      db_set_active();
      break;
    case 'session':
      require_once './includes/session.inc';
      session_set_save_handler("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");
      session_start();
      break;
    case 'page cache':
      require_once './includes/module.inc';
      // Start a page timer:
      timer_start('page');

      // deny access to hosts which were banned. t() is not yet available.
      if (drupal_is_denied('host', $_SERVER['REMOTE_ADDR'])) {
        header('HTTP/1.0 403 Forbidden');
        print "Sorry, ". $_SERVER['REMOTE_ADDR']. " has been banned.";
        exit();
      }
Dries's avatar
   
Dries committed
846

847
848
849
850
851
852
853
854
855
      // Initialize configuration variables, using values from conf.php if available.
      $conf = variable_init(isset($conf) ? $conf : array());
      drupal_page_header();
      break;
    case 'full':
      require_once './includes/common.inc';
      _drupal_bootstrap_full();
      break;
  }
Dries's avatar
   
Dries committed
856
857
}

Dries's avatar
 
Dries committed
858
?>