2006-12-12 06:27:17 +00:00
< ? php
2003-11-18 19:44:36 +00:00
2012-01-13 14:14:07 +00:00
use Symfony\Component\ClassLoader\UniversalClassLoader ;
use Symfony\Component\ClassLoader\ApcUniversalClassLoader ;
2004-07-13 07:21:14 +00:00
/**
* @ file
* Functions that need to be loaded on every Drupal request .
*/
2004-09-16 07:17:56 +00:00
2009-10-30 22:33:35 +00:00
/**
* The current system version .
*/
2011-11-29 09:56:53 +00:00
const VERSION = '8.0-dev' ;
2009-10-30 22:33:35 +00:00
/**
* Core API compatibility .
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_CORE_COMPATIBILITY = '8.x' ;
2009-10-30 22:33:35 +00:00
/**
* Minimum supported version of PHP .
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_MINIMUM_PHP = '5.3.2' ;
2009-10-30 22:33:35 +00:00
/**
* Minimum recommended value of PHP memory_limit .
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_MINIMUM_PHP_MEMORY_LIMIT = '32M' ;
2009-10-30 22:33:35 +00:00
2006-12-12 06:16:33 +00:00
/**
2009-12-30 08:16:55 +00:00
* Indicates that the item should never be removed unless explicitly selected .
*
2011-09-07 18:38:31 +00:00
* The item may be removed using cache () -> delete () with a cache ID .
2006-12-12 06:16:33 +00:00
*/
2011-11-29 09:56:53 +00:00
const CACHE_PERMANENT = 0 ;
2006-12-12 06:16:33 +00:00
/**
* Indicates that the item should be removed at the next general cache wipe .
*/
2011-11-29 09:56:53 +00:00
const CACHE_TEMPORARY = - 1 ;
2003-11-18 19:44:36 +00:00
2011-07-04 16:58:33 +00:00
/**
* @ defgroup logging_severity_levels Logging severity levels
* @ {
* Logging severity levels as defined in RFC 3164.
*
* The WATCHDOG_ * constant definitions correspond to the logging severity levels
2011-12-05 12:52:27 +00:00
* defined in RFC 3164 , section 4.1 . 1. PHP supplies predefined LOG_ * constants
2011-07-04 16:58:33 +00:00
* for use in the syslog () function , but their values on Windows builds do not
2011-12-05 12:52:27 +00:00
* correspond to RFC 3164. The associated PHP bug report was closed with the
2011-07-04 16:58:33 +00:00
* comment , " And it's also not a bug, as Windows just have less log levels, "
* and " So the behavior you're seeing is perfectly normal. "
*
* @ see http :// www . faqs . org / rfcs / rfc3164 . html
* @ see http :// bugs . php . net / bug . php ? id = 18090
* @ see http :// php . net / manual / function . syslog . php
* @ see http :// php . net / manual / network . constants . php
* @ see watchdog ()
* @ see watchdog_severity_levels ()
*/
/**
* Log message severity -- Emergency : system is unusable .
*/
2011-11-29 09:56:53 +00:00
const WATCHDOG_EMERGENCY = 0 ;
2011-07-04 16:58:33 +00:00
/**
* Log message severity -- Alert : action must be taken immediately .
*/
2011-11-29 09:56:53 +00:00
const WATCHDOG_ALERT = 1 ;
2011-07-04 16:58:33 +00:00
/**
* Log message severity -- Critical : critical conditions .
*/
2011-11-29 09:56:53 +00:00
const WATCHDOG_CRITICAL = 2 ;
2011-07-04 16:58:33 +00:00
/**
* Log message severity -- Error : error conditions .
*/
2011-11-29 09:56:53 +00:00
const WATCHDOG_ERROR = 3 ;
2011-07-04 16:58:33 +00:00
/**
* Log message severity -- Warning : warning conditions .
*/
2011-11-29 09:56:53 +00:00
const WATCHDOG_WARNING = 4 ;
2011-07-04 16:58:33 +00:00
/**
* Log message severity -- Notice : normal but significant condition .
*/
2011-11-29 09:56:53 +00:00
const WATCHDOG_NOTICE = 5 ;
2011-07-04 16:58:33 +00:00
/**
* Log message severity -- Informational : informational messages .
*/
2011-11-29 09:56:53 +00:00
const WATCHDOG_INFO = 6 ;
2011-07-04 16:58:33 +00:00
/**
* Log message severity -- Debug : debug - level messages .
*/
2011-11-29 09:56:53 +00:00
const WATCHDOG_DEBUG = 7 ;
2011-07-04 16:58:33 +00:00
/**
* @ } End of " defgroup logging_severity_levels " .
*/
2006-12-08 12:09:54 +00:00
/**
* First bootstrap phase : initialize configuration .
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_BOOTSTRAP_CONFIGURATION = 0 ;
2006-12-08 12:09:54 +00:00
/**
2009-08-16 18:39:45 +00:00
* Second bootstrap phase : try to serve a cached page .
2006-12-08 12:09:54 +00:00
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_BOOTSTRAP_PAGE_CACHE = 1 ;
2006-12-08 12:09:54 +00:00
/**
* Third bootstrap phase : initialize database layer .
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_BOOTSTRAP_DATABASE = 2 ;
2006-12-08 12:09:54 +00:00
/**
2009-09-21 08:07:07 +00:00
* Fourth bootstrap phase : initialize the variable system .
2006-12-08 12:09:54 +00:00
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_BOOTSTRAP_VARIABLES = 3 ;
2006-12-08 12:09:54 +00:00
/**
2009-09-21 08:07:07 +00:00
* Fifth bootstrap phase : initialize session handling .
2006-12-08 12:09:54 +00:00
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_BOOTSTRAP_SESSION = 4 ;
2006-12-08 12:09:54 +00:00
/**
2009-09-21 08:07:07 +00:00
* Sixth bootstrap phase : set up the page header .
2008-10-22 20:44:53 +00:00
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_BOOTSTRAP_PAGE_HEADER = 5 ;
2008-10-22 20:44:53 +00:00
/**
2009-09-21 08:07:07 +00:00
* Seventh bootstrap phase : find out language of the page .
2006-12-08 12:09:54 +00:00
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_BOOTSTRAP_LANGUAGE = 6 ;
2006-12-08 12:09:54 +00:00
/**
2011-12-05 12:52:27 +00:00
* Final bootstrap phase : Drupal is fully loaded ; validate and fix input data .
2006-12-08 12:09:54 +00:00
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_BOOTSTRAP_FULL = 7 ;
2005-07-23 05:57:27 +00:00
2006-12-11 12:00:07 +00:00
/**
* Role ID for anonymous users ; should match what ' s in the " role " table .
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_ANONYMOUS_RID = 1 ;
2006-12-11 12:00:07 +00:00
/**
* Role ID for authenticated users ; should match what ' s in the " role " table .
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_AUTHENTICATED_RID = 2 ;
2006-01-21 08:28:55 +00:00
2008-11-16 15:19:34 +00:00
/**
2011-12-05 12:52:27 +00:00
* The number of bytes in a kilobyte .
*
* For more information , visit http :// en . wikipedia . org / wiki / Kilobyte .
2008-11-16 15:19:34 +00:00
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_KILOBYTE = 1024 ;
2008-11-16 15:19:34 +00:00
2011-10-27 03:55:02 +00:00
/**
* System language ( only applicable to UI ) .
*
* Refers to the language used in Drupal and module / theme source code .
*/
2011-11-29 09:56:53 +00:00
const LANGUAGE_SYSTEM = 'system' ;
2011-10-27 03:55:02 +00:00
2009-12-02 19:26:23 +00:00
/**
* The language code used when no language is explicitly assigned .
*
2009-12-22 14:19:25 +00:00
* Defined by ISO639 - 2 for " Undetermined " .
2009-12-02 19:26:23 +00:00
*/
2011-11-29 09:56:53 +00:00
const LANGUAGE_NONE = 'und' ;
2009-12-02 19:26:23 +00:00
2007-03-26 01:32:22 +00:00
/**
2009-10-09 16:33:14 +00:00
* The type of language used to define the content language .
2007-03-26 01:32:22 +00:00
*/
2011-11-29 09:56:53 +00:00
const LANGUAGE_TYPE_CONTENT = 'language_content' ;
2007-03-26 01:32:22 +00:00
/**
2009-10-09 16:33:14 +00:00
* The type of language used to select the user interface .
2007-03-26 01:32:22 +00:00
*/
2011-11-29 09:56:53 +00:00
const LANGUAGE_TYPE_INTERFACE = 'language' ;
2007-03-26 01:32:22 +00:00
/**
2009-10-09 16:33:14 +00:00
* The type of language used for URLs .
2007-03-26 01:32:22 +00:00
*/
2011-11-29 09:56:53 +00:00
const LANGUAGE_TYPE_URL = 'language_url' ;
2007-03-26 01:32:22 +00:00
2009-01-20 03:18:41 +00:00
/**
* Language written left to right . Possible value of $language -> direction .
*/
2011-11-29 09:56:53 +00:00
const LANGUAGE_LTR = 0 ;
2009-01-20 03:18:41 +00:00
/**
* Language written right to left . Possible value of $language -> direction .
*/
2011-11-29 09:56:53 +00:00
const LANGUAGE_RTL = 1 ;
2009-01-20 03:18:41 +00:00
2008-09-17 07:11:59 +00:00
/**
2011-11-23 01:12:55 +00:00
* Time of the current request in seconds elapsed since the Unix Epoch .
2011-07-05 13:37:34 +00:00
*
2011-11-23 01:12:55 +00:00
* This differs from $_SERVER [ 'REQUEST_TIME' ], which is stored as a float
* since PHP 5.4 . 0. Float timestamps confuse most PHP functions
* ( including date_create ()) .
*
* @ see http :// php . net / manual / reserved . variables . server . php
* @ see http :// php . net / manual / function . time . php
2008-09-17 07:11:59 +00:00
*/
2011-07-05 13:37:34 +00:00
define ( 'REQUEST_TIME' , ( int ) $_SERVER [ 'REQUEST_TIME' ]);
2008-09-17 07:11:59 +00:00
2008-10-13 04:06:22 +00:00
/**
* Flag for drupal_set_title (); text is not sanitized , so run check_plain () .
*/
2011-11-29 09:56:53 +00:00
const CHECK_PLAIN = 0 ;
2008-10-13 04:06:22 +00:00
/**
* Flag for drupal_set_title (); text has already been sanitized .
*/
2011-11-29 09:56:53 +00:00
const PASS_THROUGH = - 1 ;
2008-10-13 04:06:22 +00:00
2008-11-11 22:39:59 +00:00
/**
2008-11-16 19:41:14 +00:00
* Signals that the registry lookup cache should be reset .
2008-11-11 22:39:59 +00:00
*/
2011-11-29 09:56:53 +00:00
const REGISTRY_RESET_LOOKUP_CACHE = 1 ;
2008-11-11 22:39:59 +00:00
/**
2008-11-16 19:41:14 +00:00
* Signals that the registry lookup cache should be written to storage .
2008-11-11 22:39:59 +00:00
*/
2011-11-29 09:56:53 +00:00
const REGISTRY_WRITE_LOOKUP_CACHE = 2 ;
2008-11-11 22:39:59 +00:00
2010-11-19 20:35:31 +00:00
/**
* Regular expression to match PHP function names .
*
* @ see http :// php . net / manual / en / language . functions . php
*/
2011-11-29 09:56:53 +00:00
const DRUPAL_PHP_FUNCTION_PATTERN = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*' ;
2010-11-19 20:35:31 +00:00
2011-08-27 09:14:34 +00:00
/**
* Provides a caching wrapper to be used in place of large array structures .
*
* This class should be extended by systems that need to cache large amounts
* of data and have it represented as an array to calling functions . These
* arrays can become very large , so ArrayAccess is used to allow different
* strategies to be used for caching internally ( lazy loading , building caches
* over time etc . ) . This can dramatically reduce the amount of data that needs
* to be loaded from cache backends on each request , and memory usage from
* static caches of that same data .
*
* Note that array_ * functions do not work with ArrayAccess . Systems using
* DrupalCacheArray should use this only internally . If providing API functions
* that return the full array , this can be cached separately or returned
* directly . However since DrupalCacheArray holds partial content by design , it
* should be a normal PHP array or otherwise contain the full structure .
*
* Note also that due to limitations in PHP prior to 5.3 . 4 , it is impossible to
* write directly to the contents of nested arrays contained in this object .
* Only writes to the top - level array elements are possible . So if you
* previously had set $object [ 'foo' ] = array ( 1 , 2 , 'bar' => 'baz' ), but later
* want to change the value of 'bar' from 'baz' to 'foobar' , you cannot do so
* a targeted write like $object [ 'foo' ][ 'bar' ] = 'foobar' . Instead , you must
* overwrite the entire top - level 'foo' array with the entire set of new
* values : $object [ 'foo' ] = array ( 1 , 2 , 'bar' => 'foobar' ) . Due to this same
* limitation , attempts to create references to any contained data , nested or
* otherwise , will fail silently . So $var = & $object [ 'foo' ] will not throw an
* error , and $var will be populated with the contents of $object [ 'foo' ], but
* that data will be passed by value , not reference . For more information on
* the PHP limitation , see the note in the official PHP documentation at·
* http :// php . net / manual / en / arrayaccess . offsetget . php on
* ArrayAccess :: offsetGet () .
*
* By default , the class accounts for caches where calling functions might
* request keys in the array that won ' t exist even after a cache rebuild . This
* prevents situations where a cache rebuild would be triggered over and over
* due to a 'missing' item . These cases are stored internally as a value of
* NULL . This means that the offsetGet () and offsetExists () methods
* must be overridden if caching an array where the top level values can
* legitimately be NULL , and where $object -> offsetExists () needs to correctly
* return ( equivalent to array_key_exists () vs . isset ()) . This should not
* be necessary in the majority of cases .
*
* Classes extending this class must override at least the
* resolveCacheMiss () method to have a working implementation .
*
* offsetSet () is not overridden by this class by default . In practice this
* means that assigning an offset via arrayAccess will only apply while the
* object is in scope and will not be written back to the persistent cache .
* This follows a similar pattern to static vs . persistent caching in
* procedural code . Extending classes may wish to alter this behaviour , for
* example by overriding offsetSet () and adding an automatic call to persist () .
*
* @ see SchemaCache
*/
abstract class DrupalCacheArray implements ArrayAccess {
/**
2011-09-07 18:38:31 +00:00
* A cid to pass to cache () -> set () and cache () -> get () .
2011-08-27 09:14:34 +00:00
*/
2012-01-10 15:25:36 +00:00
protected $cid ;
2011-08-27 09:14:34 +00:00
/**
2011-09-07 18:38:31 +00:00
* A bin to pass to cache () -> set () and cache () -> get () .
2011-08-27 09:14:34 +00:00
*/
2012-01-10 15:25:36 +00:00
protected $bin ;
2011-08-27 09:14:34 +00:00
/**
* An array of keys to add to the cache at the end of the request .
*/
protected $keysToPersist = array ();
/**
* Storage for the data itself .
*/
protected $storage = array ();
/**
2011-12-05 12:52:27 +00:00
* Constructs a DrupalCacheArray object .
2011-08-27 09:14:34 +00:00
*
* @ param $cid
* The cid for the array being cached .
* @ param $bin
* The bin to cache the array .
*/
public function __construct ( $cid , $bin ) {
$this -> cid = $cid ;
$this -> bin = $bin ;
2011-09-07 18:38:31 +00:00
if ( $cached = cache ( $bin ) -> get ( $this -> cid )) {
2011-08-27 09:14:34 +00:00
$this -> storage = $cached -> data ;
}
}
2011-12-05 12:52:27 +00:00
/**
* Implements ArrayAccess :: offsetExists () .
*/
2011-08-27 09:14:34 +00:00
public function offsetExists ( $offset ) {
return $this -> offsetGet ( $offset ) !== NULL ;
}
2011-12-05 12:52:27 +00:00
/**
* Implements ArrayAccess :: offsetGet () .
*/
2011-08-27 09:14:34 +00:00
public function offsetGet ( $offset ) {
if ( isset ( $this -> storage [ $offset ]) || array_key_exists ( $offset , $this -> storage )) {
return $this -> storage [ $offset ];
}
else {
return $this -> resolveCacheMiss ( $offset );
}
}
2011-12-05 12:52:27 +00:00
/**
* Implements ArrayAccess :: offsetSet () .
*/
2011-08-27 09:14:34 +00:00
public function offsetSet ( $offset , $value ) {
$this -> storage [ $offset ] = $value ;
}
2011-12-05 12:52:27 +00:00
/**
* Implements ArrayAccess :: offsetUnset () .
*/
2011-08-27 09:14:34 +00:00
public function offsetUnset ( $offset ) {
unset ( $this -> storage [ $offset ]);
}
/**
* Flags an offset value to be written to the persistent cache .
*
* If a value is assigned to a cache object with offsetSet (), by default it
* will not be written to the persistent cache unless it is flagged with this
* method . This allows items to be cached for the duration of a request ,
* without necessarily writing back to the persistent cache at the end .
*
* @ param $offset
* The array offset that was request .
* @ param $persist
* Optional boolean to specify whether the offset should be persisted or
* not , defaults to TRUE . When called with $persist = FALSE the offset will
* be unflagged so that it will not written at the end of the request .
*/
protected function persist ( $offset , $persist = TRUE ) {
$this -> keysToPersist [ $offset ] = $persist ;
}
/**
* Resolves a cache miss .
*
* When an offset is not found in the object , this is treated as a cache
* miss . This method allows classes implementing the interface to look up
* the actual value and allow it to be cached .
*
* @ param $offset
* The offset that was requested .
*
* @ return
* The value of the offset , or NULL if no value was found .
*/
abstract protected function resolveCacheMiss ( $offset );
/**
2011-12-05 12:52:27 +00:00
* Writes a value to the persistent cache immediately .
2011-08-27 09:14:34 +00:00
*
* @ param $data
* The data to write to the persistent cache .
* @ param $lock
* Whether to acquire a lock before writing to cache .
*/
2012-01-10 15:25:36 +00:00
protected function set ( $data , $lock = TRUE ) {
2011-08-27 09:14:34 +00:00
// Lock cache writes to help avoid stampedes.
// To implement locking for cache misses, override __construct().
2012-01-10 15:25:36 +00:00
$lock_name = $this -> cid . ':' . $this -> bin ;
2011-08-27 09:14:34 +00:00
if ( ! $lock || lock_acquire ( $lock_name )) {
2012-01-10 15:25:36 +00:00
if ( $cached = cache ( $this -> bin ) -> get ( $this -> cid )) {
2011-08-27 09:14:34 +00:00
$data = $cached -> data + $data ;
}
2012-01-10 15:25:36 +00:00
cache ( $this -> bin ) -> set ( $this -> cid , $data );
2011-08-27 09:14:34 +00:00
if ( $lock ) {
lock_release ( $lock_name );
}
}
}
2011-12-05 12:52:27 +00:00
/**
* Destructs the DrupalCacheArray object .
*/
2011-08-27 09:14:34 +00:00
public function __destruct () {
$data = array ();
foreach ( $this -> keysToPersist as $offset => $persist ) {
if ( $persist ) {
$data [ $offset ] = $this -> storage [ $offset ];
}
}
if ( ! empty ( $data )) {
2012-01-10 15:25:36 +00:00
$this -> set ( $data );
2011-08-27 09:14:34 +00:00
}
}
}
2005-05-12 11:21:35 +00:00
/**
2011-12-05 12:52:27 +00:00
* Starts the timer with the specified name .
*
* If you start and stop the same timer multiple times , the measured intervals
* will be accumulated .
2005-05-12 11:21:35 +00:00
*
2011-10-05 15:49:18 +00:00
* @ param $name
2005-05-12 11:21:35 +00:00
* The name of the timer .
*/
function timer_start ( $name ) {
global $timers ;
2008-10-16 21:16:06 +00:00
$timers [ $name ][ 'start' ] = microtime ( TRUE );
2006-02-27 13:46:01 +00:00
$timers [ $name ][ 'count' ] = isset ( $timers [ $name ][ 'count' ]) ? ++ $timers [ $name ][ 'count' ] : 1 ;
2005-05-12 11:21:35 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Reads the current timer value without stopping the timer .
2005-05-12 11:21:35 +00:00
*
2011-10-05 15:49:18 +00:00
* @ param $name
2005-05-12 11:21:35 +00:00
* The name of the timer .
2011-10-05 15:49:18 +00:00
*
2005-05-12 11:21:35 +00:00
* @ return
* The current timer value in ms .
*/
function timer_read ( $name ) {
global $timers ;
2006-11-12 00:21:15 +00:00
if ( isset ( $timers [ $name ][ 'start' ])) {
2008-10-16 21:16:06 +00:00
$stop = microtime ( TRUE );
2006-11-12 00:21:15 +00:00
$diff = round (( $stop - $timers [ $name ][ 'start' ]) * 1000 , 2 );
2005-05-12 11:21:35 +00:00
2006-11-12 00:21:15 +00:00
if ( isset ( $timers [ $name ][ 'time' ])) {
$diff += $timers [ $name ][ 'time' ];
}
return $diff ;
2006-09-06 06:43:03 +00:00
}
2009-10-18 11:36:49 +00:00
return $timers [ $name ][ 'time' ];
2005-05-12 11:21:35 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Stops the timer with the specified name .
2005-05-12 11:21:35 +00:00
*
2011-10-05 15:49:18 +00:00
* @ param $name
2005-05-12 11:21:35 +00:00
* The name of the timer .
2011-10-05 15:49:18 +00:00
*
2005-05-12 11:21:35 +00:00
* @ return
2009-09-14 07:43:11 +00:00
* 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 ) .
2005-05-12 11:21:35 +00:00
*/
function timer_stop ( $name ) {
global $timers ;
2010-02-25 09:13:00 +00:00
if ( isset ( $timers [ $name ][ 'start' ])) {
$stop = microtime ( TRUE );
$diff = round (( $stop - $timers [ $name ][ 'start' ]) * 1000 , 2 );
if ( isset ( $timers [ $name ][ 'time' ])) {
$timers [ $name ][ 'time' ] += $diff ;
}
else {
$timers [ $name ][ 'time' ] = $diff ;
}
unset ( $timers [ $name ][ 'start' ]);
2009-10-18 11:36:49 +00:00
}
2005-05-12 11:21:35 +00:00
return $timers [ $name ];
}
2005-01-09 09:22:40 +00:00
2004-07-13 07:21:14 +00:00
/**
2011-06-30 07:01:53 +00:00
* Finds the appropriate configuration directory .
2004-07-13 07:21:14 +00:00
*
2011-06-30 07:01:53 +00:00
* Finds a matching configuration directory by stripping the website ' s
2005-11-21 21:33:44 +00:00
* hostname from left to right and pathname from right to left . The first
2011-06-30 07:01:53 +00:00
* configuration file found will be used and the remaining ones will be ignored .
* If no configuration file is found , return a default value '$confdir/default' .
2004-11-24 22:44:01 +00:00
*
2011-06-30 07:01:53 +00:00
* With a site located at http :// www . example . com : 8080 / mysite / test / , the file ,
* settings . php , is searched for in the following directories :
2004-12-29 19:56:25 +00:00
*
2011-09-15 02:46:57 +00:00
* - $confdir / 8080. www . example . com . mysite . test
* - $confdir / www . example . com . mysite . test
* - $confdir / example . com . mysite . test
* - $confdir / com . mysite . test
2004-12-29 19:56:25 +00:00
*
2011-09-15 02:46:57 +00:00
* - $confdir / 8080. www . example . com . mysite
* - $confdir / www . example . com . mysite
* - $confdir / example . com . mysite
* - $confdir / com . mysite
2004-12-29 19:56:25 +00:00
*
2011-09-15 02:46:57 +00:00
* - $confdir / 8080. www . example . com
* - $confdir / www . example . com
* - $confdir / example . com
* - $confdir / com
2004-12-29 19:56:25 +00:00
*
2011-09-15 02:46:57 +00:00
* - $confdir / default
2007-07-30 19:22:47 +00:00
*
2008-10-12 02:47:50 +00:00
* If a file named sites . php is present in the $confdir , it will be loaded
2008-12-20 18:24:41 +00:00
* prior to scanning for directories . It should define an associative array
* named $sites , which maps domains to directories . It should be in the form
2008-10-12 02:47:50 +00:00
* of :
2011-06-30 07:01:53 +00:00
* @ code
2008-10-12 02:47:50 +00:00
* $sites = array (
* 'The url to alias' => 'A directory within the sites directory'
* );
2011-06-30 07:01:53 +00:00
* @ endcode
2008-10-12 02:47:50 +00:00
* For example :
2011-06-30 07:01:53 +00:00
* @ code
2008-10-12 02:47:50 +00:00
* $sites = array (
* 'devexample.com' => 'example.com' ,
2010-04-15 12:01:28 +00:00
* 'localhost.example' => 'example.com' ,
2008-10-12 02:47:50 +00:00
* );
2011-06-30 07:01:53 +00:00
* @ endcode
2008-10-12 02:47:50 +00:00
* The above array will cause Drupal to look for a directory named
* " example.com " in the sites directory whenever a request comes from
* " example.com " , " devexample.com " , or " localhost/example " . That is useful
* on development servers , where the domain name may not be the same as the
2008-12-20 18:24:41 +00:00
* domain of the live server . Since Drupal stores file paths into the database
2008-10-12 02:47:50 +00:00
* ( files , system table , etc . ) this will ensure the paths are correct while
* accessed on development servers .
*
2011-06-30 07:01:53 +00:00
* @ param bool $require_settings
2007-07-30 19:22:47 +00:00
* Only configuration directories with an existing settings . php file
* will be recognized . Defaults to TRUE . During initial installation ,
* this is set to FALSE so that Drupal can detect a matching directory ,
* then create a new settings . php file in it .
2011-06-30 07:01:53 +00:00
* @ param bool $reset
2007-07-30 19:22:47 +00:00
* Force a full search for matching directories even if one had been
2011-06-30 07:01:53 +00:00
* found previously . Defaults to FALSE .
*
2007-07-30 19:22:47 +00:00
* @ return
* The path of the matching directory .
2004-07-13 07:21:14 +00:00
*/
2007-07-30 19:22:47 +00:00
function conf_path ( $require_settings = TRUE , $reset = FALSE ) {
2009-04-02 20:39:45 +00:00
$conf = & drupal_static ( __FUNCTION__ , '' );
2003-11-18 19:44:36 +00:00
2007-07-30 19:22:47 +00:00
if ( $conf && ! $reset ) {
2004-11-24 22:44:01 +00:00
return $conf ;
}
2003-11-18 19:44:36 +00:00
2011-09-28 03:39:17 +00:00
$script_name = $_SERVER [ 'SCRIPT_NAME' ];
if ( ! $script_name ) {
$script_name = $_SERVER [ 'SCRIPT_FILENAME' ];
}
$http_host = $_SERVER [ 'HTTP_HOST' ];
2011-09-29 18:15:44 +00:00
$conf = find_conf_path ( $http_host , $script_name , $require_settings );
2011-09-28 03:39:17 +00:00
return $conf ;
}
/**
* Finds the appropriate configuration directory for a given host and path .
*
* @ param $http_host
* The hostname and optional port number , e . g . " www.example.com " or
* " www.example.com:8080 " .
* @ param $script_name
* The part of the url following the hostname , including the leading slash .
*
* @ return
* The path of the matching configuration directory .
*
* @ see conf_path ()
*/
function find_conf_path ( $http_host , $script_name , $require_settings = TRUE ) {
2004-12-29 19:56:25 +00:00
$confdir = 'sites' ;
2008-10-12 02:47:50 +00:00
$sites = array ();
if ( file_exists ( DRUPAL_ROOT . '/' . $confdir . '/sites.php' )) {
// This will overwrite $sites with the desired mappings.
include ( DRUPAL_ROOT . '/' . $confdir . '/sites.php' );
}
2011-09-28 03:39:17 +00:00
$uri = explode ( '/' , $script_name );
$server = explode ( '.' , implode ( '.' , array_reverse ( explode ( ':' , rtrim ( $http_host , '.' )))));
2004-11-24 22:44:01 +00:00
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 ));
2008-10-12 02:47:50 +00:00
if ( isset ( $sites [ $dir ]) && file_exists ( DRUPAL_ROOT . '/' . $confdir . '/' . $sites [ $dir ])) {
$dir = $sites [ $dir ];
}
if ( file_exists ( DRUPAL_ROOT . '/' . $confdir . '/' . $dir . '/settings.php' ) || ( ! $require_settings && file_exists ( DRUPAL_ROOT . '/' . $confdir . '/' . $dir ))) {
2004-11-24 22:44:01 +00:00
$conf = " $confdir / $dir " ;
return $conf ;
}
2003-11-18 19:44:36 +00:00
}
}
2004-11-24 22:44:01 +00:00
$conf = " $confdir /default " ;
return $conf ;
2003-11-18 19:44:36 +00:00
}
2009-07-28 12:13:47 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sets appropriate server variables needed for command line scripts to work .
2009-07-28 12:13:47 +00:00
*
* This function can be called by command line scripts before bootstrapping
* Drupal , to ensure that the page loads with the desired server parameters .
* This is because many parts of Drupal assume that they are running in a web
* browser and therefore use information from the global PHP $_SERVER variable
* that does not get set when Drupal is run from the command line .
*
* In many cases , the default way in which this function populates the $_SERVER
* variable is sufficient , and it can therefore be called without passing in
* any input . However , command line scripts running on a multisite installation
* ( or on any installation that has settings . php stored somewhere other than
* the sites / default folder ) need to pass in the URL of the site to allow
* Drupal to detect the correct location of the settings . php file . Passing in
* the 'url' parameter is also required for functions like request_uri () to
* return the expected values .
*
* Most other parameters do not need to be passed in , but may be necessary in
* some cases ; for example , if Drupal ' s ip_address () function needs to return
* anything but the standard localhost value ( '127.0.0.1' ), the command line
* script should pass in the desired value via the 'REMOTE_ADDR' key .
*
* @ param $variables
* ( optional ) An associative array of variables within $_SERVER that should
* be replaced . If the special element 'url' is provided in this array , it
* will be used to populate some of the server defaults ; it should be set to
* the URL of the current page request , excluding any $_GET request but
* including the script name ( e . g . , http :// www . example . com / mysite / index . php ) .
*
* @ see conf_path ()
* @ see request_uri ()
* @ see ip_address ()
*/
function drupal_override_server_variables ( $variables = array ()) {
2010-11-23 03:08:34 +00:00
// Allow the provided URL to override any existing values in $_SERVER.
2009-07-28 12:13:47 +00:00
if ( isset ( $variables [ 'url' ])) {
$url = parse_url ( $variables [ 'url' ]);
2010-11-23 03:08:34 +00:00
if ( isset ( $url [ 'host' ])) {
$_SERVER [ 'HTTP_HOST' ] = $url [ 'host' ];
}
if ( isset ( $url [ 'path' ])) {
$_SERVER [ 'SCRIPT_NAME' ] = $url [ 'path' ];
}
2009-07-28 12:13:47 +00:00
unset ( $variables [ 'url' ]);
}
2010-11-23 03:08:34 +00:00
// Define default values for $_SERVER keys. These will be used if $_SERVER
// does not already define them and no other values are passed in to this
// function.
2009-07-28 12:13:47 +00:00
$defaults = array (
2010-11-23 03:08:34 +00:00
'HTTP_HOST' => 'localhost' ,
'SCRIPT_NAME' => NULL ,
2009-07-28 12:13:47 +00:00
'REMOTE_ADDR' => '127.0.0.1' ,
'REQUEST_METHOD' => 'GET' ,
'SERVER_NAME' => NULL ,
2009-09-19 10:38:47 +00:00
'SERVER_SOFTWARE' => NULL ,
2009-07-28 12:13:47 +00:00
'HTTP_USER_AGENT' => NULL ,
);
// Replace elements of the $_SERVER array, as appropriate.
$_SERVER = $variables + $_SERVER + $defaults ;
}
2006-04-21 06:39:00 +00:00
/**
2011-12-05 12:52:27 +00:00
* Initializes the PHP environment .
2008-09-06 15:20:09 +00:00
*/
2009-07-14 10:22:17 +00:00
function drupal_environment_initialize () {
2008-09-06 15:20:09 +00:00
if ( ! isset ( $_SERVER [ 'HTTP_REFERER' ])) {
$_SERVER [ 'HTTP_REFERER' ] = '' ;
2006-04-21 06:39:00 +00:00
}
2008-09-08 21:24:30 +00:00
if ( ! isset ( $_SERVER [ 'SERVER_PROTOCOL' ]) || ( $_SERVER [ 'SERVER_PROTOCOL' ] != 'HTTP/1.0' && $_SERVER [ 'SERVER_PROTOCOL' ] != 'HTTP/1.1' )) {
$_SERVER [ 'SERVER_PROTOCOL' ] = 'HTTP/1.0' ;
}
2009-01-14 12:15:38 +00:00
2009-01-22 03:05:18 +00:00
if ( isset ( $_SERVER [ 'HTTP_HOST' ])) {
// As HTTP_HOST is user input, ensure it only contains characters allowed
// in hostnames. See RFC 952 (and RFC 2181).
// $_SERVER['HTTP_HOST'] is lowercased here per specifications.
$_SERVER [ 'HTTP_HOST' ] = strtolower ( $_SERVER [ 'HTTP_HOST' ]);
if ( ! drupal_valid_http_host ( $_SERVER [ 'HTTP_HOST' ])) {
// HTTP_HOST is invalid, e.g. if containing slashes it may be an attack.
header ( $_SERVER [ 'SERVER_PROTOCOL' ] . ' 400 Bad Request' );
exit ;
}
}
else {
// Some pre-HTTP/1.1 clients will not send a Host header. Ensure the key is
// defined for E_ALL compliance.
$_SERVER [ 'HTTP_HOST' ] = '' ;
2009-01-14 12:15:38 +00:00
}
2010-01-29 22:40:41 +00:00
// When clean URLs are enabled, emulate ?q=foo/bar using REQUEST_URI. It is
// not possible to append the query string using mod_rewrite without the B
// flag (this was added in Apache 2.2.8), because mod_rewrite unescapes the
// path before passing it on to PHP. This is a problem when the path contains
// e.g. "&" or "%" that have special meanings in URLs and must be encoded.
$_GET [ 'q' ] = request_path ();
2011-07-14 01:48:34 +00:00
// Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
error_reporting ( E_STRICT | E_ALL | error_reporting ());
2008-11-22 13:46:11 +00:00
2008-11-22 16:48:20 +00:00
// Override PHP settings required for Drupal to work properly.
// sites/default/default.settings.php contains more runtime settings.
// The .htaccess file contains settings that cannot be changed at runtime.
2008-11-22 13:46:11 +00:00
2008-11-22 16:48:20 +00:00
// Don't escape quotes when reading files from the database, disk, etc.
2008-11-22 13:46:11 +00:00
ini_set ( 'magic_quotes_runtime' , '0' );
2008-12-23 19:59:17 +00:00
// Use session cookies, not transparent sessions that puts the session id in
// the query string.
2009-06-06 20:15:23 +00:00
ini_set ( 'session.use_cookies' , '1' );
2008-12-23 19:59:17 +00:00
ini_set ( 'session.use_only_cookies' , '1' );
2008-12-26 11:00:23 +00:00
ini_set ( 'session.use_trans_sid' , '0' );
2008-12-23 19:59:17 +00:00
// Don't send HTTP headers using PHP's session handler.
ini_set ( 'session.cache_limiter' , 'none' );
2009-07-01 12:47:30 +00:00
// Use httponly session cookies.
ini_set ( 'session.cookie_httponly' , '1' );
2010-03-07 06:38:55 +00:00
// Set sane locale settings, to ensure consistent string, dates, times and
// numbers handling.
setlocale ( LC_ALL , 'C' );
2006-04-21 06:39:00 +00:00
}
2008-11-02 10:56:35 +00:00
/**
2011-12-05 12:52:27 +00:00
* Validates that a hostname ( for example $_SERVER [ 'HTTP_HOST' ]) is safe .
2008-11-02 10:56:35 +00:00
*
* @ return
* TRUE if only containing valid characters , or FALSE otherwise .
*/
2009-01-22 03:05:18 +00:00
function drupal_valid_http_host ( $host ) {
return preg_match ( '/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/' , $host );
2008-11-02 10:56:35 +00:00
}
2006-04-12 08:42:47 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sets the base URL , cookie domain , and session name from configuration .
2006-04-12 08:42:47 +00:00
*/
2009-07-14 10:22:17 +00:00
function drupal_settings_initialize () {
2007-04-24 08:43:31 +00:00
global $base_url , $base_path , $base_root ;
2007-04-24 10:45:20 +00:00
// Export the following settings.php variables to the global namespace
2010-07-10 17:27:50 +00:00
global $databases , $cookie_domain , $conf , $installed_profile , $update_free_access , $db_url , $db_prefix , $drupal_hash_salt , $is_https , $base_secure_url , $base_insecure_url ;
2007-04-24 10:45:20 +00:00
$conf = array ();
2008-09-20 20:22:25 +00:00
if ( file_exists ( DRUPAL_ROOT . '/' . conf_path () . '/settings.php' )) {
include_once DRUPAL_ROOT . '/' . conf_path () . '/settings.php' ;
2007-05-08 16:36:55 +00:00
}
2010-06-10 06:51:38 +00:00
$is_https = isset ( $_SERVER [ 'HTTPS' ]) && strtolower ( $_SERVER [ 'HTTPS' ]) == 'on' ;
2006-04-12 08:42:47 +00:00
if ( isset ( $base_url )) {
// Parse fixed base URL from settings.php.
$parts = parse_url ( $base_url );
2009-09-05 13:05:31 +00:00
$http_protocol = $parts [ 'scheme' ];
2006-05-02 08:37:42 +00:00
if ( ! isset ( $parts [ 'path' ])) {
$parts [ 'path' ] = '' ;
}
2008-04-14 17:48:46 +00:00
$base_path = $parts [ 'path' ] . '/' ;
2006-04-12 08:42:47 +00:00
// Build $base_root (everything until first slash after "scheme://").
$base_root = substr ( $base_url , 0 , strlen ( $base_url ) - strlen ( $parts [ 'path' ]));
}
else {
// Create base URL
2010-06-10 06:51:38 +00:00
$http_protocol = $is_https ? 'https' : 'http' ;
2009-09-05 13:05:31 +00:00
$base_root = $http_protocol . '://' . $_SERVER [ 'HTTP_HOST' ];
2007-08-30 15:53:39 +00:00
2009-09-05 13:05:31 +00:00
$base_url = $base_root ;
2007-08-30 15:53:39 +00:00
// $_SERVER['SCRIPT_NAME'] can, in contrast to $_SERVER['PHP_SELF'], not
// be modified by a visitor.
2010-01-29 22:40:41 +00:00
if ( $dir = rtrim ( dirname ( $_SERVER [ 'SCRIPT_NAME' ]), '\/' )) {
2011-10-31 04:05:57 +00:00
// Remove "core" directory if present, allowing install.php, update.php,
// cron.php and others to auto-detect a base path.
$core_position = strrpos ( $dir , '/core' );
if ( $core_position !== FALSE && strlen ( $dir ) - 5 == $core_position ) {
$base_path = substr ( $dir , 0 , $core_position );
}
else {
$base_path = $dir ;
}
2006-04-12 08:42:47 +00:00
$base_url .= $base_path ;
$base_path .= '/' ;
}
else {
$base_path = '/' ;
}
}
2009-09-05 13:05:31 +00:00
$base_secure_url = str_replace ( 'http://' , 'https://' , $base_url );
$base_insecure_url = str_replace ( 'https://' , 'http://' , $base_url );
2007-04-30 14:37:36 +00:00
if ( $cookie_domain ) {
// If the user specifies the cookie domain, also use it for session name.
$session_name = $cookie_domain ;
}
else {
2007-07-25 10:06:44 +00:00
// Otherwise use $base_url as session name, without the protocol
// to use the same session identifiers across http and https.
list ( , $session_name ) = explode ( '://' , $base_url , 2 );
2010-01-03 01:23:49 +00:00
// HTTP_HOST can be modified by a visitor, but we already sanitized it
// in drupal_settings_initialize().
2007-04-30 14:37:36 +00:00
if ( ! empty ( $_SERVER [ 'HTTP_HOST' ])) {
2010-01-03 01:23:49 +00:00
$cookie_domain = $_SERVER [ 'HTTP_HOST' ];
2010-03-24 09:17:37 +00:00
// Strip leading periods, www., and port numbers from cookie domain.
$cookie_domain = ltrim ( $cookie_domain , '.' );
if ( strpos ( $cookie_domain , 'www.' ) === 0 ) {
$cookie_domain = substr ( $cookie_domain , 4 );
}
$cookie_domain = explode ( ':' , $cookie_domain );
$cookie_domain = '.' . $cookie_domain [ 0 ];
2007-04-30 14:37:36 +00:00
}
}
// Per RFC 2109, cookie domains must contain at least one dot other than the
// first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
if ( count ( explode ( '.' , $cookie_domain )) > 2 && ! is_numeric ( str_replace ( '.' , '' , $cookie_domain ))) {
ini_set ( 'session.cookie_domain' , $cookie_domain );
}
2009-09-05 13:05:31 +00:00
// To prevent session cookies from being hijacked, a user can configure the
// SSL version of their website to only transfer session cookies via SSL by
// using PHP's session.cookie_secure setting. The browser will then use two
// separate session cookies for the HTTPS and HTTP versions of the site. So we
// must use different session identifiers for HTTPS and HTTP to prevent a
// cookie collision.
if ( $is_https ) {
ini_set ( 'session.cookie_secure' , TRUE );
}
$prefix = ini_get ( 'session.cookie_secure' ) ? 'SSESS' : 'SESS' ;
2010-05-01 08:12:23 +00:00
session_name ( $prefix . substr ( hash ( 'sha256' , $session_name ), 0 , 32 ));
2006-04-12 08:42:47 +00:00
}
2004-11-25 06:14:59 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns and optionally sets the filename for a system resource .
*
* The filename , whether provided , cached , or retrieved from the database , is
* only returned if the file exists .
2004-11-25 06:14:59 +00:00
*
2006-11-24 10:16:50 +00:00
* This function plays a key role in allowing Drupal ' s resources ( modules
* and themes ) to be located in different places depending on a site ' s
* configuration . For example , a module 'foo' may legally be be located
* in any of these three places :
*
* modules / foo / foo . module
* sites / all / modules / foo / foo . module
* sites / example . com / modules / foo / foo . module
*
* Calling drupal_get_filename ( 'module' , 'foo' ) will give you one of
* the above , depending on where the module is located .
*
2004-11-25 06:14:59 +00:00
* @ param $type
2010-02-17 03:55:45 +00:00
* The type of the item ( i . e . theme , theme_engine , module , profile ) .
2004-11-25 06:14:59 +00:00
* @ 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 .
*/
2006-11-24 10:16:50 +00:00
function drupal_get_filename ( $type , $name , $filename = NULL ) {
2009-10-31 14:00:37 +00:00
// The location of files will not change during the request, so do not use
// drupal_static().
2011-10-16 16:37:18 +00:00
static $files = array (), $dirs = array ();
2004-11-25 06:14:59 +00:00
2011-11-08 04:24:21 +00:00
// Profiles are a special case: they have a fixed location and naming.
if ( $type == 'profile' ) {
$profile_filename = " profiles/ $name / $name .profile " ;
$files [ $type ][ $name ] = file_exists ( $profile_filename ) ? $profile_filename : FALSE ;
}
2005-10-22 15:14:46 +00:00
if ( ! isset ( $files [ $type ])) {
2004-11-25 06:14:59 +00:00
$files [ $type ] = array ();
}
2005-10-22 15:14:46 +00:00
if ( ! empty ( $filename ) && file_exists ( $filename )) {
2004-11-25 06:14:59 +00:00
$files [ $type ][ $name ] = $filename ;
}
2005-10-22 15:14:46 +00:00
elseif ( isset ( $files [ $type ][ $name ])) {
2004-11-25 06:14:59 +00:00
// nothing
}
2006-11-24 10:16:50 +00:00
// Verify that we have an active database connection, before querying
2008-12-20 18:24:41 +00:00
// the database. This is required because this function is called both
2006-11-24 10:16:50 +00:00
// before we have a database connection (i.e. during installation) and
// when a database connection fails.
2004-11-25 06:14:59 +00:00
else {
2009-08-04 04:02:26 +00:00
try {
2009-12-27 03:37:54 +00:00
if ( function_exists ( 'db_query' )) {
$file = db_query ( " SELECT filename FROM { system} WHERE name = :name AND type = :type " , array ( ':name' => $name , ':type' => $type )) -> fetchField ();
2010-09-27 01:14:10 +00:00
if ( file_exists ( DRUPAL_ROOT . '/' . $file )) {
2009-12-27 03:37:54 +00:00
$files [ $type ][ $name ] = $file ;
}
2009-08-04 04:02:26 +00:00
}
}
2009-12-27 03:37:54 +00:00
catch ( Exception $e ) {
2009-08-04 04:02:26 +00:00
// The database table may not exist because Drupal is not yet installed,
// or the database might be down. We have a fallback for this case so we
// hide the error completely.
}
// Fallback to searching the filesystem if the database could not find the
// file or the file returned by the database is not found.
if ( ! isset ( $files [ $type ][ $name ])) {
// We have a consistent directory naming: modules, themes...
$dir = $type . 's' ;
if ( $type == 'theme_engine' ) {
$dir = 'themes/engines' ;
2009-12-27 03:37:54 +00:00
$extension = 'engine' ;
2009-08-04 04:02:26 +00:00
}
elseif ( $type == 'theme' ) {
2009-12-27 03:37:54 +00:00
$extension = 'info' ;
2009-08-04 04:02:26 +00:00
}
else {
2009-12-27 03:37:54 +00:00
$extension = $type ;
2009-08-04 04:02:26 +00:00
}
2011-10-16 16:37:18 +00:00
if ( ! isset ( $dirs [ $dir ][ $extension ])) {
$dirs [ $dir ][ $extension ] = TRUE ;
if ( ! function_exists ( 'drupal_system_listing' )) {
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/common.inc' ;
2011-10-16 16:37:18 +00:00
}
// Scan the appropriate directories for all files with the requested
// extension, not just the file we are currently looking for. This
// prevents unnecessary scans from being repeated when this function is
// called more than once in the same page request.
$matches = drupal_system_listing ( " /^ " . DRUPAL_PHP_FUNCTION_PATTERN . " \ . $extension $ / " , $dir , 'name' , 0 );
foreach ( $matches as $matched_name => $file ) {
$files [ $type ][ $matched_name ] = $file -> uri ;
}
2004-11-25 06:14:59 +00:00
}
}
}
2007-03-27 05:13:55 +00:00
if ( isset ( $files [ $type ][ $name ])) {
return $files [ $type ][ $name ];
}
2004-11-25 06:14:59 +00:00
}
2004-07-13 07:21:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Loads the persistent variable table .
2004-07-13 07:21:14 +00:00
*
* The variable table is composed of values that have been saved in the table
2011-12-05 12:52:27 +00:00
* with variable_set () as well as those explicitly specified in the
* configuration file .
2004-07-13 07:21:14 +00:00
*/
2009-07-14 10:22:17 +00:00
function variable_initialize ( $conf = array ()) {
2010-06-24 18:56:10 +00:00
// NOTE: caching the variables improves performance by 20% when serving
// cached pages.
2011-09-07 18:38:31 +00:00
if ( $cached = cache ( 'bootstrap' ) -> get ( 'variables' )) {
2007-04-25 21:34:32 +00:00
$variables = $cached -> data ;
2004-09-08 18:06:04 +00:00
}
else {
2010-06-24 18:56:10 +00:00
// Cache miss. Avoid a stampede.
$name = 'variable_init' ;
if ( ! lock_acquire ( $name , 1 )) {
// Another request is building the variable cache.
// Wait, then re-run this function.
lock_wait ( $name );
return variable_initialize ( $conf );
}
else {
// Proceed with variable rebuild.
$variables = array_map ( 'unserialize' , db_query ( 'SELECT name, value FROM {variable}' ) -> fetchAllKeyed ());
2011-09-07 18:38:31 +00:00
cache ( 'bootstrap' ) -> set ( 'variables' , $variables );
2010-06-24 18:56:10 +00:00
lock_release ( $name );
}
2004-09-08 18:06:04 +00:00
}
foreach ( $conf as $name => $value ) {
$variables [ $name ] = $value ;
2003-11-18 19:44:36 +00:00
}
2004-09-08 18:06:04 +00:00
return $variables ;
2003-11-18 19:44:36 +00:00
}
2004-07-13 07:21:14 +00:00
/**
2010-06-01 18:26:44 +00:00
* Returns a persistent variable .
*
* Case - sensitivity of the variable_ * functions depends on the database
* collation used . To avoid problems , always use lower case for persistent
* variable names .
2004-07-13 07:21:14 +00:00
*
* @ param $name
* The name of the variable to return .
* @ param $default
* The default value to use if this variable has never been set .
2010-03-26 17:14:46 +00:00
*
2004-07-13 07:21:14 +00:00
* @ return
* The value of the variable .
2009-08-21 00:00:43 +00:00
*
2010-03-26 17:14:46 +00:00
* @ see variable_del ()
* @ see variable_set ()
2004-07-13 07:21:14 +00:00
*/
2009-01-31 16:50:57 +00:00
function variable_get ( $name , $default = NULL ) {
2003-11-18 19:44:36 +00:00
global $conf ;
return isset ( $conf [ $name ]) ? $conf [ $name ] : $default ;
}
2004-07-13 07:21:14 +00:00
/**
2010-06-01 18:26:44 +00:00
* Sets a persistent variable .
*
* Case - sensitivity of the variable_ * functions depends on the database
* collation used . To avoid problems , always use lower case for persistent
* variable names .
2004-07-13 07:21:14 +00:00
*
* @ 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 .
2009-08-21 00:00:43 +00:00
*
2010-03-26 17:14:46 +00:00
* @ see variable_del ()
* @ see variable_get ()
2004-07-13 07:21:14 +00:00
*/
2003-11-18 19:44:36 +00:00
function variable_set ( $name , $value ) {
global $conf ;
2008-08-21 19:36:39 +00:00
db_merge ( 'variable' ) -> key ( array ( 'name' => $name )) -> fields ( array ( 'value' => serialize ( $value ))) -> execute ();
2005-05-12 11:21:35 +00:00
2011-09-07 18:38:31 +00:00
cache ( 'bootstrap' ) -> delete ( 'variables' );
2003-11-18 19:44:36 +00:00
$conf [ $name ] = $value ;
}
2004-07-13 07:21:14 +00:00
/**
2010-06-01 18:26:44 +00:00
* Unsets a persistent variable .
*
* Case - sensitivity of the variable_ * functions depends on the database
* collation used . To avoid problems , always use lower case for persistent
* variable names .
2004-07-13 07:21:14 +00:00
*
* @ param $name
* The name of the variable to undefine .
2009-08-21 00:00:43 +00:00
*
2010-03-26 17:14:46 +00:00
* @ see variable_get ()
* @ see variable_set ()
2004-07-13 07:21:14 +00:00
*/
2003-11-18 19:44:36 +00:00
function variable_del ( $name ) {
2009-05-23 19:21:30 +00:00
global $conf ;
2008-10-06 14:26:54 +00:00
db_delete ( 'variable' )
-> condition ( 'name' , $name )
-> execute ();
2011-09-07 18:38:31 +00:00
cache ( 'bootstrap' ) -> delete ( 'variables' );
2003-11-18 19:44:36 +00:00
2009-05-23 19:21:30 +00:00
unset ( $conf [ $name ]);
2003-11-18 19:44:36 +00:00
}
2004-07-13 07:21:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Retrieves the current page from the cache .
2004-07-13 07:21:14 +00:00
*
2009-01-19 10:46:52 +00:00
* Note : we do not serve cached pages to authenticated users , or to anonymous
* users when $_SESSION is non - empty . $_SESSION may contain status messages
* from a form submission , the contents of a shopping cart , or other user -
* specific content that should not be cached and displayed to other users .
*
2009-11-05 03:00:21 +00:00
* @ param $check_only
* ( optional ) Set to TRUE to only return whether a previous call found a
* cache entry .
*
2009-01-19 10:46:52 +00:00
* @ return
2009-06-02 06:58:17 +00:00
* The cache object , if the page was found in the cache , NULL otherwise .
2004-07-13 07:21:14 +00:00
*/
2009-11-05 03:00:21 +00:00
function drupal_page_get_cache ( $check_only = FALSE ) {
2009-06-02 06:58:17 +00:00
global $base_root ;
2009-11-05 03:00:21 +00:00
static $cache_hit = FALSE ;
if ( $check_only ) {
return $cache_hit ;
}
2003-11-18 19:44:36 +00:00
2009-06-02 06:58:17 +00:00
if ( drupal_page_is_cacheable ()) {
2011-09-07 18:38:31 +00:00
$cache = cache ( 'page' ) -> get ( $base_root . request_uri ());
2009-11-05 03:00:21 +00:00
if ( $cache !== FALSE ) {
$cache_hit = TRUE ;
}
return $cache ;
2009-01-19 10:46:52 +00:00
}
2009-06-02 06:58:17 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Determines the cacheability of the current page .
2009-06-02 06:58:17 +00:00
*
* @ param $allow_caching
2009-11-05 03:00:21 +00:00
* Set to FALSE if you want to prevent this page to get cached .
*
2009-06-02 06:58:17 +00:00
* @ return
2009-11-05 03:00:21 +00:00
* TRUE if the current page can be cached , FALSE otherwise .
2009-06-02 06:58:17 +00:00
*/
function drupal_page_is_cacheable ( $allow_caching = NULL ) {
$allow_caching_static = & drupal_static ( __FUNCTION__ , TRUE );
if ( isset ( $allow_caching )) {
$allow_caching_static = $allow_caching ;
2003-11-18 19:44:36 +00:00
}
2009-06-02 06:58:17 +00:00
return $allow_caching_static && ( $_SERVER [ 'REQUEST_METHOD' ] == 'GET' || $_SERVER [ 'REQUEST_METHOD' ] == 'HEAD' )
2009-09-19 10:38:47 +00:00
&& ! drupal_is_cli ();
2003-11-18 19:44:36 +00:00
}
2009-08-24 00:14:23 +00:00
/**
2011-12-05 12:52:27 +00:00
* Invokes a bootstrap hook in all bootstrap modules that implement it .
2009-08-24 00:14:23 +00:00
*
* @ param $hook
2010-04-07 05:15:51 +00:00
* The name of the bootstrap hook to invoke .
2010-06-29 18:50:36 +00:00
*
* @ see bootstrap_hooks ()
2009-08-24 00:14:23 +00:00
*/
function bootstrap_invoke_all ( $hook ) {
2010-06-29 18:50:36 +00:00
// Bootstrap modules should have been loaded when this function is called, so
2010-11-20 05:45:48 +00:00
// we don't need to tell module_list() to reset its internal list (and we
// therefore leave the first parameter at its default value of FALSE). We
// still pass in TRUE for the second parameter, though; in case this is the
// first time during the bootstrap that module_list() is called, we want to
// make sure that its internal cache is primed with the bootstrap modules
// only.
2009-11-22 08:20:51 +00:00
foreach ( module_list ( FALSE , TRUE ) as $module ) {
2009-08-24 00:14:23 +00:00
drupal_load ( 'module' , $module );
module_invoke ( $module , $hook );
}
}
2004-11-25 06:14:59 +00:00
/**
2011-12-05 12:52:27 +00:00
* Includes a file with the provided type and name .
*
* This prevents including a theme , engine , module , etc . , more than once .
2004-11-25 06:14:59 +00:00
*
* @ 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 ) {
2009-10-31 14:00:37 +00:00
// Once a file is included this can't be reversed during a request so do not
// use drupal_static() here.
static $files = array ();
2004-11-25 06:14:59 +00:00
2005-05-14 09:23:47 +00:00
if ( isset ( $files [ $type ][ $name ])) {
2004-11-25 06:14:59 +00:00
return TRUE ;
}
$filename = drupal_get_filename ( $type , $name );
if ( $filename ) {
2008-09-20 20:22:25 +00:00
include_once DRUPAL_ROOT . '/' . $filename ;
2004-11-25 06:14:59 +00:00
$files [ $type ][ $name ] = TRUE ;
return TRUE ;
}
return FALSE ;
}
2009-04-22 09:45:03 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sets an HTTP response header for the current page .
2009-04-22 09:45:03 +00:00
*
* Note : When sending a Content - Type header , always include a 'charset' type ,
* too . This is necessary to avoid security bugs ( e . g . UTF - 7 XSS ) .
*
* @ param $name
2010-03-06 06:31:24 +00:00
* The HTTP header name , or the special 'Status' header name .
2009-04-22 09:45:03 +00:00
* @ param $value
2010-03-06 06:31:24 +00:00
* The HTTP header value ; if equal to FALSE , the specified header is unset .
* If $name is 'Status' , this is expected to be a status code followed by a
* reason phrase , e . g . " 404 Not Found " .
2009-04-22 09:45:03 +00:00
* @ param $append
* Whether to append the value to an existing header or to replace it .
*/
2010-03-06 06:31:24 +00:00
function drupal_add_http_header ( $name , $value , $append = FALSE ) {
2009-04-22 09:45:03 +00:00
// The headers as name/value pairs.
2010-03-06 06:31:24 +00:00
$headers = & drupal_static ( 'drupal_http_headers' , array ());
2009-04-22 09:45:03 +00:00
2010-03-06 06:31:24 +00:00
$name_lower = strtolower ( $name );
2009-04-24 08:16:56 +00:00
_drupal_set_preferred_header_name ( $name );
2009-04-22 09:45:03 +00:00
2010-03-06 06:31:24 +00:00
if ( $value === FALSE ) {
2009-04-24 08:16:56 +00:00
$headers [ $name_lower ] = FALSE ;
2009-04-22 09:45:03 +00:00
}
2009-04-24 08:16:56 +00:00
elseif ( isset ( $headers [ $name_lower ]) && $append ) {
2009-04-22 09:45:03 +00:00
// Multiple headers with identical names may be combined using comma (RFC
// 2616, section 4.2).
2009-04-24 08:16:56 +00:00
$headers [ $name_lower ] .= ',' . $value ;
2009-04-22 09:45:03 +00:00
}
else {
2009-04-24 08:16:56 +00:00
$headers [ $name_lower ] = $value ;
2009-04-22 09:45:03 +00:00
}
2009-04-24 08:16:56 +00:00
drupal_send_headers ( array ( $name => $headers [ $name_lower ]), TRUE );
2009-04-22 09:45:03 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Gets the HTTP response headers for the current page .
2009-04-22 09:45:03 +00:00
*
* @ param $name
* An HTTP header name . If omitted , all headers are returned as name / value
* pairs . If an array value is FALSE , the header has been unset .
2011-12-05 12:52:27 +00:00
*
2009-04-22 09:45:03 +00:00
* @ return
* A string containing the header value , or FALSE if the header has been set ,
* or NULL if the header has not been set .
*/
2009-09-30 18:36:02 +00:00
function drupal_get_http_header ( $name = NULL ) {
2010-03-06 06:31:24 +00:00
$headers = & drupal_static ( 'drupal_http_headers' , array ());
2009-04-22 09:45:03 +00:00
if ( isset ( $name )) {
$name = strtolower ( $name );
return isset ( $headers [ $name ]) ? $headers [ $name ] : NULL ;
}
else {
return $headers ;
}
}
/**
2011-12-05 12:52:27 +00:00
* Sets the preferred name for the HTTP header .
*
2009-04-22 09:45:03 +00:00
* Header names are case - insensitive , but for maximum compatibility they should
* follow " common form " ( see RFC 2617 , section 4.2 ) .
*/
function _drupal_set_preferred_header_name ( $name = NULL ) {
static $header_names = array ();
if ( ! isset ( $name )) {
return $header_names ;
}
$header_names [ strtolower ( $name )] = $name ;
}
/**
2011-12-05 12:52:27 +00:00
* Sends the HTTP response headers that were previously set , adding defaults .
*
* Headers are set in drupal_add_http_header () . Default headers are not set
* if they have been replaced or unset using drupal_add_http_header () .
2009-04-22 09:45:03 +00:00
*
* @ param $default_headers
* An array of headers as name / value pairs .
* @ param $single
* If TRUE and headers have already be sent , send only the specified header .
*/
function drupal_send_headers ( $default_headers = array (), $only_default = FALSE ) {
$headers_sent = & drupal_static ( __FUNCTION__ , FALSE );
2009-09-30 18:36:02 +00:00
$headers = drupal_get_http_header ();
2009-04-22 09:45:03 +00:00
if ( $only_default && $headers_sent ) {
$headers = array ();
}
$headers_sent = TRUE ;
$header_names = _drupal_set_preferred_header_name ();
foreach ( $default_headers as $name => $value ) {
$name_lower = strtolower ( $name );
if ( ! isset ( $headers [ $name_lower ])) {
$headers [ $name_lower ] = $value ;
$header_names [ $name_lower ] = $name ;
}
}
foreach ( $headers as $name_lower => $value ) {
2010-03-06 06:31:24 +00:00
if ( $name_lower == 'status' ) {
2009-04-22 09:45:03 +00:00
header ( $_SERVER [ 'SERVER_PROTOCOL' ] . ' ' . $value );
}
// Skip headers that have been unset.
elseif ( $value ) {
header ( $header_names [ $name_lower ] . ': ' . $value );
}
}
}
2004-07-13 07:21:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sets HTTP headers in preparation for a page response .
2005-10-09 21:51:43 +00:00
*
2009-04-22 09:45:03 +00:00
* Authenticated users are always given a 'no-cache' header , and will fetch a
* fresh page on every request . This prevents authenticated users from seeing
* locally cached pages .
*
* Also give each page a unique ETag . This will force clients to include both
* an If - Modified - Since header and an If - None - Match header when doing
* conditional requests for the page ( required by RFC 2616 , section 13.3 . 4 ),
* making the validation more robust . This is a workaround for a bug in Mozilla
* Firefox that is triggered when Drupal ' s caching is enabled and the user
* accesses Drupal via an HTTP proxy ( see
* https :// bugzilla . mozilla . org / show_bug . cgi ? id = 269303 ) : When an authenticated
* user requests a page , and then logs out and requests the same page again ,
* Firefox may send a conditional request based on the page that was cached
* locally when the user was logged in . If this page did not have an ETag
* header , the request only contains an If - Modified - Since header . The date will
* be recent , because with authenticated users the Last - Modified header always
* refers to the time of the request . If the user accesses Drupal via a proxy
* server , and the proxy already has a cached copy of the anonymous page with an
* older Last - Modified date , the proxy may respond with 304 Not Modified , making
* the client think that the anonymous and authenticated pageviews are
* identical .
2006-08-03 13:42:34 +00:00
*
2009-06-02 06:58:17 +00:00
* @ see drupal_page_set_cache ()
2004-07-13 07:21:14 +00:00
*/
2003-11-18 19:44:36 +00:00
function drupal_page_header () {
2009-04-22 09:45:03 +00:00
$headers_sent = & drupal_static ( __FUNCTION__ , FALSE );
if ( $headers_sent ) {
return TRUE ;
}
$headers_sent = TRUE ;
$default_headers = array (
'Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT' ,
'Last-Modified' => gmdate ( DATE_RFC1123 , REQUEST_TIME ),
'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0' ,
'ETag' => '"' . REQUEST_TIME . '"' ,
);
drupal_send_headers ( $default_headers );
2006-08-31 18:40:04 +00:00
}
2004-02-15 15:57:55 +00:00
2006-08-31 18:40:04 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sets HTTP headers in preparation for a cached page response .
2006-08-31 18:40:04 +00:00
*
2009-04-22 09:45:03 +00:00
* The headers allow as much as possible in proxies and browsers without any
* particular knowledge about the pages . Modules can override these headers
2009-09-30 18:36:02 +00:00
* using drupal_add_http_header () .
2006-08-31 18:40:04 +00:00
*
2009-04-22 09:45:03 +00:00
* If the request is conditional ( using If - Modified - Since and If - None - Match ),
* and the conditions match those currently in the cache , a 304 Not Modified
* response is sent .
*/
2009-06-02 06:58:17 +00:00
function drupal_serve_page_from_cache ( stdClass $cache ) {
2009-04-22 09:45:03 +00:00
// Negotiate whether to use compression.
$page_compression = variable_get ( 'page_compression' , TRUE ) && extension_loaded ( 'zlib' );
$return_compressed = $page_compression && isset ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ]) && strpos ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ], 'gzip' ) !== FALSE ;
// Get headers set in hook_boot(). Keys are lower-case.
2009-09-30 18:36:02 +00:00
$hook_boot_headers = drupal_get_http_header ();
2009-04-22 09:45:03 +00:00
// Headers generated in this function, that may be replaced or unset using
2009-09-30 18:36:02 +00:00
// drupal_add_http_headers(). Keys are mixed-case.
2009-04-22 09:45:03 +00:00
$default_headers = array ();
2010-05-18 18:26:30 +00:00
foreach ( $cache -> data [ 'headers' ] as $name => $value ) {
2009-04-22 09:45:03 +00:00
// In the case of a 304 response, certain headers must be sent, and the
// remaining may not (see RFC 2616, section 10.3.5). Do not override
// headers set in hook_boot().
$name_lower = strtolower ( $name );
if ( in_array ( $name_lower , array ( 'content-location' , 'expires' , 'cache-control' , 'vary' )) && ! isset ( $hook_boot_headers [ $name_lower ])) {
2009-09-30 18:36:02 +00:00
drupal_add_http_header ( $name , $value );
2010-05-18 18:26:30 +00:00
unset ( $cache -> data [ 'headers' ][ $name ]);
2009-04-22 09:45:03 +00:00
}
}
2011-06-12 23:52:20 +00:00
// If the client sent a session cookie, a cached copy will only be served
// to that one particular client due to Vary: Cookie. Thus, do not set
// max-age > 0, allowing the page to be cached by external proxies, when a
// session cookie is present unless the Vary header has been replaced or
// unset in hook_boot().
$max_age = ! isset ( $_COOKIE [ session_name ()]) || isset ( $hook_boot_headers [ 'vary' ]) ? variable_get ( 'page_cache_maximum_age' , 0 ) : 0 ;
2009-04-22 09:45:03 +00:00
$default_headers [ 'Cache-Control' ] = 'public, max-age=' . $max_age ;
// Entity tag should change if the output changes.
$etag = '"' . $cache -> created . '-' . intval ( $return_compressed ) . '"' ;
header ( 'Etag: ' . $etag );
2006-08-31 18:40:04 +00:00
2008-12-03 14:51:53 +00:00
// See if the client has provided the required HTTP headers.
$if_modified_since = isset ( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) ? strtotime ( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) : FALSE ;
2006-08-31 18:40:04 +00:00
$if_none_match = isset ( $_SERVER [ 'HTTP_IF_NONE_MATCH' ]) ? stripslashes ( $_SERVER [ 'HTTP_IF_NONE_MATCH' ]) : FALSE ;
if ( $if_modified_since && $if_none_match
&& $if_none_match == $etag // etag must match
2008-12-03 14:51:53 +00:00
&& $if_modified_since == $cache -> created ) { // if-modified-since must match
2008-09-08 21:24:30 +00:00
header ( $_SERVER [ 'SERVER_PROTOCOL' ] . ' 304 Not Modified' );
2009-04-22 09:45:03 +00:00
drupal_send_headers ( $default_headers );
2008-10-11 04:56:34 +00:00
return ;
2006-08-31 18:40:04 +00:00
}
2006-08-03 13:42:34 +00:00
2009-04-22 09:45:03 +00:00
// Send the remaining headers.
2010-05-18 18:26:30 +00:00
foreach ( $cache -> data [ 'headers' ] as $name => $value ) {
2009-09-30 18:36:02 +00:00
drupal_add_http_header ( $name , $value );
2009-04-22 09:45:03 +00:00
}
2006-07-02 19:25:34 +00:00
2009-04-22 09:45:03 +00:00
$default_headers [ 'Last-Modified' ] = gmdate ( DATE_RFC1123 , $cache -> created );
2006-07-02 19:25:34 +00:00
2009-04-22 09:45:03 +00:00
// HTTP/1.0 proxies does not support the Vary header, so prevent any caching
// by sending an Expires date in the past. HTTP/1.1 clients ignores the
// Expires header if a Cache-Control: max-age= directive is specified (see RFC
// 2616, section 14.9.3).
$default_headers [ 'Expires' ] = 'Sun, 19 Nov 1978 05:00:00 GMT' ;
drupal_send_headers ( $default_headers );
// Allow HTTP proxies to cache pages for anonymous users without a session
// cookie. The Vary header is used to indicates the set of request-header
// fields that fully determines whether a cache is permitted to use the
// response to reply to a subsequent request for a given URL without
// revalidation. If a Vary header has been set in hook_boot(), it is assumed
// that the module knows how to cache the page.
if ( ! isset ( $hook_boot_headers [ 'vary' ]) && ! variable_get ( 'omit_vary_cookie' )) {
header ( 'Vary: Cookie' );
2003-11-18 19:44:36 +00:00
}
2006-08-31 18:40:04 +00:00
2009-04-22 09:45:03 +00:00
if ( $page_compression ) {
header ( 'Vary: Accept-Encoding' , FALSE );
// If page_compression is enabled, the cache contains gzipped data.
if ( $return_compressed ) {
2010-05-18 18:26:30 +00:00
// $cache->data['body'] is already gzip'ed, so make sure
// zlib.output_compression does not compress it once more.
2009-11-02 03:12:05 +00:00
ini_set ( 'zlib.output_compression' , '0' );
2009-04-22 09:45:03 +00:00
header ( 'Content-Encoding: gzip' );
}
else {
// The client does not support compression, so unzip the data in the
// cache. Strip the gzip header and run uncompress.
2010-05-18 18:26:30 +00:00
$cache -> data [ 'body' ] = gzinflate ( substr ( substr ( $cache -> data [ 'body' ], 10 ), 0 , - 8 ));
2009-04-22 09:45:03 +00:00
}
2006-08-31 18:40:04 +00:00
}
2010-05-18 18:26:30 +00:00
// Print the page.
print $cache -> data [ 'body' ];
2003-11-18 19:44:36 +00:00
}
2009-08-24 00:14:23 +00:00
/**
2011-12-05 12:52:27 +00:00
* Defines the critical hooks that force modules to always be loaded .
2009-08-24 00:14:23 +00:00
*/
function bootstrap_hooks () {
2010-04-07 05:15:51 +00:00
return array ( 'boot' , 'exit' , 'watchdog' , 'language_init' );
2009-08-24 00:14:23 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* 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 .
*/
2004-01-13 19:25:37 +00:00
function drupal_unpack ( $obj , $field = 'data' ) {
if ( $obj -> $field && $data = unserialize ( $obj -> $field )) {
foreach ( $data as $key => $value ) {
2010-05-21 20:19:48 +00:00
if ( ! empty ( $key ) && ! isset ( $obj -> $key )) {
2004-01-13 19:25:37 +00:00
$obj -> $key = $value ;
}
}
}
return $obj ;
}
2010-02-17 02:52:15 +00:00
/**
2010-04-29 05:03:28 +00:00
* Translates a string to the current language or to a given language .
2010-02-17 02:52:15 +00:00
*
2011-01-13 01:04:13 +00:00
* The t () function serves two purposes . First , at run - time it translates
* user - visible text into the appropriate language . Second , various mechanisms
* that figure out what text needs to be translated work off t () -- the text
2011-09-07 10:32:17 +00:00
* inside t () calls is added to the database of strings to be translated .
* These strings are expected to be in English , so the first argument should
* always be in English . To enable a fully - translatable site , it is important
* that all human - readable text that will be displayed on the site or sent to
* a user is passed through the t () function , or a related function . See the
2011-01-13 01:04:13 +00:00
* @ link http :// drupal . org / node / 322729 Localization API @ endlink pages for
* more information , including recommendations on how to break up or not
* break up strings for translation .
*
* You should never use t () to translate variables , such as calling
* @ code t ( $text ); @ endcode , unless the text that the variable holds has been
* passed through t () elsewhere ( e . g . , $text is one of several translated
* literal strings in an array ) . It is especially important never to call
* @ code t ( $user_text ); @ endcode , where $user_text is some text that a user
* entered - doing that can lead to cross - site scripting and other security
* problems . However , you can use variable substitution in your string , to put
* variable text such as user names or link URLs into translated text . Variable
* substitution looks like this :
2010-02-17 02:52:15 +00:00
* @ code
2012-01-16 02:18:26 +00:00
* $text = t ( " @name's blog " , array ( '@name' => user_format_name ( $account )));
2010-02-17 02:52:15 +00:00
* @ endcode
2011-01-13 01:04:13 +00:00
* Basically , you can put variables like @ name into your string , and t () will
2011-12-12 16:15:08 +00:00
* substitute their sanitized values at translation time . ( See the
* Localization API pages referenced above and the documentation of
* format_string () for details . ) Translators can then rearrange the string as
* necessary for the language ( e . g . , in Spanish , it might be " blog de @name " ) .
2010-02-17 02:52:15 +00:00
*
2011-05-05 03:42:31 +00:00
* During the Drupal installation phase , some resources used by t () wil not be
* available to code that needs localization . See st () and get_t () for
* alternatives .
*
2010-02-17 02:52:15 +00:00
* @ param $string
* A string containing the English string to translate .
* @ param $args
2011-12-12 16:15:08 +00:00
* An associative array of replacements to make after translation . Based
* on the first character of the key , the value is escaped and / or themed .
* See format_string () for details .
2010-02-17 02:52:15 +00:00
* @ param $options
2011-01-13 01:04:13 +00:00
* An associative array of additional options , with the following elements :
* - 'langcode' ( defaults to the current language ) : The language code to
* translate to a language other than what is used to display the page .
* - 'context' ( defaults to the empty context ) : The context the source string
* belongs to .
2010-04-29 05:03:28 +00:00
*
2010-02-17 02:52:15 +00:00
* @ return
* The translated string .
2010-04-24 14:53:59 +00:00
*
2011-05-05 03:42:31 +00:00
* @ see st ()
* @ see get_t ()
2011-12-12 16:15:08 +00:00
* @ see format_string ()
2010-04-24 14:53:59 +00:00
* @ ingroup sanitization
2010-02-17 02:52:15 +00:00
*/
function t ( $string , array $args = array (), array $options = array ()) {
2010-03-07 07:44:18 +00:00
global $language ;
2010-02-17 02:52:15 +00:00
static $custom_strings ;
// Merge in default.
if ( empty ( $options [ 'langcode' ])) {
2012-01-10 15:29:08 +00:00
$options [ 'langcode' ] = isset ( $language -> langcode ) ? $language -> langcode : LANGUAGE_SYSTEM ;
2010-02-17 02:52:15 +00:00
}
if ( empty ( $options [ 'context' ])) {
$options [ 'context' ] = '' ;
}
// First, check for an array of customized strings. If present, use the array
// *instead of* database lookups. This is a high performance way to provide a
// handful of string replacements. See settings.php for examples.
// Cache the $custom_strings variable to improve performance.
if ( ! isset ( $custom_strings [ $options [ 'langcode' ]])) {
$custom_strings [ $options [ 'langcode' ]] = variable_get ( 'locale_custom_strings_' . $options [ 'langcode' ], array ());
}
// Custom strings work for English too, even if locale module is disabled.
if ( isset ( $custom_strings [ $options [ 'langcode' ]][ $options [ 'context' ]][ $string ])) {
$string = $custom_strings [ $options [ 'langcode' ]][ $options [ 'context' ]][ $string ];
}
// Translate with locale module if enabled.
2011-10-27 03:55:02 +00:00
elseif ( $options [ 'langcode' ] != LANGUAGE_SYSTEM && ( $options [ 'langcode' ] != 'en' || variable_get ( 'locale_translate_english' , FALSE )) && function_exists ( 'locale' )) {
2010-02-17 02:52:15 +00:00
$string = locale ( $string , $options [ 'context' ], $options [ 'langcode' ]);
}
if ( empty ( $args )) {
return $string ;
}
else {
2011-08-07 15:01:39 +00:00
return format_string ( $string , $args );
}
}
/**
2011-12-05 12:52:27 +00:00
* Replaces placeholders with sanitized values in a string .
2011-08-07 15:01:39 +00:00
*
* @ param $string
* A string containing placeholders .
* @ param $args
* An associative array of replacements to make . Occurrences in $string of
* any key in $args are replaced with the corresponding value , after
* sanitization . The sanitization function depends on the first character of
* the key :
* - ! variable : Inserted as is . Use this for text that has already been
* sanitized .
* - @ variable : Escaped to HTML using check_plain () . Use this for anything
* displayed on a page on the site .
* - % variable : Escaped as a placeholder for user - submitted content using
* drupal_placeholder (), which shows up as < em > emphasized </ em > text .
*
* @ see t ()
* @ ingroup sanitization
*/
function format_string ( $string , array $args = array ()) {
// Transform arguments before inserting them.
foreach ( $args as $key => $value ) {
switch ( $key [ 0 ]) {
case '@' :
// Escaped only.
$args [ $key ] = check_plain ( $value );
break ;
case '%' :
default :
// Escaped and placeholder.
$args [ $key ] = drupal_placeholder ( $value );
break ;
case '!' :
// Pass-through.
2010-02-17 02:52:15 +00:00
}
}
2011-08-07 15:01:39 +00:00
return strtr ( $string , $args );
2010-02-17 02:52:15 +00:00
}
2005-11-29 20:37:19 +00:00
/**
2011-12-05 12:52:27 +00:00
* Encodes special characters in a plain - text string for display as HTML .
2008-01-10 22:47:17 +00:00
*
2009-11-08 13:58:03 +00:00
* Also validates strings as UTF - 8 to prevent cross site scripting attacks on
2008-01-10 22:47:17 +00:00
* Internet Explorer 6.
2009-11-08 13:58:03 +00:00
*
* @ param $text
* The text to be checked or processed .
2010-03-26 17:14:46 +00:00
*
2009-11-08 13:58:03 +00:00
* @ return
* An HTML safe version of $text , or an empty string if $text is not
* valid UTF - 8.
2010-03-26 17:14:46 +00:00
*
* @ see drupal_validate_utf8 ()
2010-04-24 14:53:59 +00:00
* @ ingroup sanitization
2005-11-29 20:37:19 +00:00
*/
function check_plain ( $text ) {
2010-10-12 03:10:03 +00:00
return htmlspecialchars ( $text , ENT_QUOTES , 'UTF-8' );
2008-01-10 22:47:17 +00:00
}
/**
* Checks whether a string is valid UTF - 8.
*
* All functions designed to filter input should use drupal_validate_utf8
* to ensure they operate on valid UTF - 8 strings to prevent bypass of the
* filter .
*
* When text containing an invalid UTF - 8 lead byte ( 0xC0 - 0xFF ) is presented
* as UTF - 8 to Internet Explorer 6 , the program may misinterpret subsequent
* bytes . When these subsequent bytes are HTML control characters such as
* quotes or angle brackets , parts of the text that were deemed safe by filters
* end up in locations that are potentially unsafe ; An onerror attribute that
* is outside of a tag , and thus deemed safe by a filter , can be interpreted
* by the browser as if it were inside the tag .
*
2008-11-07 17:21:54 +00:00
* The function does not return FALSE for strings containing character codes
* above U + 10 FFFF , even though these are prohibited by RFC 3629.
2008-01-10 22:47:17 +00:00
*
* @ param $text
* The text to check .
2011-12-05 12:52:27 +00:00
*
2008-01-10 22:47:17 +00:00
* @ return
* TRUE if the text is valid UTF - 8 , FALSE if not .
*/
function drupal_validate_utf8 ( $text ) {
if ( strlen ( $text ) == 0 ) {
return TRUE ;
}
2008-11-07 17:21:54 +00:00
// With the PCRE_UTF8 modifier 'u', preg_match() fails silently on strings
// containing invalid UTF-8 byte sequences. It does not reject character
// codes above U+10FFFF (represented by 4 or more octets), though.
2008-01-10 22:47:17 +00:00
return ( preg_match ( '/^./us' , $text ) == 1 );
2005-11-29 20:37:19 +00:00
}
2004-07-13 07:21:14 +00:00
/**
2011-09-21 09:31:43 +00:00
* Returns the equivalent of Apache 's $_SERVER[' REQUEST_URI ' ] variable .
*
* Because $_SERVER [ 'REQUEST_URI' ] is only available on Apache , we generate an
* equivalent using other environment variables .
2004-07-13 07:21:14 +00:00
*/
2003-11-18 19:44:36 +00:00
function request_uri () {
2006-12-10 20:13:36 +00:00
if ( isset ( $_SERVER [ 'REQUEST_URI' ])) {
$uri = $_SERVER [ 'REQUEST_URI' ];
}
else {
if ( isset ( $_SERVER [ 'argv' ])) {
2008-04-14 17:48:46 +00:00
$uri = $_SERVER [ 'SCRIPT_NAME' ] . '?' . $_SERVER [ 'argv' ][ 0 ];
2004-10-12 19:50:12 +00:00
}
2007-10-17 13:03:03 +00:00
elseif ( isset ( $_SERVER [ 'QUERY_STRING' ])) {
2008-04-14 17:48:46 +00:00
$uri = $_SERVER [ 'SCRIPT_NAME' ] . '?' . $_SERVER [ 'QUERY_STRING' ];
2004-10-12 19:50:12 +00:00
}
2007-10-17 13:03:03 +00:00
else {
$uri = $_SERVER [ 'SCRIPT_NAME' ];
}
2003-11-18 19:44:36 +00:00
}
2009-04-30 16:15:44 +00:00
// Prevent multiple slashes to avoid cross site requests via the Form API.
$uri = '/' . ltrim ( $uri , '/' );
2004-10-18 18:35:19 +00:00
2005-03-31 09:25:33 +00:00
return $uri ;
2003-11-18 19:44:36 +00:00
}
2003-12-13 14:10:23 +00:00
2010-05-26 07:52:13 +00:00
/**
2011-12-05 12:52:27 +00:00
* Logs an exception .
2010-05-26 07:52:13 +00:00
*
* This is a wrapper function for watchdog () which automatically decodes an
* exception .
*
* @ param $type
* The category to which this message belongs .
* @ param $exception
* The exception that is going to be logged .
* @ param $message
* The message to store in the log . If empty , a text that contains all useful
2011-04-12 20:54:16 +00:00
* information about the passed - in exception is used .
2010-05-26 07:52:13 +00:00
* @ param $variables
* Array of variables to replace in the message on display . Defaults to the
* return value of drupal_decode_exception () .
* @ param $severity
* The severity of the message , as per RFC 3164.
* @ param $link
* A link to associate with the message .
*
* @ see watchdog ()
* @ see drupal_decode_exception ()
*/
2011-07-04 16:58:33 +00:00
function watchdog_exception ( $type , Exception $exception , $message = NULL , $variables = array (), $severity = WATCHDOG_ERROR , $link = NULL ) {
2010-05-26 07:52:13 +00:00
// Use a default value if $message is not set.
if ( empty ( $message )) {
2010-10-25 00:06:19 +00:00
// The exception message is run through check_plain() by _drupal_decode_exception().
$message = '%type: !message in %function (line %line of %file).' ;
2010-05-26 07:52:13 +00:00
}
// $variables must be an array so that we can add the exception information.
if ( ! is_array ( $variables )) {
$variables = array ();
}
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/errors.inc' ;
2010-05-26 07:52:13 +00:00
$variables += _drupal_decode_exception ( $exception );
watchdog ( $type , $message , $variables , $severity , $link );
}
2004-07-13 07:21:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Logs a system message .
2004-07-13 07:21:14 +00:00
*
* @ param $type
2010-06-25 21:28:47 +00:00
* The category to which this message belongs . Can be any string , but the
* general practice is to use the name of the module calling watchdog () .
2004-07-13 07:21:14 +00:00
* @ param $message
2009-05-12 18:08:43 +00:00
* The message to store in the log . Keep $message translatable
* by not concatenating dynamic values into it ! Variables in the
* message should be added by using placeholder strings alongside
* the variables argument to declare the value of the placeholders .
* See t () for documentation on how $message and $variables interact .
2007-04-24 13:53:15 +00:00
* @ param $variables
* Array of variables to replace in the message on display or
* NULL if message is already translated or not possible to
* translate .
2005-01-09 09:22:40 +00:00
* @ param $severity
2010-06-25 21:28:47 +00:00
* The severity of the message , as per RFC 3164. Possible values are
2011-07-04 16:58:33 +00:00
* WATCHDOG_ERROR , WATCHDOG_WARNING , etc .
2004-07-13 07:21:14 +00:00
* @ param $link
* A link to associate with the message .
2007-04-30 11:12:35 +00:00
*
2008-01-08 10:35:43 +00:00
* @ see watchdog_severity_levels ()
2008-12-28 20:41:19 +00:00
* @ see hook_watchdog ()
2004-07-13 07:21:14 +00:00
*/
2011-07-04 16:58:33 +00:00
function watchdog ( $type , $message , $variables = array (), $severity = WATCHDOG_NOTICE , $link = NULL ) {
2006-04-12 08:42:47 +00:00
global $user , $base_root ;
2006-03-26 14:11:38 +00:00
2008-08-21 19:36:39 +00:00
static $in_error_state = FALSE ;
2008-12-20 18:24:41 +00:00
// It is possible that the error handling will itself trigger an error. In that case, we could
// end up in an infinite loop. To avoid that, we implement a simple static semaphore.
2010-02-17 02:52:15 +00:00
if ( ! $in_error_state && function_exists ( 'module_implements' )) {
2008-08-21 19:36:39 +00:00
$in_error_state = TRUE ;
// Prepare the fields to be logged
2008-12-28 20:41:19 +00:00
$log_entry = array (
2008-08-21 19:36:39 +00:00
'type' => $type ,
'message' => $message ,
'variables' => $variables ,
'severity' => $severity ,
'link' => $link ,
'user' => $user ,
'request_uri' => $base_root . request_uri (),
2010-07-26 03:05:36 +00:00
'referer' => isset ( $_SERVER [ 'HTTP_REFERER' ]) ? $_SERVER [ 'HTTP_REFERER' ] : '' ,
2008-08-21 19:36:39 +00:00
'ip' => ip_address (),
2008-09-17 07:11:59 +00:00
'timestamp' => REQUEST_TIME ,
2007-04-10 10:10:27 +00:00
);
2008-08-21 19:36:39 +00:00
// Call the logging hooks to log/process the message
2010-06-25 20:42:48 +00:00
foreach ( module_implements ( 'watchdog' ) as $module ) {
2008-12-28 20:41:19 +00:00
module_invoke ( $module , 'watchdog' , $log_entry );
2008-08-21 19:36:39 +00:00
}
2008-11-24 06:17:40 +00:00
// It is critical that the semaphore is only cleared here, in the parent
// watchdog() call (not outside the loop), to prevent recursive execution.
$in_error_state = FALSE ;
2006-03-26 14:11:38 +00:00
}
2003-12-10 23:09:31 +00:00
}
2004-07-13 07:21:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sets a message which reflects the status of the performed operation .
2004-07-13 07:21:14 +00:00
*
2005-05-14 18:32:22 +00:00
* If the function is called with no arguments , this function returns all set
* messages without clearing them .
2004-07-13 07:21:14 +00:00
*
2005-05-14 18:32:22 +00:00
* @ param $message
2011-04-21 02:42:21 +00:00
* The message to be displayed to the user . For consistency with other
2011-04-26 02:11:13 +00:00
* messages , it should begin with a capital letter and end with a period .
2005-05-14 18:32:22 +00:00
* @ param $type
* The type of the message . One of the following values are possible :
* - 'status'
2007-10-17 12:11:30 +00:00
* - 'warning'
2005-05-14 18:32:22 +00:00
* - 'error'
2008-01-02 14:29:32 +00:00
* @ param $repeat
* If this is FALSE and the message is already set , then the message won ' t
* be repeated .
2004-07-13 07:21:14 +00:00
*/
2008-01-02 14:29:32 +00:00
function drupal_set_message ( $message = NULL , $type = 'status' , $repeat = TRUE ) {
2006-02-10 05:42:11 +00:00
if ( $message ) {
2004-07-08 16:04:07 +00:00
if ( ! isset ( $_SESSION [ 'messages' ][ $type ])) {
$_SESSION [ 'messages' ][ $type ] = array ();
}
2008-01-02 14:29:32 +00:00
if ( $repeat || ! in_array ( $message , $_SESSION [ 'messages' ][ $type ])) {
$_SESSION [ 'messages' ][ $type ][] = $message ;
}
2009-06-02 06:58:17 +00:00
2010-07-17 02:00:50 +00:00
// Mark this page as being uncacheable.
2009-06-02 06:58:17 +00:00
drupal_page_is_cacheable ( FALSE );
2004-06-28 20:00:53 +00:00
}
2009-05-26 09:12:29 +00:00
// Messages not set when DB connection fails.
2005-10-22 15:14:46 +00:00
return isset ( $_SESSION [ 'messages' ]) ? $_SESSION [ 'messages' ] : NULL ;
2004-06-28 20:00:53 +00:00
}
2004-07-13 07:21:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns all messages that have been set .
2004-07-13 07:21:14 +00:00
*
2006-07-13 13:14:25 +00:00
* @ param $type
* ( optional ) Only return messages of this type .
2006-09-07 07:11:15 +00:00
* @ param $clear_queue
* ( optional ) Set to FALSE if you do not want to clear the messages queue
2011-12-05 12:52:27 +00:00
*
2007-04-04 20:50:53 +00:00
* @ return
* An associative array , the key is the message type , the value an array
* of messages . If the $type parameter is passed , you get only that type ,
* or an empty array if there are no such messages . If $type is not passed ,
* all message types are returned , or an empty array if none exist .
2004-07-13 07:21:14 +00:00
*/
2006-09-07 07:11:15 +00:00
function drupal_get_messages ( $type = NULL , $clear_queue = TRUE ) {
2006-04-01 14:53:03 +00:00
if ( $messages = drupal_set_message ()) {
2006-07-13 13:14:25 +00:00
if ( $type ) {
2006-09-07 07:11:15 +00:00
if ( $clear_queue ) {
2007-12-08 14:06:23 +00:00
unset ( $_SESSION [ 'messages' ][ $type ]);
2006-09-07 07:11:15 +00:00
}
2007-04-04 20:50:53 +00:00
if ( isset ( $messages [ $type ])) {
return array ( $type => $messages [ $type ]);
}
2006-07-13 13:14:25 +00:00
}
else {
2006-09-07 07:11:15 +00:00
if ( $clear_queue ) {
2007-12-08 14:06:23 +00:00
unset ( $_SESSION [ 'messages' ]);
2006-09-07 07:11:15 +00:00
}
2006-07-13 13:14:25 +00:00
return $messages ;
}
2006-04-01 14:53:03 +00:00
}
2006-07-13 13:14:25 +00:00
return array ();
2004-06-28 20:00:53 +00:00
}
2010-05-18 18:26:30 +00:00
/**
2011-12-05 12:52:27 +00:00
* Gets the title of the current page .
*
* The title is displayed on the page and in the title bar .
2010-05-18 18:26:30 +00:00
*
* @ return
* The current page ' s title .
*/
function drupal_get_title () {
$title = drupal_set_title ();
// During a bootstrap, menu.inc is not included and thus we cannot provide a title.
if ( ! isset ( $title ) && function_exists ( 'menu_get_active_title' )) {
$title = check_plain ( menu_get_active_title ());
}
return $title ;
}
/**
2011-12-05 12:52:27 +00:00
* Sets the title of the current page .
*
* The title is displayed on the page and in the title bar .
2010-05-18 18:26:30 +00:00
*
* @ param $title
* Optional string value to assign to the page title ; or if set to NULL
* ( default ), leaves the current title unchanged .
* @ param $output
* Optional flag - normally should be left as CHECK_PLAIN . Only set to
* PASS_THROUGH if you have already removed any possibly dangerous code
* from $title using a function like check_plain () or filter_xss () . With this
* flag the string will be passed through unchanged .
*
* @ return
* The updated title of the current page .
*/
function drupal_set_title ( $title = NULL , $output = CHECK_PLAIN ) {
$stored_title = & drupal_static ( __FUNCTION__ );
if ( isset ( $title )) {
$stored_title = ( $output == PASS_THROUGH ) ? $title : check_plain ( $title );
}
return $stored_title ;
}
2005-06-07 18:54:37 +00:00
/**
2011-12-05 12:52:27 +00:00
* Checks to see if an IP address has been blocked .
2008-04-08 22:50:55 +00:00
*
* Blocked IP addresses are stored in the database by default . However for
* performance reasons we allow an override in settings . php . This allows us
* to avoid querying the database at this critical stage of the bootstrap if
* an administrative interface for IP address blocking is not required .
*
2009-08-16 18:39:45 +00:00
* @ param $ip
2008-04-08 22:50:55 +00:00
* IP address to check .
2011-12-05 12:52:27 +00:00
*
2006-08-29 08:36:14 +00:00
* @ return bool
* TRUE if access is denied , FALSE if access is allowed .
2005-06-07 18:54:37 +00:00
*/
2008-04-08 22:50:55 +00:00
function drupal_is_denied ( $ip ) {
// Because this function is called on every page request, we first check
// for an array of IP addresses in settings.php before querying the
// database.
2009-01-31 16:50:57 +00:00
$blocked_ips = variable_get ( 'blocked_ips' );
2009-08-16 18:39:45 +00:00
$denied = FALSE ;
2008-04-08 22:50:55 +00:00
if ( isset ( $blocked_ips ) && is_array ( $blocked_ips )) {
2009-08-16 18:39:45 +00:00
$denied = in_array ( $ip , $blocked_ips );
2008-04-08 22:50:55 +00:00
}
2009-08-16 23:20:43 +00:00
// Only check if database.inc is loaded already. If
// $conf['page_cache_without_database'] = TRUE; is set in settings.php,
// then the database won't be loaded here so the IPs in the database
// won't be denied. However the user asked explicitly not to use the
// database and also in this case it's quite likely that the user relies
// on higher performance solutions like a firewall.
2010-04-23 05:21:19 +00:00
elseif ( class_exists ( 'Database' , FALSE )) {
2009-08-16 18:39:45 +00:00
$denied = ( bool ) db_query ( " SELECT 1 FROM { blocked_ips} WHERE ip = :ip " , array ( ':ip' => $ip )) -> fetchField ();
}
return $denied ;
}
/**
2011-12-05 12:52:27 +00:00
* Handles denied users .
2009-08-16 18:39:45 +00:00
*
* @ param $ip
* IP address to check . Prints a message and exits if access is denied .
*/
2009-08-16 23:20:43 +00:00
function drupal_block_denied ( $ip ) {
2009-08-16 18:39:45 +00:00
// Deny access to blocked IP addresses - t() is not yet available.
if ( drupal_is_denied ( $ip )) {
header ( $_SERVER [ 'SERVER_PROTOCOL' ] . ' 403 Forbidden' );
print 'Sorry, ' . check_plain ( ip_address ()) . ' has been banned.' ;
exit ();
2008-04-08 22:50:55 +00:00
}
2005-06-07 18:54:37 +00:00
}
2010-05-01 08:12:23 +00:00
/**
* Returns a string of highly randomized bytes ( over the full 8 - bit range ) .
*
* This function is better than simply calling mt_rand () or any other built - in
* PHP function because it can return a long string of bytes ( compared to < 4
2011-12-05 12:52:27 +00:00
* bytes normally from mt_rand ()) and uses the best available pseudo - random
* source .
2010-05-01 08:12:23 +00:00
*
* @ param $count
* The number of characters ( bytes ) to return in the string .
*/
function drupal_random_bytes ( $count ) {
// $random_state does not use drupal_static as it stores random bytes.
2012-01-29 21:37:38 +00:00
static $random_state , $bytes , $php_compatible ;
2010-05-01 08:12:23 +00:00
// Initialize on the first call. The contents of $_SERVER includes a mix of
// user-specific and system information that varies a little with each page.
if ( ! isset ( $random_state )) {
$random_state = print_r ( $_SERVER , TRUE );
if ( function_exists ( 'getmypid' )) {
2010-05-04 15:47:03 +00:00
// Further initialize with the somewhat random PHP process ID.
2010-05-01 08:12:23 +00:00
$random_state .= getmypid ();
}
$bytes = '' ;
}
if ( strlen ( $bytes ) < $count ) {
2012-01-29 21:37:38 +00:00
// PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes()
// locking on Windows and rendered it unusable.
if ( ! isset ( $php_compatible )) {
$php_compatible = version_compare ( PHP_VERSION , '5.3.4' , '>=' );
}
2010-05-01 08:12:23 +00:00
// /dev/urandom is available on many *nix systems and is considered the
// best commonly available pseudo-random source.
if ( $fh = @ fopen ( '/dev/urandom' , 'rb' )) {
// PHP only performs buffered reads, so in reality it will always read
// at least 4096 bytes. Thus, it costs nothing extra to read and store
// that much so as to speed any additional invocations.
$bytes .= fread ( $fh , max ( 4096 , $count ));
fclose ( $fh );
}
2012-01-29 21:37:38 +00:00
// openssl_random_pseudo_bytes() will find entropy in a system-dependent
// way.
elseif ( $php_compatible && function_exists ( 'openssl_random_pseudo_bytes' )) {
$bytes .= openssl_random_pseudo_bytes ( $count - strlen ( $bytes ));
}
2010-05-01 08:12:23 +00:00
// If /dev/urandom is not available or returns no bytes, this loop will
// generate a good set of pseudo-random bytes on any system.
// Note that it may be important that our $random_state is passed
// through hash() prior to being rolled into $output, that the two hash()
// invocations are different, and that the extra input into the first one -
// the microtime() - is prepended rather than appended. This is to avoid
// directly leaking $random_state via the $output stream, which could
// allow for trivial prediction of further "random" numbers.
while ( strlen ( $bytes ) < $count ) {
$random_state = hash ( 'sha256' , microtime () . mt_rand () . $random_state );
$bytes .= hash ( 'sha256' , mt_rand () . $random_state , TRUE );
}
}
$output = substr ( $bytes , 0 , $count );
$bytes = substr ( $bytes , $count );
return $output ;
}
/**
2011-12-05 12:52:27 +00:00
* Calculates a base - 64 encoded , URL - safe sha - 256 hmac .
2010-05-01 08:12:23 +00:00
*
* @ param $data
* String to be validated with the hmac .
* @ param $key
* A secret string key .
*
* @ return
* A base - 64 encoded sha - 256 hmac , with + replaced with - , / with _ and
* any = padding characters removed .
*/
function drupal_hmac_base64 ( $data , $key ) {
$hmac = base64_encode ( hash_hmac ( 'sha256' , $data , $key , TRUE ));
// Modify the hmac so it's safe to use in URLs.
return strtr ( $hmac , array ( '+' => '-' , '/' => '_' , '=' => '' ));
}
/**
2011-12-05 12:52:27 +00:00
* Calculates a base - 64 encoded , URL - safe sha - 256 hash .
2010-05-01 08:12:23 +00:00
*
* @ param $data
* String to be hashed .
*
* @ return
* A base - 64 encoded sha - 256 hash , with + replaced with - , / with _ and
* any = padding characters removed .
*/
function drupal_hash_base64 ( $data ) {
$hash = base64_encode ( hash ( 'sha256' , $data , TRUE ));
// Modify the hash so it's safe to use in URLs.
return strtr ( $hash , array ( '+' => '-' , '/' => '_' , '=' => '' ));
}
2010-11-20 05:02:46 +00:00
/**
* Merges multiple arrays , recursively , and returns the merged array .
*
* This function is similar to PHP ' s array_merge_recursive () function , but it
* handles non - array values differently . When merging values that are not both
* arrays , the latter value replaces the former rather than merging with it .
*
* Example :
* @ code
* $link_options_1 = array ( 'fragment' => 'x' , 'attributes' => array ( 'title' => t ( 'X' ), 'class' => array ( 'a' , 'b' )));
* $link_options_2 = array ( 'fragment' => 'y' , 'attributes' => array ( 'title' => t ( 'Y' ), 'class' => array ( 'c' , 'd' )));
*
* // This results in array('fragment' => array('x', 'y'), 'attributes' => array('title' => array(t('X'), t('Y')), 'class' => array('a', 'b', 'c', 'd'))).
* $incorrect = array_merge_recursive ( $link_options_1 , $link_options_2 );
*
* // This results in array('fragment' => 'y', 'attributes' => array('title' => t('Y'), 'class' => array('a', 'b', 'c', 'd'))).
* $correct = drupal_array_merge_deep ( $link_options_1 , $link_options_2 );
* @ endcode
*
* @ param ...
* Arrays to merge .
*
* @ return
* The merged array .
*
* @ see drupal_array_merge_deep_array ()
*/
function drupal_array_merge_deep () {
return drupal_array_merge_deep_array ( func_get_args ());
}
/**
* Merges multiple arrays , recursively , and returns the merged array .
*
* This function is equivalent to drupal_array_merge_deep (), except the
* input arrays are passed as a single array parameter rather than a variable
* parameter list .
*
* The following are equivalent :
* - drupal_array_merge_deep ( $a , $b );
* - drupal_array_merge_deep_array ( array ( $a , $b ));
*
* The following are also equivalent :
* - call_user_func_array ( 'drupal_array_merge_deep' , $arrays_to_merge );
* - drupal_array_merge_deep_array ( $arrays_to_merge );
*
* @ see drupal_array_merge_deep ()
*/
function drupal_array_merge_deep_array ( $arrays ) {
$result = array ();
foreach ( $arrays as $array ) {
foreach ( $array as $key => $value ) {
// Renumber integer keys as array_merge_recursive() does. Note that PHP
// automatically converts array keys that are integer strings (e.g., '1')
// to integers.
if ( is_integer ( $key )) {
$result [] = $value ;
}
// Recurse when both values are arrays.
elseif ( isset ( $result [ $key ]) && is_array ( $result [ $key ]) && is_array ( $value )) {
$result [ $key ] = drupal_array_merge_deep_array ( array ( $result [ $key ], $value ));
}
// Otherwise, use the latter value, overriding any previous value.
else {
$result [ $key ] = $value ;
}
}
}
return $result ;
}
2006-08-16 13:13:34 +00:00
/**
2006-08-25 05:42:00 +00:00
* Generates a default anonymous $user object .
2006-08-16 13:13:34 +00:00
*
* @ return Object - the user object .
*/
2010-10-15 04:15:41 +00:00
function drupal_anonymous_user () {
2006-08-16 13:13:34 +00:00
$user = new stdClass ();
$user -> uid = 0 ;
2007-05-25 15:04:42 +00:00
$user -> hostname = ip_address ();
2006-08-16 13:13:34 +00:00
$user -> roles = array ();
$user -> roles [ DRUPAL_ANONYMOUS_RID ] = 'anonymous user' ;
2007-03-25 20:54:33 +00:00
$user -> cache = 0 ;
2006-08-16 13:13:34 +00:00
return $user ;
}
2005-06-22 20:19:58 +00:00
/**
2011-12-05 12:52:27 +00:00
* Ensures Drupal is bootstrapped to the specified phase .
*
* The bootstrap phase is an integer constant identifying a phase of Drupal
* to load . Each phase adds to the previous one , so invoking a later phase
* automatically runs the earlier phases as well . To access the Drupal
* database from a script without loading anything else , include bootstrap . inc
* and call drupal_bootstrap ( DRUPAL_BOOTSTRAP_DATABASE ) .
2005-06-22 20:19:58 +00:00
*
* @ param $phase
2009-09-21 08:07:07 +00:00
* A constant . Allowed values are the DRUPAL_BOOTSTRAP_ * constants .
2009-08-16 18:39:45 +00:00
* @ param $new_phase
* A boolean , set to FALSE if calling drupal_bootstrap from inside a
* function called from drupal_bootstrap ( recursion ) .
2011-12-05 12:52:27 +00:00
*
2009-10-03 19:27:44 +00:00
* @ return
* The most recently completed phase .
2009-08-16 18:39:45 +00:00
*/
function drupal_bootstrap ( $phase = NULL , $new_phase = TRUE ) {
2009-11-21 14:06:46 +00:00
// Not drupal_static(), because does not depend on any run-time information.
static $phases = array (
2009-04-02 20:39:45 +00:00
DRUPAL_BOOTSTRAP_CONFIGURATION ,
2009-08-16 18:39:45 +00:00
DRUPAL_BOOTSTRAP_PAGE_CACHE ,
2009-04-02 20:39:45 +00:00
DRUPAL_BOOTSTRAP_DATABASE ,
DRUPAL_BOOTSTRAP_VARIABLES ,
2009-08-16 18:39:45 +00:00
DRUPAL_BOOTSTRAP_SESSION ,
DRUPAL_BOOTSTRAP_PAGE_HEADER ,
2009-04-02 20:39:45 +00:00
DRUPAL_BOOTSTRAP_LANGUAGE ,
DRUPAL_BOOTSTRAP_FULL ,
2009-11-21 14:06:46 +00:00
);
// Not drupal_static(), because the only legitimate API to control this is to
// call drupal_bootstrap() with a new phase parameter.
static $final_phase ;
// Not drupal_static(), because it's impossible to roll back to an earlier
// bootstrap state.
2010-01-14 21:17:56 +00:00
static $stored_phase = - 1 ;
2008-10-19 21:27:13 +00:00
2009-11-21 14:06:46 +00:00
// When not recursing, store the phase name so it's not forgotten while
// recursing.
if ( $new_phase ) {
$final_phase = $phase ;
}
2008-10-20 11:33:00 +00:00
if ( isset ( $phase )) {
2009-08-16 23:20:43 +00:00
// Call a phase if it has not been called before and is below the requested
// phase.
2010-01-14 21:17:56 +00:00
while ( $phases && $phase > $stored_phase && $final_phase > $stored_phase ) {
2008-10-19 21:27:13 +00:00
$current_phase = array_shift ( $phases );
2010-01-14 21:17:56 +00:00
// This function is re-entrant. Only update the completed phase when the
// current call actually resulted in a progress in the bootstrap process.
if ( $current_phase > $stored_phase ) {
$stored_phase = $current_phase ;
}
2009-11-05 03:00:21 +00:00
switch ( $current_phase ) {
case DRUPAL_BOOTSTRAP_CONFIGURATION :
_drupal_bootstrap_configuration ();
break ;
case DRUPAL_BOOTSTRAP_PAGE_CACHE :
_drupal_bootstrap_page_cache ();
break ;
case DRUPAL_BOOTSTRAP_DATABASE :
_drupal_bootstrap_database ();
break ;
case DRUPAL_BOOTSTRAP_VARIABLES :
_drupal_bootstrap_variables ();
break ;
case DRUPAL_BOOTSTRAP_SESSION :
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/' . variable_get ( 'session_inc' , 'core/includes/session.inc' );
2009-11-05 03:00:21 +00:00
drupal_session_initialize ();
break ;
case DRUPAL_BOOTSTRAP_PAGE_HEADER :
_drupal_bootstrap_page_header ();
break ;
case DRUPAL_BOOTSTRAP_LANGUAGE :
drupal_language_initialize ();
break ;
case DRUPAL_BOOTSTRAP_FULL :
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/common.inc' ;
2009-11-05 03:00:21 +00:00
_drupal_bootstrap_full ();
break ;
}
2008-10-19 21:27:13 +00:00
}
2005-06-22 20:19:58 +00:00
}
2010-01-14 21:17:56 +00:00
return $stored_phase ;
2005-06-22 20:19:58 +00:00
}
2005-06-07 18:54:37 +00:00
2010-04-11 18:33:44 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns the time zone of the current user .
2010-04-11 18:33:44 +00:00
*/
function drupal_get_user_timezone () {
global $user ;
if ( variable_get ( 'configurable_timezones' , 1 ) && $user -> uid && $user -> timezone ) {
return $user -> timezone ;
}
else {
2011-02-19 16:59:43 +00:00
// Ignore PHP strict notice if time zone has not yet been set in the php.ini
// configuration.
return variable_get ( 'date_default_timezone' , @ date_default_timezone_get ());
2010-04-11 18:33:44 +00:00
}
}
2010-02-15 15:52:27 +00:00
/**
2011-12-05 12:52:27 +00:00
* Provides custom PHP error handling .
2010-02-15 15:52:27 +00:00
*
* @ param $error_level
* The level of the error raised .
* @ param $message
* The error message .
* @ param $filename
* The filename that the error was raised in .
* @ param $line
* The line number the error was raised at .
* @ param $context
2011-12-05 12:52:27 +00:00
* An array that points to the active symbol table at the point the error
* occurred .
2010-02-15 15:52:27 +00:00
*/
function _drupal_error_handler ( $error_level , $message , $filename , $line , $context ) {
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/errors.inc' ;
2010-02-15 15:52:27 +00:00
_drupal_error_handler_real ( $error_level , $message , $filename , $line , $context );
}
/**
2011-12-05 12:52:27 +00:00
* Provides custom PHP exception handling .
2010-02-15 15:52:27 +00:00
*
* Uncaught exceptions are those not enclosed in a try / catch block . They are
* always fatal : the execution of the script will stop as soon as the exception
* handler exits .
*
* @ param $exception
* The exception object that was thrown .
*/
function _drupal_exception_handler ( $exception ) {
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/errors.inc' ;
2010-04-03 03:36:11 +00:00
try {
// Log the message to the watchdog and return an error page to the user.
_drupal_log_error ( _drupal_decode_exception ( $exception ), TRUE );
}
catch ( Exception $exception2 ) {
// Another uncaught exception was thrown while handling the first one.
// If we are displaying errors, then do so with no possibility of a further uncaught exception being thrown.
2010-06-05 13:30:42 +00:00
if ( error_displayable ()) {
print '<h1>Additional uncaught exception thrown while handling exception.</h1>' ;
print '<h2>Original</h2><p>' . _drupal_render_exception_safe ( $exception ) . '</p>' ;
print '<h2>Additional</h2><p>' . _drupal_render_exception_safe ( $exception2 ) . '</p><hr />' ;
2010-04-03 03:36:11 +00:00
}
}
2010-02-15 15:52:27 +00:00
}
2008-08-21 19:36:39 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sets up the script environment and loads settings . php .
2008-08-21 19:36:39 +00:00
*/
2009-11-05 03:00:21 +00:00
function _drupal_bootstrap_configuration () {
2010-02-15 15:52:27 +00:00
// Set the Drupal custom error handler.
set_error_handler ( '_drupal_error_handler' );
set_exception_handler ( '_drupal_exception_handler' );
2009-11-05 03:00:21 +00:00
drupal_environment_initialize ();
// Start a page timer:
timer_start ( 'page' );
// Initialize the configuration, including variables from settings.php.
drupal_settings_initialize ();
2011-10-24 18:14:03 +00:00
2012-01-13 14:14:07 +00:00
// Include and activate the class loader.
$loader = drupal_classloader ();
2011-10-24 18:14:03 +00:00
2012-01-13 14:14:07 +00:00
// Register explicit vendor namespaces.
2011-10-24 18:14:03 +00:00
$loader -> registerNamespaces ( array (
2012-02-01 03:22:12 +00:00
// All Symfony-borrowed code lives in /core/vendor/Symfony.
'Symfony' => DRUPAL_ROOT . '/core/vendor' ,
2012-01-13 14:14:07 +00:00
));
// Register the Drupal namespace for classes in core as a fallback.
// This allows to register additional namespaces within the Drupal namespace
// (e.g., for modules) and avoids an additional file_exists() on the Drupal
// core namespace, since the class loader can already determine the best
// namespace match based on a string comparison. It further allows modules to
// register/overload namespaces in Drupal core.
$loader -> registerNamespaceFallbacks ( array (
2012-02-01 03:22:12 +00:00
// All Drupal-namespaced code in core lives in /core/lib/Drupal.
'Drupal' => DRUPAL_ROOT . '/core/lib' ,
2011-10-24 18:14:03 +00:00
));
2008-08-21 19:36:39 +00:00
}
2009-11-05 03:00:21 +00:00
/**
2011-12-05 12:52:27 +00:00
* Attempts to serve a page from the cache .
2009-11-05 03:00:21 +00:00
*/
function _drupal_bootstrap_page_cache () {
global $user ;
// Allow specifying special cache handlers in settings.php, like
// using memcached or files for storing cache information.
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/cache.inc' ;
2009-12-05 19:27:34 +00:00
foreach ( variable_get ( 'cache_backends' , array ()) as $include ) {
require_once DRUPAL_ROOT . '/' . $include ;
}
2009-11-05 03:00:21 +00:00
// Check for a cache mode force from settings.php.
if ( variable_get ( 'page_cache_without_database' )) {
2010-05-12 08:26:15 +00:00
$cache_enabled = TRUE ;
2009-11-05 03:00:21 +00:00
}
else {
drupal_bootstrap ( DRUPAL_BOOTSTRAP_VARIABLES , FALSE );
2010-05-12 08:26:15 +00:00
$cache_enabled = variable_get ( 'cache' );
2009-11-05 03:00:21 +00:00
}
drupal_block_denied ( ip_address ());
// If there is no session cookie and cache is enabled (or forced), try
// to serve a cached page.
2010-05-12 08:26:15 +00:00
if ( ! isset ( $_COOKIE [ session_name ()]) && $cache_enabled ) {
2010-07-21 00:26:21 +00:00
// Make sure there is a user object because its timestamp will be
2009-11-05 03:00:21 +00:00
// checked, hook_boot might check for anonymous user etc.
$user = drupal_anonymous_user ();
// Get the page from the cache.
$cache = drupal_page_get_cache ();
// If there is a cached page, display it.
if ( is_object ( $cache )) {
2010-05-16 09:39:31 +00:00
header ( 'X-Drupal-Cache: HIT' );
2010-05-18 18:26:30 +00:00
// Restore the metadata cached with the page.
$_GET [ 'q' ] = $cache -> data [ 'path' ];
drupal_set_title ( $cache -> data [ 'title' ], PASS_THROUGH );
2011-02-19 16:59:43 +00:00
date_default_timezone_set ( drupal_get_user_timezone ());
2009-11-05 03:00:21 +00:00
// If the skipping of the bootstrap hooks is not enforced, call
// hook_boot.
if ( variable_get ( 'page_cache_invoke_hooks' , TRUE )) {
bootstrap_invoke_all ( 'boot' );
2009-07-22 04:45:35 +00:00
}
2009-11-05 03:00:21 +00:00
drupal_serve_page_from_cache ( $cache );
// If the skipping of the bootstrap hooks is not enforced, call
// hook_exit.
if ( variable_get ( 'page_cache_invoke_hooks' , TRUE )) {
bootstrap_invoke_all ( 'exit' );
2009-04-22 09:45:03 +00:00
}
2009-11-05 03:00:21 +00:00
// We are done.
exit ;
}
2010-05-16 09:39:31 +00:00
else {
header ( 'X-Drupal-Cache: MISS' );
}
2009-11-05 03:00:21 +00:00
}
}
2009-06-02 06:58:17 +00:00
2009-11-05 03:00:21 +00:00
/**
2011-12-05 12:52:27 +00:00
* Initializes the database system and registers autoload functions .
2009-11-05 03:00:21 +00:00
*/
function _drupal_bootstrap_database () {
2010-04-29 03:48:16 +00:00
// Redirect the user to the installation script if Drupal has not been
// installed yet (i.e., if no $databases array has been defined in the
// settings.php file) and we are not already installing.
if ( empty ( $GLOBALS [ 'databases' ]) && ! drupal_installation_attempted ()) {
2011-10-31 04:05:57 +00:00
include_once DRUPAL_ROOT . '/core/includes/install.inc' ;
install_goto ( 'core/install.php' );
2010-04-29 03:48:16 +00:00
}
2010-06-28 19:57:34 +00:00
// The user agent header is used to pass a database prefix in the request when
// running tests. However, for security reasons, it is imperative that we
// validate we ourselves made the request.
2010-11-05 19:05:02 +00:00
if ( $test_prefix = drupal_valid_test_ua ()) {
2010-06-28 19:57:34 +00:00
// Set the test run id for use in other parts of Drupal.
$test_info = & $GLOBALS [ 'drupal_test_info' ];
$test_info [ 'test_run_id' ] = $test_prefix ;
$test_info [ 'in_child_site' ] = TRUE ;
foreach ( $GLOBALS [ 'databases' ][ 'default' ] as & $value ) {
// Extract the current default database prefix.
if ( ! isset ( $value [ 'prefix' ])) {
$current_prefix = '' ;
}
2010-07-24 17:28:27 +00:00
elseif ( is_array ( $value [ 'prefix' ])) {
2010-06-28 19:57:34 +00:00
$current_prefix = $value [ 'prefix' ][ 'default' ];
}
else {
$current_prefix = $value [ 'prefix' ];
}
// Remove the current database prefix and replace it by our own.
$value [ 'prefix' ] = array (
'default' => $current_prefix . $test_prefix ,
);
}
}
2009-11-05 03:00:21 +00:00
// Initialize the database system. Note that the connection
// won't be initialized until it is actually requested.
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/database/database.inc' ;
2009-11-19 04:00:47 +00:00
2009-11-05 03:00:21 +00:00
// Register autoload functions so that we can access classes and interfaces.
2010-04-11 17:16:45 +00:00
// The database autoload routine comes first so that we can load the database
// system without hitting the database. That is especially important during
// the install or upgrade process.
2009-11-05 03:00:21 +00:00
spl_autoload_register ( 'drupal_autoload_class' );
spl_autoload_register ( 'drupal_autoload_interface' );
}
2009-08-17 20:32:30 +00:00
2009-11-05 03:00:21 +00:00
/**
2011-12-05 12:52:27 +00:00
* Loads system variables and all enabled bootstrap modules .
2009-11-05 03:00:21 +00:00
*/
function _drupal_bootstrap_variables () {
global $conf ;
2010-06-24 18:56:10 +00:00
// Initialize the lock system.
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/' . variable_get ( 'lock_inc' , 'core/includes/lock.inc' );
2010-06-24 18:56:10 +00:00
lock_initialize ();
2009-11-05 03:00:21 +00:00
// Load variables from the database, but do not overwrite variables set in settings.php.
$conf = variable_initialize ( isset ( $conf ) ? $conf : array ());
// Load bootstrap modules.
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/module.inc' ;
2009-11-05 03:00:21 +00:00
module_load_all ( TRUE );
}
/**
2011-12-05 12:52:27 +00:00
* Invokes hook_boot (), initializes locking system , and sends HTTP headers .
2009-11-05 03:00:21 +00:00
*/
function _drupal_bootstrap_page_header () {
bootstrap_invoke_all ( 'boot' );
2005-07-23 05:57:27 +00:00
2009-11-05 03:00:21 +00:00
if ( ! drupal_is_cli ()) {
ob_start ();
drupal_page_header ();
2005-06-22 20:19:58 +00:00
}
2005-06-07 18:54:37 +00:00
}
2009-11-05 03:00:21 +00:00
/**
* Returns the current bootstrap phase for this Drupal process .
*
* The current phase is the one most recently completed by drupal_bootstrap () .
*
* @ see drupal_bootstrap ()
*/
function drupal_get_bootstrap_phase () {
return drupal_bootstrap ();
}
2009-07-22 04:45:35 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns the test prefix if this is an internal request from SimpleTest .
2010-11-05 19:05:02 +00:00
*
* @ return
* Either the simpletest prefix ( the string " simpletest " followed by any
* number of digits ) or FALSE if the user agent does not contain a valid
* HMAC and timestamp .
2009-07-22 04:45:35 +00:00
*/
2010-11-05 19:05:02 +00:00
function drupal_valid_test_ua () {
2010-06-28 19:57:34 +00:00
global $drupal_hash_salt ;
2010-11-05 19:05:02 +00:00
// No reason to reset this.
static $test_prefix ;
if ( isset ( $test_prefix )) {
return $test_prefix ;
}
2009-07-22 04:45:35 +00:00
2010-11-05 19:05:02 +00:00
if ( isset ( $_SERVER [ 'HTTP_USER_AGENT' ]) && preg_match ( " /^(simpletest \ d+);(.+);(.+);(.+) $ / " , $_SERVER [ 'HTTP_USER_AGENT' ], $matches )) {
list (, $prefix , $time , $salt , $hmac ) = $matches ;
$check_string = $prefix . ';' . $time . ';' . $salt ;
// We use the salt from settings.php to make the HMAC key, since
// the database is not yet initialized and we can't access any Drupal variables.
// The file properties add more entropy not easily accessible to others.
$key = $drupal_hash_salt . filectime ( __FILE__ ) . fileinode ( __FILE__ );
$time_diff = REQUEST_TIME - $time ;
// Since we are making a local request a 5 second time window is allowed,
// and the HMAC must match.
if ( $time_diff >= 0 && $time_diff <= 5 && $hmac == drupal_hmac_base64 ( $check_string , $key )) {
$test_prefix = $prefix ;
return $test_prefix ;
}
}
return FALSE ;
2009-07-22 04:45:35 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Generates a user agent string with a HMAC and timestamp for simpletest .
2009-07-22 04:45:35 +00:00
*/
function drupal_generate_test_ua ( $prefix ) {
2010-06-28 19:57:34 +00:00
global $drupal_hash_salt ;
2009-07-22 04:45:35 +00:00
static $key ;
if ( ! isset ( $key )) {
2010-06-28 19:57:34 +00:00
// We use the salt from settings.php to make the HMAC key, since
// the database is not yet initialized and we can't access any Drupal variables.
// The file properties add more entropy not easily accessible to others.
2010-11-05 19:05:02 +00:00
$key = $drupal_hash_salt . filectime ( __FILE__ ) . fileinode ( __FILE__ );
2009-07-22 04:45:35 +00:00
}
2010-11-05 19:05:02 +00:00
// Generate a moderately secure HMAC based on the database credentials.
$salt = uniqid ( '' , TRUE );
$check_string = $prefix . ';' . time () . ';' . $salt ;
return $check_string . ';' . drupal_hmac_base64 ( $check_string , $key );
2009-07-22 04:45:35 +00:00
}
2005-07-27 01:58:43 +00:00
/**
2007-11-30 12:19:10 +00:00
* Enables use of the theme system without requiring database access .
*
* Loads and initializes the theme system for site installs , updates and when
2009-04-19 19:10:08 +00:00
* the site is in maintenance mode . This also applies when the database fails .
2007-11-30 12:19:10 +00:00
*
* @ see _drupal_maintenance_theme ()
2005-07-27 01:58:43 +00:00
*/
function drupal_maintenance_theme () {
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/theme.maintenance.inc' ;
2007-11-30 12:19:10 +00:00
_drupal_maintenance_theme ();
2005-07-27 01:58:43 +00:00
}
2006-09-01 08:44:53 +00:00
2011-09-14 20:24:19 +00:00
/**
* Returns a simple 404 Not Found page .
*
* If fast 404 pages are enabled , and this is a matching page then print a
* simple 404 page and exit .
*
* This function is called from drupal_deliver_html_page () at the time when a
* a normal 404 page is generated , but it can also optionally be called directly
* from settings . php to prevent a Drupal bootstrap on these pages . See
* documentation in settings . php for the benefits and drawbacks of using this .
*
* Paths to dynamically - generated content , such as image styles , should also be
* accounted for in this function .
*/
function drupal_fast_404 () {
$exclude_paths = variable_get ( '404_fast_paths_exclude' , FALSE );
if ( $exclude_paths && ! preg_match ( $exclude_paths , $_GET [ 'q' ])) {
$fast_paths = variable_get ( '404_fast_paths' , FALSE );
if ( $fast_paths && preg_match ( $fast_paths , $_GET [ 'q' ])) {
drupal_add_http_header ( 'Status' , '404 Not Found' );
$fast_404_html = variable_get ( '404_fast_html' , '<html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>' );
// Replace @path in the variable with the page path.
print strtr ( $fast_404_html , array ( '@path' => check_plain ( request_uri ())));
exit ;
}
}
}
2009-07-28 12:13:47 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns TRUE if a Drupal installation is currently being attempted .
2009-07-28 12:13:47 +00:00
*/
function drupal_installation_attempted () {
return defined ( 'MAINTENANCE_MODE' ) && MAINTENANCE_MODE == 'install' ;
}
2006-09-01 08:44:53 +00:00
/**
2011-05-05 03:42:31 +00:00
* Returns the name of the proper localization function .
*
* get_t () exists to support localization for code that might run during
* the installation phase , when some elements of the system might not have
* loaded .
*
* This would include implementations of hook_install (), which could run
* during the Drupal installation phase , and might also be run during
* non - installation time , such as while installing the module from the the
* module administration page .
*
2011-09-24 20:44:06 +00:00
* Example usage :
2011-05-05 03:42:31 +00:00
* @ code
* $t = get_t ();
* $translated = $t ( 'translate this' );
* @ endcode
*
* Use t () if your code will never run during the Drupal installation phase .
* Use st () if your code will only run during installation and never any other
* time . Use get_t () if your code could run in either circumstance .
*
* @ see t ()
* @ see st ()
* @ ingroup sanitization
2006-09-01 08:44:53 +00:00
*/
function get_t () {
static $t ;
2009-04-02 20:39:45 +00:00
// This is not converted to drupal_static because there is no point in
// resetting this as it can not change in the course of a request.
if ( ! isset ( $t )) {
2009-07-28 12:13:47 +00:00
$t = drupal_installation_attempted () ? 'st' : 't' ;
2006-09-01 08:44:53 +00:00
}
return $t ;
}
2007-03-26 01:32:22 +00:00
/**
2011-12-05 12:52:27 +00:00
* Initializes all the defined language types .
2007-03-26 01:32:22 +00:00
*/
2009-07-14 10:22:17 +00:00
function drupal_language_initialize () {
2009-10-09 16:33:14 +00:00
$types = language_types ();
2007-03-26 01:32:22 +00:00
2010-09-11 06:24:55 +00:00
// Ensure the language is correctly returned, even without multilanguage
// support. Also make sure we have a $language fallback, in case a language
// negotiation callback needs to do a full bootstrap.
2007-03-26 01:32:22 +00:00
// Useful for eg. XML/HTML 'lang' attributes.
2010-09-11 06:24:55 +00:00
$default = language_default ();
foreach ( $types as $type ) {
$GLOBALS [ $type ] = $default ;
2007-03-26 01:32:22 +00:00
}
2012-01-03 05:17:30 +00:00
if ( language_multilingual ()) {
2011-10-31 04:05:57 +00:00
include_once DRUPAL_ROOT . '/core/includes/language.inc' ;
2009-10-09 16:33:14 +00:00
foreach ( $types as $type ) {
$GLOBALS [ $type ] = language_initialize ( $type );
}
2009-10-16 19:06:25 +00:00
// Allow modules to react on language system initialization in multilingual
// environments.
2010-04-07 05:15:51 +00:00
bootstrap_invoke_all ( 'language_init' );
2007-03-26 01:32:22 +00:00
}
}
2009-10-09 16:33:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns a list of the built - in language types .
2009-10-09 16:33:14 +00:00
*
* @ return
* An array of key - values pairs where the key is the language type and the
* value is its configurability .
*/
function drupal_language_types () {
return array (
LANGUAGE_TYPE_INTERFACE => TRUE ,
2010-03-07 07:44:18 +00:00
LANGUAGE_TYPE_CONTENT => FALSE ,
2009-10-09 16:33:14 +00:00
LANGUAGE_TYPE_URL => FALSE ,
);
}
2009-10-16 02:04:44 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns TRUE if there is more than one language enabled .
2009-10-16 02:04:44 +00:00
*/
2012-01-03 05:17:30 +00:00
function language_multilingual () {
2011-05-01 10:31:14 +00:00
// The "language_count" variable stores the number of enabled languages to
// avoid unnecessarily querying the database when building the list of
// enabled languages on monolingual sites.
2010-03-07 07:30:40 +00:00
return variable_get ( 'language_count' , 1 ) > 1 ;
2009-10-16 02:04:44 +00:00
}
2009-10-09 16:33:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns an array of the available language types .
2009-10-09 16:33:14 +00:00
*/
function language_types () {
return array_keys ( variable_get ( 'language_types' , drupal_language_types ()));
}
2007-03-26 01:32:22 +00:00
/**
2012-01-23 15:46:29 +00:00
* Returns a list of configured languages .
2007-03-26 01:32:22 +00:00
*
2012-01-23 15:46:29 +00:00
* @ param $only_enabled
* ( optional ) Whether to return only enabled languages .
2011-10-17 16:22:46 +00:00
*
* @ return
2012-01-23 15:46:29 +00:00
* An associative array of languages , keyed by the language code , ordered by
* weight ascending and name ascending .
*/
function language_list ( $only_enabled = FALSE ) {
2009-04-02 20:39:45 +00:00
$languages = & drupal_static ( __FUNCTION__ );
2012-01-23 15:46:29 +00:00
// Initialize master language list.
2007-03-26 01:32:22 +00:00
if ( ! isset ( $languages )) {
2012-01-23 15:46:29 +00:00
// Initialize local language list caches.
$languages = array ( 'all' => array (), 'enabled' => array ());
// Fill in master language list based on current configuration.
2011-09-28 10:47:48 +00:00
$default = language_default ();
2012-01-03 05:17:30 +00:00
if ( language_multilingual () || module_exists ( 'language' )) {
2012-01-23 15:46:29 +00:00
// Use language module configuration if available.
$languages [ 'all' ] = db_query ( 'SELECT * FROM {language} ORDER BY weight ASC, name ASC' ) -> fetchAllAssoc ( 'langcode' );
2007-07-01 19:49:19 +00:00
}
else {
2012-01-23 15:46:29 +00:00
// No language module, so use the default language only.
$languages [ 'all' ][ $default -> langcode ] = $default ;
2007-03-26 01:32:22 +00:00
}
2011-09-28 10:47:48 +00:00
2012-01-23 15:46:29 +00:00
// Initialize default property so callers have an easy reference and can
// save the same object without data loss. Also fill in the filtered list
// of enabled languages only.
foreach ( $languages [ 'all' ] as $langcode => $language ) {
$languages [ 'all' ][ $langcode ] -> default = ( $langcode == $default -> langcode );
if ( $language -> enabled ) {
$languages [ 'enabled' ][ $langcode ] = $languages [ 'all' ][ $langcode ];
2007-03-26 01:32:22 +00:00
}
}
}
2012-01-23 15:46:29 +00:00
return $only_enabled ? $languages [ 'enabled' ] : $languages [ 'all' ];
2007-03-26 01:32:22 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Returns the default language used on the site .
2007-05-30 08:08:59 +00:00
*
2011-09-08 02:00:12 +00:00
* @ return
* A language object .
*/
function language_default () {
2011-11-29 02:23:49 +00:00
$default = variable_get (
2011-09-08 02:00:12 +00:00
'language_default' ,
( object ) array (
2012-01-10 15:29:08 +00:00
'langcode' => 'en' ,
2011-09-08 02:00:12 +00:00
'name' => 'English' ,
'direction' => 0 ,
'enabled' => 1 ,
'weight' => 0 ,
)
);
2011-11-29 02:23:49 +00:00
$default -> default = TRUE ;
return $default ;
2007-03-26 01:32:22 +00:00
}
2007-05-25 15:04:42 +00:00
2010-01-29 22:40:41 +00:00
/**
* Returns the requested URL path of the page being viewed .
*
* Examples :
* - http :// example . com / node / 306 returns " node/306 " .
* - http :// example . com / drupalfolder / node / 306 returns " node/306 " while
* base_path () returns " /drupalfolder/ " .
* - http :// example . com / path / alias ( which is a path alias for node / 306 ) returns
* " path/alias " as opposed to the internal path .
2011-05-01 10:08:46 +00:00
* - http :// example . com / index . php returns an empty string ( meaning : front page ) .
* - http :// example . com / index . php ? page = 1 returns an empty string .
2010-01-29 22:40:41 +00:00
*
* @ return
* The requested Drupal URL path .
*
* @ see current_path ()
*/
function request_path () {
static $path ;
if ( isset ( $path )) {
return $path ;
}
if ( isset ( $_GET [ 'q' ])) {
// This is a request with a ?q=foo/bar query string. $_GET['q'] is
// overwritten in drupal_path_initialize(), but request_path() is called
// very early in the bootstrap process, so the original value is saved in
// $path and returned in later calls.
$path = $_GET [ 'q' ];
}
elseif ( isset ( $_SERVER [ 'REQUEST_URI' ])) {
2011-05-01 10:08:46 +00:00
// This request is either a clean URL, or 'index.php', or nonsense.
// Extract the path from REQUEST_URI.
2010-01-29 22:40:41 +00:00
$request_path = strtok ( $_SERVER [ 'REQUEST_URI' ], '?' );
$base_path_len = strlen ( rtrim ( dirname ( $_SERVER [ 'SCRIPT_NAME' ]), '\/' ));
// Unescape and strip $base_path prefix, leaving q without a leading slash.
$path = substr ( urldecode ( $request_path ), $base_path_len + 1 );
2011-05-01 10:08:46 +00:00
// If the path equals the script filename, either because 'index.php' was
// explicitly provided in the URL, or because the server added it to
// $_SERVER['REQUEST_URI'] even when it wasn't provided in the URL (some
// versions of Microsoft IIS do this), the front page should be served.
if ( $path == basename ( $_SERVER [ 'PHP_SELF' ])) {
$path = '' ;
}
2010-01-29 22:40:41 +00:00
}
else {
// This is the front page.
$path = '' ;
}
2010-03-10 19:36:14 +00:00
// Under certain conditions Apache's RewriteRule directive prepends the value
// assigned to $_GET['q'] with a slash. Moreover we can always have a trailing
// slash in place, hence we need to normalize $_GET['q'].
$path = trim ( $path , '/' );
2010-01-29 22:40:41 +00:00
return $path ;
}
2010-05-18 18:26:30 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns a component of the current Drupal path .
2010-05-18 18:26:30 +00:00
*
* When viewing a page at the path " admin/structure/types " , for example , arg ( 0 )
* returns " admin " , arg ( 1 ) returns " structure " , and arg ( 2 ) returns " types " .
*
2011-12-05 12:52:27 +00:00
* Avoid use of this function where possible , as resulting code is hard to
* read . In menu callback functions , attempt to use named arguments . See the
* explanation in menu . inc for how to construct callbacks that take arguments .
* When attempting to use this function to load an element from the current
* path , e . g . loading the node on a node page , use menu_get_object () instead .
2010-05-18 18:26:30 +00:00
*
* @ param $index
* The index of the component , where each component is separated by a '/'
* ( forward - slash ), and where the first component has an index of 0 ( zero ) .
* @ param $path
* A path to break into components . Defaults to the path of the current page .
*
* @ return
* The component specified by $index , or NULL if the specified component was
2010-10-23 12:56:40 +00:00
* not found . If called without arguments , it returns an array containing all
* the components of the current path .
2010-05-18 18:26:30 +00:00
*/
function arg ( $index = NULL , $path = NULL ) {
// Even though $arguments doesn't need to be resettable for any functional
// reasons (the result of explode() does not depend on any run-time
// information), it should be resettable anyway in case a module needs to
// free up the memory used by it.
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static_fast ;
if ( ! isset ( $drupal_static_fast )) {
$drupal_static_fast [ 'arguments' ] = & drupal_static ( __FUNCTION__ );
}
$arguments = & $drupal_static_fast [ 'arguments' ];
if ( ! isset ( $path )) {
$path = $_GET [ 'q' ];
}
if ( ! isset ( $arguments [ $path ])) {
$arguments [ $path ] = explode ( '/' , $path );
}
if ( ! isset ( $index )) {
return $arguments [ $path ];
}
if ( isset ( $arguments [ $path ][ $index ])) {
return $arguments [ $path ][ $index ];
}
}
2007-05-25 15:04:42 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns the IP address of the client machine .
*
2007-05-25 15:04:42 +00:00
* If Drupal is behind a reverse proxy , we use the X - Forwarded - For header
2008-07-02 20:05:11 +00:00
* instead of $_SERVER [ 'REMOTE_ADDR' ], which would be the IP address of
2010-03-17 13:58:45 +00:00
* the proxy server , and not the client ' s . The actual header name can be
* configured by the reverse_proxy_header variable .
2007-05-25 15:04:42 +00:00
*
* @ return
2008-06-26 11:29:20 +00:00
* IP address of client machine , adjusted for reverse proxy and / or cluster
* environments .
2007-05-25 15:04:42 +00:00
*/
2009-04-02 20:39:45 +00:00
function ip_address () {
$ip_address = & drupal_static ( __FUNCTION__ );
2007-05-25 15:04:42 +00:00
2009-04-02 20:39:45 +00:00
if ( ! isset ( $ip_address )) {
2007-07-29 21:04:03 +00:00
$ip_address = $_SERVER [ 'REMOTE_ADDR' ];
2008-07-08 01:08:15 +00:00
2008-07-04 22:54:09 +00:00
if ( variable_get ( 'reverse_proxy' , 0 )) {
2010-03-17 13:58:45 +00:00
$reverse_proxy_header = variable_get ( 'reverse_proxy_header' , 'HTTP_X_FORWARDED_FOR' );
if ( ! empty ( $_SERVER [ $reverse_proxy_header ])) {
2008-07-04 22:54:09 +00:00
// If an array of known reverse proxy IPs is provided, then trust
// the XFF header if request really comes from one of them.
$reverse_proxy_addresses = variable_get ( 'reverse_proxy_addresses' , array ());
2010-06-14 13:24:32 +00:00
// Turn XFF header into an array.
$forwarded = explode ( ',' , $_SERVER [ $reverse_proxy_header ]);
// Trim the forwarded IPs; they may have been delimited by commas and spaces.
$forwarded = array_map ( 'trim' , $forwarded );
// Tack direct client IP onto end of forwarded array.
$forwarded [] = $ip_address ;
// Eliminate all trusted IPs.
$untrusted = array_diff ( $forwarded , $reverse_proxy_addresses );
// The right-most IP is the most specific we can trust.
$ip_address = array_pop ( $untrusted );
2007-11-26 08:06:52 +00:00
}
2008-06-26 11:29:20 +00:00
}
2007-05-25 15:04:42 +00:00
}
2007-07-29 17:28:23 +00:00
2007-07-29 21:04:03 +00:00
return $ip_address ;
2007-05-25 15:04:42 +00:00
}
2008-05-06 12:18:54 +00:00
2008-08-21 19:36:39 +00:00
/**
* @ ingroup schemaapi
* @ {
*/
/**
2011-12-05 12:52:27 +00:00
* Gets the schema definition of a table , or the whole database schema .
2008-08-21 19:36:39 +00:00
*
* The returned schema will include any modifications made by any
* module that implements hook_schema_alter () .
*
* @ param $table
* The name of the table . If not given , the schema of all tables is returned .
* @ param $rebuild
* If true , the schema will be rebuilt instead of retrieved from the cache .
*/
function drupal_get_schema ( $table = NULL , $rebuild = FALSE ) {
2011-08-27 09:14:34 +00:00
static $schema ;
if ( $rebuild || ! isset ( $table )) {
$schema = drupal_get_complete_schema ( $rebuild );
}
elseif ( ! isset ( $schema )) {
$schema = new SchemaCache ();
}
if ( ! isset ( $table )) {
return $schema ;
}
if ( isset ( $schema [ $table ])) {
return $schema [ $table ];
}
else {
return FALSE ;
}
}
/**
* Extends DrupalCacheArray to allow for dynamic building of the schema cache .
*/
class SchemaCache extends DrupalCacheArray {
2011-12-05 12:52:27 +00:00
/**
* Constructs a SchemaCache object .
*/
2011-08-27 09:14:34 +00:00
public function __construct () {
// Cache by request method.
2011-09-24 19:13:04 +00:00
parent :: __construct ( 'schema:runtime:' . ( $_SERVER [ 'REQUEST_METHOD' ] == 'GET' ), 'cache' );
2011-08-27 09:14:34 +00:00
}
2011-12-05 12:52:27 +00:00
/**
* Overrides DrupalCacheArray :: resolveCacheMiss () .
*/
2011-08-27 09:14:34 +00:00
protected function resolveCacheMiss ( $offset ) {
$complete_schema = drupal_get_complete_schema ();
$value = isset ( $complete_schema [ $offset ]) ? $complete_schema [ $offset ] : NULL ;
$this -> storage [ $offset ] = $value ;
$this -> persist ( $offset );
return $value ;
}
}
/**
2011-12-05 12:52:27 +00:00
* Gets the whole database schema .
2011-08-27 09:14:34 +00:00
*
* The returned schema will include any modifications made by any
* module that implements hook_schema_alter () .
*
* @ param $rebuild
* If true , the schema will be rebuilt instead of retrieved from the cache .
*/
function drupal_get_complete_schema ( $rebuild = FALSE ) {
2008-08-21 19:36:39 +00:00
static $schema = array ();
if ( empty ( $schema ) || $rebuild ) {
// Try to load the schema from cache.
2011-09-07 18:38:31 +00:00
if ( ! $rebuild && $cached = cache () -> get ( 'schema' )) {
2008-08-21 19:36:39 +00:00
$schema = $cached -> data ;
}
// Otherwise, rebuild the schema cache.
else {
$schema = array ();
// Load the .install files to get hook_schema.
// On some databases this function may be called before bootstrap has
// been completed, so we force the functions we need to load just in case.
2009-08-24 00:14:23 +00:00
if ( function_exists ( 'module_load_all_includes' )) {
2010-11-20 05:45:48 +00:00
// This function can be called very early in the bootstrap process, so
// we force the module_list() cache to be refreshed to ensure that it
// contains the complete list of modules before we go on to call
// module_load_all_includes().
module_list ( TRUE );
2008-08-21 19:36:39 +00:00
module_load_all_includes ( 'install' );
}
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/common.inc' ;
2008-08-21 19:36:39 +00:00
// Invoke hook_schema for all modules.
foreach ( module_implements ( 'schema' ) as $module ) {
2009-11-01 23:10:14 +00:00
// Cast the result of hook_schema() to an array, as a NULL return value
// would cause array_merge() to set the $schema variable to NULL as well.
// That would break modules which use $schema further down the line.
$current = ( array ) module_invoke ( $module , 'schema' );
2010-09-25 02:00:06 +00:00
// Set 'module' and 'name' keys for each table, and remove descriptions,
2011-09-07 18:38:31 +00:00
// as they needlessly slow down cache()->get() for every single request.
2010-09-25 02:00:06 +00:00
_drupal_schema_initialize ( $current , $module );
2008-08-21 19:36:39 +00:00
$schema = array_merge ( $schema , $current );
}
2009-08-24 00:14:23 +00:00
drupal_alter ( 'schema' , $schema );
2008-11-30 01:05:16 +00:00
// If the schema is empty, avoid saving it: some database engines require
// the schema to perform queries, and this could lead to infinite loops.
if ( ! empty ( $schema ) && ( drupal_get_bootstrap_phase () == DRUPAL_BOOTSTRAP_FULL )) {
2011-09-07 18:38:31 +00:00
cache () -> set ( 'schema' , $schema );
2008-08-21 19:36:39 +00:00
}
2011-08-27 09:14:34 +00:00
if ( $rebuild ) {
2011-09-07 18:38:31 +00:00
cache () -> deletePrefix ( 'schema:' );
2011-08-27 09:14:34 +00:00
}
2008-08-21 19:36:39 +00:00
}
}
2011-08-27 09:14:34 +00:00
return $schema ;
2008-08-21 19:36:39 +00:00
}
/**
* @ } End of " ingroup schemaapi " .
*/
2008-05-06 12:18:54 +00:00
/**
* @ ingroup registry
* @ {
*/
2012-01-13 14:14:07 +00:00
/**
* Initializes and returns the class loader .
*
* The class loader is responsible for lazy - loading all PSR - 0 compatible
* classes , interfaces , and traits ( PHP 5.4 and later ) . Its only dependencies
* are DRUPAL_ROOT and variable_get () . Otherwise it may be called as early as
* possible .
*
* @ return Symfony\Component\ClassLoader\UniversalClassLoader
* A UniversalClassLoader class instance ( or extension thereof ) .
*/
function drupal_classloader () {
// Include the Symfony ClassLoader for loading PSR-0-compatible classes.
2012-02-01 03:22:12 +00:00
require_once DRUPAL_ROOT . '/core/vendor/Symfony/Component/ClassLoader/UniversalClassLoader.php' ;
2012-01-13 14:14:07 +00:00
// By default, use the UniversalClassLoader which is best for development,
// as it does not break when code is moved on the file system. However, as it
// is slow, allow to use the APC class loader in production.
static $loader ;
if ( ! isset ( $loader )) {
// @todo Use a cleaner way than variable_get() to switch autoloaders.
switch ( variable_get ( 'autoloader_mode' , 'default' )) {
case 'apc' :
if ( function_exists ( 'apc_store' )) {
2012-02-01 03:22:12 +00:00
require_once DRUPAL_ROOT . '/core/vendor/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php' ;
2012-01-13 14:14:07 +00:00
$loader = new ApcUniversalClassLoader ( 'drupal.' . $GLOBALS [ 'drupal_hash_salt' ]);
break ;
}
// Fall through to the default loader if APC was not loaded, so that the
// site does not fail completely.
case 'dev' :
case 'default' :
default :
$loader = new UniversalClassLoader ();
break ;
}
$loader -> register ();
}
return $loader ;
}
2008-05-06 12:18:54 +00:00
/**
2011-12-05 12:52:27 +00:00
* Confirms that an interface is available .
2008-05-06 12:18:54 +00:00
*
2009-08-24 00:14:23 +00:00
* This function is rarely called directly . Instead , it is registered as an
* spl_autoload () handler , and PHP calls it for us when necessary .
2008-05-06 12:18:54 +00:00
*
* @ param $interface
* The name of the interface to check or load .
2011-12-05 12:52:27 +00:00
*
2008-05-06 12:18:54 +00:00
* @ return
* TRUE if the interface is currently available , FALSE otherwise .
*/
function drupal_autoload_interface ( $interface ) {
return _registry_check_code ( 'interface' , $interface );
}
/**
2011-12-05 12:52:27 +00:00
* Confirms that a class is available .
2008-05-06 12:18:54 +00:00
*
2009-08-24 00:14:23 +00:00
* This function is rarely called directly . Instead , it is registered as an
* spl_autoload () handler , and PHP calls it for us when necessary .
2008-05-06 12:18:54 +00:00
*
* @ param $class
* The name of the class to check or load .
2011-12-05 12:52:27 +00:00
*
2008-05-06 12:18:54 +00:00
* @ return
* TRUE if the class is currently available , FALSE otherwise .
*/
function drupal_autoload_class ( $class ) {
return _registry_check_code ( 'class' , $class );
}
/**
2011-12-05 12:52:27 +00:00
* Checks for a resource in the registry .
2008-11-11 22:39:59 +00:00
*
* @ param $type
2008-11-16 19:41:14 +00:00
* The type of resource we are looking up , or one of the constants
2008-11-11 22:39:59 +00:00
* REGISTRY_RESET_LOOKUP_CACHE or REGISTRY_WRITE_LOOKUP_CACHE , which
* signal that we should reset or write the cache , respectively .
* @ param $name
* The name of the resource , or NULL if either of the REGISTRY_ * constants
* is passed in .
2011-12-05 12:52:27 +00:00
*
2008-11-11 22:39:59 +00:00
* @ return
* TRUE if the resource was found , FALSE if not .
* NULL if either of the REGISTRY_ * constants is passed in as $type .
2008-05-06 12:18:54 +00:00
*/
2008-11-11 22:39:59 +00:00
function _registry_check_code ( $type , $name = NULL ) {
static $lookup_cache , $cache_update_needed ;
2010-04-11 21:05:13 +00:00
2009-10-26 13:00:54 +00:00
if ( $type == 'class' && class_exists ( $name ) || $type == 'interface' && interface_exists ( $name )) {
return TRUE ;
}
2008-11-11 22:39:59 +00:00
if ( ! isset ( $lookup_cache )) {
2008-11-29 23:21:22 +00:00
$lookup_cache = array ();
2011-09-07 18:38:31 +00:00
if ( $cache = cache ( 'bootstrap' ) -> get ( 'lookup_cache' )) {
2008-11-29 23:21:22 +00:00
$lookup_cache = $cache -> data ;
}
2008-11-11 22:39:59 +00:00
}
2008-11-16 19:41:14 +00:00
2008-11-11 22:39:59 +00:00
// When we rebuild the registry, we need to reset this cache so
// we don't keep lookups for resources that changed during the rebuild.
if ( $type == REGISTRY_RESET_LOOKUP_CACHE ) {
$cache_update_needed = TRUE ;
$lookup_cache = NULL ;
return ;
}
// Called from drupal_page_footer, we write to permanent storage if there
// changes to the lookup cache for this request.
if ( $type == REGISTRY_WRITE_LOOKUP_CACHE ) {
if ( $cache_update_needed ) {
2011-09-07 18:38:31 +00:00
cache ( 'bootstrap' ) -> set ( 'lookup_cache' , $lookup_cache );
2008-11-11 22:39:59 +00:00
}
return ;
}
2008-11-16 19:41:14 +00:00
2009-10-22 01:15:15 +00:00
// $type is either 'interface' or 'class', so we only need the first letter to
// keep the cache key unique.
2008-11-11 22:39:59 +00:00
$cache_key = $type [ 0 ] . $name ;
if ( isset ( $lookup_cache [ $cache_key ])) {
if ( $lookup_cache [ $cache_key ]) {
2010-06-28 02:28:42 +00:00
require_once DRUPAL_ROOT . '/' . $lookup_cache [ $cache_key ];
2008-11-11 22:39:59 +00:00
}
2010-05-06 05:59:31 +00:00
return ( bool ) $lookup_cache [ $cache_key ];
2008-11-11 22:39:59 +00:00
}
2008-11-16 19:41:14 +00:00
2008-11-02 06:33:56 +00:00
// This function may get called when the default database is not active, but
// there is no reason we'd ever want to not use the default database for
// this query.
2009-01-25 12:19:32 +00:00
$file = Database :: getConnection ( 'default' , 'default' ) -> query ( " SELECT filename FROM { registry} WHERE name = :name AND type = :type " , array (
2008-10-06 14:26:54 +00:00
':name' => $name ,
':type' => $type ,
))
-> fetchField ();
2008-11-11 22:39:59 +00:00
// Flag that we've run a lookup query and need to update the cache.
$cache_update_needed = TRUE ;
// Misses are valuable information worth caching, so cache even if
// $file is FALSE.
$lookup_cache [ $cache_key ] = $file ;
2008-05-06 12:18:54 +00:00
if ( $file ) {
2010-06-28 02:28:42 +00:00
require_once DRUPAL_ROOT . '/' . $file ;
2008-05-06 12:18:54 +00:00
return TRUE ;
}
2008-11-11 22:39:59 +00:00
else {
return FALSE ;
2008-05-06 12:18:54 +00:00
}
}
/**
2011-12-05 12:52:27 +00:00
* Rescans all enabled modules and rebuilds the registry .
2008-05-06 12:18:54 +00:00
*
2009-08-24 00:14:23 +00:00
* Rescans all code in modules or includes directories , storing the location of
* each interface or class in the database .
2008-05-06 12:18:54 +00:00
*/
2008-08-02 19:01:02 +00:00
function registry_rebuild () {
2009-12-28 10:48:51 +00:00
system_rebuild_module_data ();
registry_update ();
}
/**
2011-12-05 12:52:27 +00:00
* Updates the registry based on the latest files listed in the database .
2009-12-28 10:48:51 +00:00
*
* This function should be used when system_rebuild_module_data () does not need
* to be called , because it is already known that the list of files in the
* { system } table matches those in the file system .
*
* @ see registry_rebuild ()
*/
function registry_update () {
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/registry.inc' ;
2009-12-28 10:48:51 +00:00
_registry_update ();
2008-05-06 12:18:54 +00:00
}
/**
* @ } End of " ingroup registry " .
*/
2009-04-02 20:39:45 +00:00
/**
2011-12-05 12:52:27 +00:00
* Provides central static variable storage .
2009-04-02 20:39:45 +00:00
*
2009-11-20 06:12:45 +00:00
* All functions requiring a static variable to persist or cache data within
* a single page request are encouraged to use this function unless it is
* absolutely certain that the static variable will not need to be reset during
* the page request . By centralizing static variable storage through this
* function , other functions can rely on a consistent API for resetting any
* other function ' s static variables .
*
* Example :
* @ code
2012-01-23 15:46:29 +00:00
* function example_list ( $field = 'default' ) {
* $examples = & drupal_static ( __FUNCTION__ );
* if ( ! isset ( $examples )) {
2009-11-20 06:12:45 +00:00
* // If this function is being called for the first time after a reset,
* // query the database and execute any other code needed to retrieve
2012-01-23 15:46:29 +00:00
* // information.
2009-11-20 06:12:45 +00:00
* ...
* }
2012-01-23 15:46:29 +00:00
* if ( ! isset ( $examples [ $field ])) {
2009-11-20 06:12:45 +00:00
* // If this function is being called for the first time for a particular
* // index field, then execute code needed to index the information already
2012-01-23 15:46:29 +00:00
* // available in $examples by the desired field.
2009-11-20 06:12:45 +00:00
* ...
* }
* // Subsequent invocations of this function for a particular index field
* // skip the above two code blocks and quickly return the already indexed
* // information.
2012-01-23 15:46:29 +00:00
* return $examples [ $field ];
2009-11-20 06:12:45 +00:00
* }
2012-01-23 15:46:29 +00:00
* function examples_admin_overview () {
* // When building the content for the overview page, make sure to get
* // completely fresh information.
* drupal_static_reset ( 'example_list' );
2009-11-20 06:12:45 +00:00
* ...
* }
* @ endcode
*
* In a few cases , a function can have certainty that there is no legitimate
* use - case for resetting that function ' s static variable . This is rare ,
* because when writing a function , it ' s hard to forecast all the situations in
* which it will be used . A guideline is that if a function ' s static variable
* does not depend on any information outside of the function that might change
* during a single page request , then it ' s ok to use the " static " keyword
* instead of the drupal_static () function .
*
* Example :
* @ code
* function actions_do ( ... ) {
* // $stack tracks the number of recursive calls.
* static $stack ;
* $stack ++ ;
* if ( $stack > variable_get ( 'actions_max_stack' , 35 )) {
* ...
* return ;
* }
* ...
* $stack -- ;
* }
* @ endcode
*
* In a few cases , a function needs a resettable static variable , but the
* function is called many times ( 100 + ) during a single page request , so
* every microsecond of execution time that can be removed from the function
* counts . These functions can use a more cumbersome , but faster variant of
2010-01-07 04:54:18 +00:00
* calling drupal_static () . It works by storing the reference returned by
* drupal_static () in the calling function ' s own static variable , thereby
* removing the need to call drupal_static () for each iteration of the function .
* Conceptually , it replaces :
* @ code
* $foo = & drupal_static ( __FUNCTION__ );
* @ endcode
* with :
* @ code
* // Unfortunately, this does not work.
* static $foo = & drupal_static ( __FUNCTION__ );
* @ endcode
* However , the above line of code does not work , because PHP only allows static
* variables to be initializied by literal values , and does not allow static
* variables to be assigned to references .
* - http :// php . net / manual / en / language . variables . scope . php #language.variables.scope.static
* - http :// php . net / manual / en / language . variables . scope . php #language.variables.scope.references
* The example below shows the syntax needed to work around both limitations .
2010-03-26 17:14:46 +00:00
* For benchmarks and more information , see http :// drupal . org / node / 619666.
2009-11-20 06:12:45 +00:00
*
* Example :
* @ code
* function user_access ( $string , $account = NULL ) {
* // Use the advanced drupal_static() pattern, since this is called very often.
2010-01-07 04:54:18 +00:00
* static $drupal_static_fast ;
* if ( ! isset ( $drupal_static_fast )) {
* $drupal_static_fast [ 'perm' ] = & drupal_static ( __FUNCTION__ );
* }
* $perm = & $drupal_static_fast [ 'perm' ];
2009-11-20 06:12:45 +00:00
* ...
* }
* @ endcode
*
2009-04-02 20:39:45 +00:00
* @ param $name
* Globally unique name for the variable . For a function with only one static ,
* variable , the function name ( e . g . via the PHP magic __FUNCTION__ constant )
2009-05-24 17:39:35 +00:00
* is recommended . For a function with multiple static variables add a
2009-04-02 20:39:45 +00:00
* distinguishing suffix to the function name for each one .
* @ param $default_value
* Optional default value .
* @ param $reset
* TRUE to reset a specific named variable , or all variables if $name is NULL .
* Resetting every variable should only be used , for example , for running
* unit tests with a clean environment . Should be used only though via
2009-11-08 20:36:12 +00:00
* function drupal_static_reset () and the return value should not be used in
* this case .
2009-04-02 20:39:45 +00:00
*
* @ return
2009-11-08 20:36:12 +00:00
* Returns a variable by reference .
2009-11-20 06:12:45 +00:00
*
* @ see drupal_static_reset ()
2009-04-02 20:39:45 +00:00
*/
function & drupal_static ( $name , $default_value = NULL , $reset = FALSE ) {
2009-11-08 20:36:12 +00:00
static $data = array (), $default = array ();
2010-07-18 01:22:53 +00:00
// First check if dealing with a previously defined static variable.
if ( isset ( $data [ $name ]) || array_key_exists ( $name , $data )) {
// Non-NULL $name and both $data[$name] and $default[$name] statics exist.
if ( $reset ) {
// Reset pre-existing static variable to its default value.
2009-11-08 20:36:12 +00:00
$data [ $name ] = $default [ $name ];
2009-04-02 20:39:45 +00:00
}
2010-07-18 01:22:53 +00:00
return $data [ $name ];
}
// Neither $data[$name] nor $default[$name] static variables exist.
if ( isset ( $name )) {
if ( $reset ) {
2009-11-08 20:36:12 +00:00
// Reset was called before a default is set and yet a variable must be
// returned.
return $data ;
2009-04-02 20:39:45 +00:00
}
2010-07-18 01:22:53 +00:00
// First call with new non-NULL $name. Initialize a new static variable.
2009-11-08 20:36:12 +00:00
$default [ $name ] = $data [ $name ] = $default_value ;
2010-07-18 01:22:53 +00:00
return $data [ $name ];
}
// Reset all: ($name == NULL). This needs to be done one at a time so that
// references returned by earlier invocations of drupal_static() also get
// reset.
foreach ( $default as $name => $value ) {
$data [ $name ] = $value ;
2009-04-02 20:39:45 +00:00
}
2010-07-18 01:22:53 +00:00
// As the function returns a reference, the return should always be a
// variable.
return $data ;
2009-04-02 20:39:45 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Resets one or all centrally stored static variable ( s ) .
2009-04-02 20:39:45 +00:00
*
* @ param $name
* Name of the static variable to reset . Omit to reset all variables .
*/
function drupal_static_reset ( $name = NULL ) {
drupal_static ( $name , NULL , TRUE );
}
2009-09-19 10:38:47 +00:00
/**
2011-12-05 12:52:27 +00:00
* Detects whether the current script is running in a command - line environment .
2009-09-19 10:38:47 +00:00
*/
function drupal_is_cli () {
return ( ! isset ( $_SERVER [ 'SERVER_SOFTWARE' ]) && ( php_sapi_name () == 'cli' || ( is_numeric ( $_SERVER [ 'argc' ]) && $_SERVER [ 'argc' ] > 0 )));
}
2009-12-22 14:47:14 +00:00
/**
* Formats text for emphasized display in a placeholder inside a sentence .
2011-12-05 12:52:27 +00:00
*
* Used automatically by format_string () .
2009-12-22 14:47:14 +00:00
*
2010-08-17 13:50:52 +00:00
* @ param $text
* The text to format ( plain - text ) .
2009-12-22 14:47:14 +00:00
*
* @ return
* The formatted text ( html ) .
*/
2010-08-17 13:50:52 +00:00
function drupal_placeholder ( $text ) {
return '<em class="placeholder">' . check_plain ( $text ) . '</em>' ;
2009-12-22 14:47:14 +00:00
}
2010-02-17 22:44:52 +00:00
/**
2011-12-05 12:52:27 +00:00
* Registers a function for execution on shutdown .
2010-02-17 22:44:52 +00:00
*
2010-08-22 14:11:47 +00:00
* Wrapper for register_shutdown_function () that catches thrown exceptions to
* avoid " Exception thrown without a stack frame in Unknown " .
2010-02-17 22:44:52 +00:00
*
* @ param $callback
* The shutdown function to register .
2010-08-22 14:11:47 +00:00
* @ param ...
* Additional arguments to pass to the shutdown function .
*
2010-02-17 22:44:52 +00:00
* @ return
* Array of shutdown functions to be executed .
*
* @ see register_shutdown_function ()
2010-06-11 11:00:18 +00:00
* @ ingroup php_wrappers
2010-02-17 22:44:52 +00:00
*/
2010-08-22 14:11:47 +00:00
function & drupal_register_shutdown_function ( $callback = NULL ) {
// We cannot use drupal_static() here because the static cache is reset during
// batch processing, which breaks batch handling.
2010-02-17 22:44:52 +00:00
static $callbacks = array ();
if ( isset ( $callback )) {
// Only register the internal shutdown function once.
if ( empty ( $callbacks )) {
register_shutdown_function ( '_drupal_shutdown_function' );
}
$args = func_get_args ();
array_shift ( $args );
// Save callback and arguments
2011-01-01 22:46:02 +00:00
$callbacks [] = array ( 'callback' => $callback , 'arguments' => $args );
2010-02-17 22:44:52 +00:00
}
return $callbacks ;
}
/**
2011-12-05 12:52:27 +00:00
* Executes registered shutdown functions .
2010-02-17 22:44:52 +00:00
*/
function _drupal_shutdown_function () {
$callbacks = & drupal_register_shutdown_function ();
2011-01-01 22:46:02 +00:00
// Set the CWD to DRUPAL_ROOT as it is not guaranteed to be the same as it
// was in the normal context of execution.
chdir ( DRUPAL_ROOT );
2010-02-17 22:44:52 +00:00
try {
while ( list ( $key , $callback ) = each ( $callbacks )) {
call_user_func_array ( $callback [ 'callback' ], $callback [ 'arguments' ]);
}
}
2010-04-03 03:36:11 +00:00
catch ( Exception $exception ) {
// If we are displaying errors, then do so with no possibility of a further uncaught exception being thrown.
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/errors.inc' ;
2010-06-05 13:30:42 +00:00
if ( error_displayable ()) {
print '<h1>Uncaught exception thrown in shutdown function.</h1>' ;
print '<p>' . _drupal_render_exception_safe ( $exception ) . '</p><hr />' ;
2010-04-03 03:36:11 +00:00
}
2010-02-17 22:44:52 +00:00
}
}