2001-12-01 15:20:48 +00:00
< ? php
2005-08-11 12:57:41 +00:00
// $Id$
2001-12-01 15:20:48 +00:00
2004-07-13 07:21:14 +00:00
/**
* @ file
* Common functions that many Drupal modules will need to reference .
*
* The functions that are critical and need to be available even when serving
* a cached page are instead located in bootstrap . inc .
*/
2005-05-07 01:48:06 +00:00
/**
* Return status for saving which involved creating a new item .
*/
define ( 'SAVED_NEW' , 1 );
/**
* Return status for saving which involved an update to an existing item .
*/
define ( 'SAVED_UPDATED' , 2 );
/**
* Return status for saving which deleted an existing item .
*/
define ( 'SAVED_DELETED' , 3 );
2005-08-16 18:06:18 +00:00
/**
* Set content for a specified region .
*
* @ param $region
* Page region the content is assigned to .
*
* @ param $data
* Content to be set .
*/
function drupal_set_content ( $region = null , $data = null ) {
static $content = array ();
if ( ! is_null ( $region ) && ! is_null ( $data )) {
$content [ $region ][] = $data ;
}
return $content ;
}
/**
* Get assigned content .
*
* @ param $region
* A specified region to fetch content for . If null , all regions will be returned .
*
* @ param $delimiter
* Content to be inserted between exploded array elements .
*/
2005-10-23 09:47:53 +00:00
function drupal_get_content ( $region = NULL , $delimiter = ' ' ) {
2005-08-16 18:06:18 +00:00
$content = drupal_set_content ();
2005-10-23 09:47:53 +00:00
if ( isset ( $region )) {
if ( isset ( $content [ $region ]) && is_array ( $content [ $region ])) {
2005-12-17 10:35:59 +00:00
return implode ( $delimiter , $content [ $region ]);
2005-10-23 09:47:53 +00:00
}
2005-08-16 18:06:18 +00:00
}
else {
foreach ( array_keys ( $content ) as $region ) {
if ( is_array ( $content [ $region ])) {
2005-12-17 10:35:59 +00:00
$content [ $region ] = implode ( $delimiter , $content [ $region ]);
2005-08-16 18:06:18 +00:00
}
}
return $content ;
}
}
2003-11-23 10:41:04 +00:00
/**
2004-09-09 05:51:08 +00:00
* Set the breadcrumb trail for the current page .
2003-12-08 06:32:19 +00:00
*
2004-09-09 05:51:08 +00:00
* @ param $breadcrumb
* Array of links , starting with " home " and proceeding up to but not including
* the current page .
2004-01-06 19:52:14 +00:00
*/
2003-11-23 10:41:04 +00:00
function drupal_set_breadcrumb ( $breadcrumb = NULL ) {
static $stored_breadcrumb ;
2005-10-22 15:14:46 +00:00
if ( ! is_null ( $breadcrumb )) {
2003-11-23 10:41:04 +00:00
$stored_breadcrumb = $breadcrumb ;
}
return $stored_breadcrumb ;
}
2004-09-09 05:51:08 +00:00
/**
* Get the breadcrumb trail for the current page .
*/
2003-11-23 10:41:04 +00:00
function drupal_get_breadcrumb () {
$breadcrumb = drupal_set_breadcrumb ();
2005-10-22 15:14:46 +00:00
if ( is_null ( $breadcrumb )) {
2003-11-23 10:41:04 +00:00
$breadcrumb = menu_get_active_breadcrumb ();
}
return $breadcrumb ;
}
2004-01-14 22:30:09 +00:00
/**
2004-09-09 05:51:08 +00:00
* Add output to the head tag of the HTML page .
2004-11-15 10:47:18 +00:00
* This function can be called as long the headers aren ' t sent .
2004-01-14 22:30:09 +00:00
*/
function drupal_set_html_head ( $data = NULL ) {
2004-04-12 08:27:57 +00:00
static $stored_head = '' ;
2004-01-14 22:30:09 +00:00
if ( ! is_null ( $data )) {
2004-07-13 07:21:14 +00:00
$stored_head .= $data . " \n " ;
2004-01-14 22:30:09 +00:00
}
return $stored_head ;
}
2004-09-09 05:51:08 +00:00
/**
* Retrieve output to be displayed in the head tag of the HTML page .
*/
2004-01-14 22:30:09 +00:00
function drupal_get_html_head () {
2004-01-29 06:47:19 +00:00
$output = " <meta http-equiv= \" Content-Type \" content= \" text/html; charset=utf-8 \" /> \n " ;
2006-02-02 12:44:57 +00:00
$output .= theme ( 'stylesheet_import' , base_path () . 'misc/drupal.css' );
2004-01-14 22:30:09 +00:00
return $output . drupal_set_html_head ();
}
2004-09-09 05:51:08 +00:00
/**
2005-05-14 09:23:47 +00:00
* Reset the static variable which holds the aliases mapped for this request .
2004-09-09 05:51:08 +00:00
*/
2005-05-14 09:23:47 +00:00
function drupal_clear_path_cache () {
drupal_lookup_path ( 'wipe' );
2003-10-03 14:10:05 +00:00
}
2004-01-06 19:52:14 +00:00
2004-01-14 22:30:09 +00:00
/**
2004-09-09 05:51:08 +00:00
* Set an HTTP response header for the current page .
2004-01-14 22:30:09 +00:00
*/
function drupal_set_header ( $header = NULL ) {
2004-07-29 01:41:33 +00:00
// We use an array to guarantee there are no leading or trailing delimiters.
2004-09-09 05:51:08 +00:00
// Otherwise, header('') could get called when serving the page later, which
2004-07-29 01:41:33 +00:00
// ends HTTP headers prematurely on some PHP versions.
static $stored_headers = array ();
2004-01-14 22:30:09 +00:00
2004-07-29 01:41:33 +00:00
if ( strlen ( $header )) {
2004-01-14 22:30:09 +00:00
header ( $header );
2004-07-29 01:41:33 +00:00
$stored_headers [] = $header ;
2004-01-14 22:30:09 +00:00
}
2004-07-29 01:41:33 +00:00
return implode ( " \n " , $stored_headers );
2004-01-14 22:30:09 +00:00
}
2004-09-09 05:51:08 +00:00
/**
* Get the HTTP response headers for the current page .
*/
2004-01-14 22:30:09 +00:00
function drupal_get_headers () {
return drupal_set_header ();
}
2004-02-08 17:12:44 +00:00
/**
* @ name HTTP handling
* @ {
2004-09-09 05:51:08 +00:00
* Functions to properly handle HTTP responses .
2004-02-08 17:12:44 +00:00
*/
2005-02-01 19:45:58 +00:00
/**
* Prepare a destination query string for use in combination with
2005-07-20 10:48:20 +00:00
* drupal_goto () . Used to direct the user back to the referring page
* after completing a form . By default the current URL is returned .
* If a destination exists in the previous request , that destination
* is returned . As such , a destination can persist across multiple
* pages .
2005-02-01 19:45:58 +00:00
*
* @ see drupal_goto ()
*/
function drupal_get_destination () {
2005-07-20 10:48:20 +00:00
if ( $_REQUEST [ 'destination' ]) {
return 'destination=' . urlencode ( $_REQUEST [ 'destination' ]);
}
else {
2006-02-27 14:06:09 +00:00
$path = $_GET [ 'q' ];
$params = array ();
foreach ( $_GET as $key => $value ) {
if ( $key == 'q' ) {
continue ;
2005-07-20 10:48:20 +00:00
}
2006-02-27 14:06:09 +00:00
$params [] = urlencode ( $key ) . '=' . urlencode ( $value );
2005-02-01 19:45:58 +00:00
}
2006-02-27 14:06:09 +00:00
if ( count ( $params )) {
$path .= '?' ;
}
return 'destination=' . urlencode ( $path . implode ( '&' , $params ));
2005-02-01 19:45:58 +00:00
}
}
2004-01-06 19:52:14 +00:00
/**
2004-07-11 07:31:11 +00:00
* Send the user to a different Drupal page .
2004-01-06 19:52:14 +00:00
*
2004-07-11 07:31:11 +00:00
* This issues an on - site HTTP redirect . The function makes sure the redirected
* URL is formatted correctly .
2004-01-06 19:52:14 +00:00
*
2005-02-01 19:45:58 +00:00
* Usually the redirected URL is constructed from this function ' s input
* parameters . However you may override that behavior by setting a
* < em > destination </ em > in either the $_REQUEST - array ( i . e . by using
* the query string of an URI ) or the $_REQUEST [ 'edit' ] - array ( i . e . by
* using a hidden form field ) . This is used to direct the user back to
* the proper page after completing a form . For example , after editing
* a post on the 'admin/node' - page or after having logged on using the
* 'user login' - block in a sidebar . The function drupal_get_destination ()
* can be used to help set the destination URL .
*
2004-07-11 07:31:11 +00:00
* It is advised to use drupal_goto () instead of PHP ' s header (), because
* drupal_goto () will append the user ' s session ID to the URI when PHP is
* compiled with " --enable-trans-sid " .
*
* This function ends the request ; use it rather than a print theme ( 'page' )
* statement in your menu callback .
*
* @ param $path
* A Drupal path .
* @ param $query
* The query string component , if any .
* @ param $fragment
* The destination fragment identifier ( named anchor ) .
2005-02-01 19:45:58 +00:00
*
* @ see drupal_get_destination ()
2004-01-06 19:52:14 +00:00
*/
2004-07-11 07:31:11 +00:00
function drupal_goto ( $path = '' , $query = NULL , $fragment = NULL ) {
2006-02-27 14:19:07 +00:00
if ( isset ( $_REQUEST [ 'destination' ])) {
2005-02-01 19:45:58 +00:00
extract ( parse_url ( $_REQUEST [ 'destination' ]));
}
2006-02-27 14:19:07 +00:00
else if ( isset ( $_REQUEST [ 'edit' ][ 'destination' ])) {
2005-02-01 19:45:58 +00:00
extract ( parse_url ( $_REQUEST [ 'edit' ][ 'destination' ]));
}
2005-03-31 09:25:33 +00:00
$url = url ( $path , $query , $fragment , TRUE );
2004-01-06 19:52:14 +00:00
2004-07-11 07:31:11 +00:00
// Before the redirect, allow modules to react to the end of the page request.
module_invoke_all ( 'exit' , $url );
header ( 'Location: ' . $url );
2004-01-06 19:52:14 +00:00
2004-07-11 07:31:11 +00:00
// The "Location" header sends a REDIRECT status code to the http
// daemon. In some cases this can go wrong, so we make sure none
// of the code below the drupal_goto() call gets executed when we redirect.
2004-01-06 19:52:14 +00:00
exit ();
}
2005-10-08 12:38:20 +00:00
/**
2006-01-22 07:51:06 +00:00
* Generates a site off - line message
2005-10-08 12:38:20 +00:00
*/
function drupal_site_offline () {
2005-10-25 03:43:57 +00:00
drupal_set_header ( 'HTTP/1.0 503 Service unavailable' );
2006-01-22 07:51:06 +00:00
drupal_set_title ( t ( 'Site off-line' ));
2006-04-07 15:32:17 +00:00
print theme ( 'maintenance_page' , filter_xss_admin ( variable_get ( 'site_offline_message' ,
t ( '%site is currently under maintenance. We should be back shortly. Thank you for your patience.' , array ( '%site' => variable_get ( 'site_name' , t ( 'This Drupal site' )))))));
2005-10-08 12:38:20 +00:00
}
2004-01-06 19:52:14 +00:00
/**
* Generates a 404 error if the request can not be handled .
*/
2003-12-16 21:06:34 +00:00
function drupal_not_found () {
2005-10-25 03:43:57 +00:00
drupal_set_header ( 'HTTP/1.0 404 Not Found' );
2005-03-31 09:25:33 +00:00
watchdog ( 'page not found' , t ( '%page not found.' , array ( '%page' => theme ( 'placeholder' , $_GET [ 'q' ]))), WATCHDOG_WARNING );
2003-12-16 21:06:34 +00:00
2006-04-04 07:46:02 +00:00
// Keep old path for reference
if ( ! isset ( $_REQUEST [ 'destination' ])) {
$_REQUEST [ 'destination' ] = $_GET [ 'q' ];
}
2003-12-16 21:06:34 +00:00
$path = drupal_get_normal_path ( variable_get ( 'site_404' , '' ));
2006-01-26 08:59:00 +00:00
if ( $path && $path != $_GET [ 'q' ]) {
2003-12-16 21:06:34 +00:00
menu_set_active_item ( $path );
2005-04-28 19:23:19 +00:00
$return = menu_execute_active_handler ();
2003-12-16 21:06:34 +00:00
}
2006-03-17 18:56:25 +00:00
else {
// Redirect to a non-existant menu item to make possible tabs disappear.
2006-04-04 07:46:02 +00:00
menu_set_active_item ( '' );
2006-03-17 18:56:25 +00:00
}
2003-12-16 21:06:34 +00:00
2005-04-28 19:23:19 +00:00
if ( empty ( $return )) {
2004-12-15 21:19:42 +00:00
drupal_set_title ( t ( 'Page not found' ));
2003-12-16 21:06:34 +00:00
}
2005-04-28 19:23:19 +00:00
print theme ( 'page' , $return );
2003-12-16 21:06:34 +00:00
}
2004-01-07 19:52:10 +00:00
2004-04-21 13:56:38 +00:00
/**
* Generates a 403 error if the request is not allowed .
*/
function drupal_access_denied () {
2005-10-25 03:43:57 +00:00
drupal_set_header ( 'HTTP/1.0 403 Forbidden' );
2005-03-31 09:25:33 +00:00
watchdog ( 'access denied' , t ( '%page denied access.' , array ( '%page' => theme ( 'placeholder' , $_GET [ 'q' ]))), WATCHDOG_WARNING , l ( t ( 'view' ), $_GET [ 'q' ]));
2004-04-21 13:56:38 +00:00
2006-04-04 07:46:02 +00:00
// Keep old path for reference
if ( ! isset ( $_REQUEST [ 'destination' ])) {
$_REQUEST [ 'destination' ] = $_GET [ 'q' ];
}
2004-04-21 13:56:38 +00:00
$path = drupal_get_normal_path ( variable_get ( 'site_403' , '' ));
2006-01-26 08:59:00 +00:00
if ( $path && $path != $_GET [ 'q' ]) {
2004-04-21 13:56:38 +00:00
menu_set_active_item ( $path );
2005-04-28 19:23:19 +00:00
$return = menu_execute_active_handler ();
2004-04-21 13:56:38 +00:00
}
2006-03-17 18:56:25 +00:00
else {
// Redirect to a non-existant menu item to make possible tabs disappear.
2006-04-04 07:46:02 +00:00
menu_set_active_item ( '' );
2006-03-17 18:56:25 +00:00
}
2004-04-21 13:56:38 +00:00
2005-04-28 19:23:19 +00:00
if ( empty ( $return )) {
2004-12-15 21:19:42 +00:00
drupal_set_title ( t ( 'Access denied' ));
2005-08-22 20:39:43 +00:00
$return = t ( 'You are not authorized to access this page.' );
2004-04-21 13:56:38 +00:00
}
2005-04-28 19:23:19 +00:00
print theme ( 'page' , $return );
2004-04-21 13:56:38 +00:00
}
2004-01-07 19:52:10 +00:00
/**
2004-07-13 07:21:14 +00:00
* Perform an HTTP request .
2004-01-07 19:52:10 +00:00
*
2004-07-13 07:21:14 +00:00
* This is a flexible and powerful HTTP client implementation . Correctly handles
* GET , POST , PUT or any other HTTP requests . Handles redirects .
*
* @ param $url
* A string containing a fully qualified URI .
* @ param $headers
* An array containing an HTTP header => value pair .
* @ param $method
* A string defining the HTTP request to use .
* @ param $data
* A string containing data to include in the request .
* @ param $retry
* An integer representing how many times to retry the request in case of a
* redirect .
* @ return
* An object containing the HTTP request headers , response code , headers ,
* data , and redirect status .
2004-01-07 19:52:10 +00:00
*/
function drupal_http_request ( $url , $headers = array (), $method = 'GET' , $data = NULL , $retry = 3 ) {
2005-01-22 11:15:24 +00:00
$result = new StdClass ();
2004-07-13 07:21:14 +00:00
// Parse the URL, and make sure we can handle the schema.
2004-01-07 19:52:10 +00:00
$uri = parse_url ( $url );
switch ( $uri [ 'scheme' ]) {
case 'http' :
2005-12-11 12:31:17 +00:00
$port = isset ( $uri [ 'port' ]) ? $uri [ 'port' ] : 80 ;
2006-02-16 13:00:18 +00:00
$host = $uri [ 'host' ] . ( $port != 80 ? ':' . $port : '' );
2005-09-29 12:33:34 +00:00
$fp = @ fsockopen ( $uri [ 'host' ], $port , $errno , $errstr , 15 );
2004-01-07 19:52:10 +00:00
break ;
case 'https' :
2004-07-13 07:21:14 +00:00
// Note: Only works for PHP 4.3 compiled with OpenSSL.
2005-12-11 12:31:17 +00:00
$port = isset ( $uri [ 'port' ]) ? $uri [ 'port' ] : 443 ;
2006-02-16 13:00:18 +00:00
$host = $uri [ 'host' ] . ( $port != 443 ? ':' . $port : '' );
2005-09-29 12:33:34 +00:00
$fp = @ fsockopen ( 'ssl://' . $uri [ 'host' ], $port , $errno , $errstr , 20 );
2004-01-07 19:52:10 +00:00
break ;
default :
2004-07-13 07:21:14 +00:00
$result -> error = 'invalid schema ' . $uri [ 'scheme' ];
2004-01-07 19:52:10 +00:00
return $result ;
}
2004-07-13 07:21:14 +00:00
// Make sure the socket opened properly.
2004-01-07 19:52:10 +00:00
if ( ! $fp ) {
2004-07-13 07:21:14 +00:00
$result -> error = trim ( $errno . ' ' . $errstr );
2004-01-07 19:52:10 +00:00
return $result ;
}
2004-07-13 07:21:14 +00:00
// Construct the path to act on.
2005-12-11 12:31:17 +00:00
$path = isset ( $uri [ 'path' ]) ? $uri [ 'path' ] : '/' ;
if ( isset ( $uri [ 'query' ])) {
2004-07-13 07:21:14 +00:00
$path .= '?' . $uri [ 'query' ];
2004-01-07 19:52:10 +00:00
}
2004-09-09 05:51:08 +00:00
// Create HTTP request.
2004-01-07 19:52:10 +00:00
$defaults = array (
2006-02-16 13:00:18 +00:00
// RFC 2616: "non-standard ports MUST, default ports MAY be included".
// We don't add the port to prevent from breaking rewrite rules checking
// the host that do not take into account the port number.
'Host' => " Host: $host " ,
2006-02-21 18:46:54 +00:00
'User-Agent' => 'User-Agent: Drupal (+http://drupal.org/)' ,
2004-01-07 20:43:26 +00:00
'Content-Length' => 'Content-Length: ' . strlen ( $data )
2004-01-07 19:52:10 +00:00
);
foreach ( $headers as $header => $value ) {
2004-07-13 07:21:14 +00:00
$defaults [ $header ] = $header . ': ' . $value ;
2004-01-07 19:52:10 +00:00
}
2004-07-13 07:21:14 +00:00
$request = $method . ' ' . $path . " HTTP/1.0 \r \n " ;
2004-01-07 19:52:10 +00:00
$request .= implode ( " \r \n " , $defaults );
$request .= " \r \n \r \n " ;
if ( $data ) {
2004-07-13 07:21:14 +00:00
$request .= $data . " \r \n " ;
2004-01-07 19:52:10 +00:00
}
$result -> request = $request ;
fwrite ( $fp , $request );
// Fetch response.
2004-04-27 18:17:17 +00:00
$response = '' ;
2006-02-23 15:19:10 +00:00
while ( ! feof ( $fp ) && $chunk = fread ( $fp , 1024 )) {
$response .= $chunk ;
2004-01-07 19:52:10 +00:00
}
fclose ( $fp );
// Parse response.
2006-02-23 15:19:10 +00:00
list ( $split , $result -> data ) = explode ( " \r \n \r \n " , $response , 2 );
$split = preg_split ( " / \r \n | \n | \r / " , $split );
2004-06-21 20:14:41 +00:00
2006-02-23 15:19:10 +00:00
list ( $protocol , $code , $text ) = explode ( ' ' , trim ( array_shift ( $split )), 3 );
2004-01-07 19:52:10 +00:00
$result -> headers = array ();
// Parse headers.
2006-02-23 15:19:10 +00:00
while ( $line = trim ( array_shift ( $split ))) {
2004-01-07 19:52:10 +00:00
list ( $header , $value ) = explode ( ':' , $line , 2 );
2005-08-22 20:24:53 +00:00
if ( isset ( $result -> headers [ $header ]) && $header == 'Set-Cookie' ) {
// RFC 2109: the Set-Cookie response header comprises the token Set-
// Cookie:, followed by a comma-separated list of one or more cookies.
$result -> headers [ $header ] .= ',' . trim ( $value );
}
else {
$result -> headers [ $header ] = trim ( $value );
}
2004-01-07 19:52:10 +00:00
}
$responses = array (
100 => 'Continue' , 101 => 'Switching Protocols' ,
200 => 'OK' , 201 => 'Created' , 202 => 'Accepted' , 203 => 'Non-Authoritative Information' , 204 => 'No Content' , 205 => 'Reset Content' , 206 => 'Partial Content' ,
300 => 'Multiple Choices' , 301 => 'Moved Permanently' , 302 => 'Found' , 303 => 'See Other' , 304 => 'Not Modified' , 305 => 'Use Proxy' , 307 => 'Temporary Redirect' ,
400 => 'Bad Request' , 401 => 'Unauthorized' , 402 => 'Payment Required' , 403 => 'Forbidden' , 404 => 'Not Found' , 405 => 'Method Not Allowed' , 406 => 'Not Acceptable' , 407 => 'Proxy Authentication Required' , 408 => 'Request Time-out' , 409 => 'Conflict' , 410 => 'Gone' , 411 => 'Length Required' , 412 => 'Precondition Failed' , 413 => 'Request Entity Too Large' , 414 => 'Request-URI Too Large' , 415 => 'Unsupported Media Type' , 416 => 'Requested range not satisfiable' , 417 => 'Expectation Failed' ,
500 => 'Internal Server Error' , 501 => 'Not Implemented' , 502 => 'Bad Gateway' , 503 => 'Service Unavailable' , 504 => 'Gateway Time-out' , 505 => 'HTTP Version not supported'
);
// RFC 2616 states that all unknown HTTP codes must be treated the same as
2004-09-09 05:51:08 +00:00
// the base code in their class.
2004-01-07 19:52:10 +00:00
if ( ! isset ( $responses [ $code ])) {
$code = floor ( $code / 100 ) * 100 ;
}
switch ( $code ) {
case 200 : // OK
case 304 : // Not modified
break ;
case 301 : // Moved permanently
case 302 : // Moved temporarily
case 307 : // Moved temporarily
$location = $result -> headers [ 'Location' ];
if ( $retry ) {
$result = drupal_http_request ( $result -> headers [ 'Location' ], $headers , $method , $data , -- $retry );
$result -> redirect_code = $result -> code ;
}
$result -> redirect_url = $location ;
break ;
default :
$result -> error = $text ;
}
$result -> code = $code ;
return $result ;
}
2004-09-09 05:51:08 +00:00
/**
* @ } End of " HTTP handling " .
*/
2003-12-16 21:06:34 +00:00
2004-07-13 07:21:14 +00:00
/**
2004-10-04 22:04:07 +00:00
* Log errors as defined by administrator
* Error levels :
2005-08-23 05:19:44 +00:00
* 0 = Log errors to database .
* 1 = Log errors to database and to screen .
2004-07-13 07:21:14 +00:00
*/
2005-03-21 19:26:47 +00:00
function error_handler ( $errno , $message , $filename , $line ) {
2005-03-03 20:13:20 +00:00
if ( $errno & ( E_ALL ^ E_NOTICE )) {
2004-10-04 22:04:07 +00:00
$types = array ( 1 => 'error' , 2 => 'warning' , 4 => 'parse error' , 8 => 'notice' , 16 => 'core error' , 32 => 'core warning' , 64 => 'compile error' , 128 => 'compile warning' , 256 => 'user error' , 512 => 'user warning' , 1024 => 'user notice' , 2048 => 'strict warning' );
$entry = $types [ $errno ] . ': ' . $message . ' in ' . $filename . ' on line ' . $line . '.' ;
2003-04-21 12:36:09 +00:00
2006-03-28 09:29:23 +00:00
// Note: force display of error messages in update.php
if ( variable_get ( 'error_level' , 1 ) == 1 || strstr ( $_SERVER [ 'PHP_SELF' ], 'update.php' )) {
2005-11-27 09:14:52 +00:00
drupal_set_message ( $entry , 'error' );
2003-12-13 14:59:55 +00:00
}
2005-01-09 09:22:40 +00:00
watchdog ( 'php' , t ( '%message in %file on line %line.' , array ( '%error' => $types [ $errno ], '%message' => $message , '%file' => $filename , '%line' => $line )), WATCHDOG_ERROR );
2001-12-01 15:20:48 +00:00
}
}
2005-03-21 19:26:47 +00:00
function _fix_gpc_magic ( & $item ) {
2003-12-13 14:59:55 +00:00
if ( is_array ( $item )) {
2003-12-19 10:52:37 +00:00
array_walk ( $item , '_fix_gpc_magic' );
}
else {
2003-12-19 13:44:08 +00:00
$item = stripslashes ( $item );
2002-12-26 12:16:09 +00:00
}
}
2004-07-13 07:21:14 +00:00
/**
* Correct double - escaping problems caused by " magic quotes " in some PHP
* installations .
*/
2003-10-31 19:34:03 +00:00
function fix_gpc_magic () {
static $fixed = false ;
2004-07-13 07:21:14 +00:00
if ( ! $fixed && ini_get ( 'magic_quotes_gpc' )) {
2003-12-13 14:59:55 +00:00
array_walk ( $_GET , '_fix_gpc_magic' );
array_walk ( $_POST , '_fix_gpc_magic' );
array_walk ( $_COOKIE , '_fix_gpc_magic' );
array_walk ( $_REQUEST , '_fix_gpc_magic' );
$fixed = true ;
}
2003-10-31 19:34:03 +00:00
}
2004-01-06 19:52:14 +00:00
/**
* @ name Messages
* @ {
2004-09-09 05:51:08 +00:00
* Frequently used messages .
2004-01-06 19:52:14 +00:00
*/
2004-07-13 07:21:14 +00:00
/**
* Return a string with a " not applicable " message .
*/
2001-12-01 15:20:48 +00:00
function message_na () {
2004-07-13 07:21:14 +00:00
return t ( 'n/a' );
2001-12-01 15:20:48 +00:00
}
2004-09-09 05:51:08 +00:00
/**
* @ } End of " Messages " .
*/
2001-12-01 15:20:48 +00:00
2004-07-13 07:21:14 +00:00
/**
* Initialize the localization system .
*/
2004-08-11 11:26:20 +00:00
function locale_initialize () {
global $user ;
2004-09-15 09:54:32 +00:00
if ( function_exists ( 'i18n_get_lang' )) {
return i18n_get_lang ();
}
2004-08-11 11:26:20 +00:00
if ( function_exists ( 'locale' )) {
$languages = locale_supported_languages ();
$languages = $languages [ 'name' ];
}
else {
2004-09-09 13:36:01 +00:00
// Ensure the locale/language is correctly returned, even without locale.module.
// Useful for e.g. XML/HTML 'lang' attributes.
$languages = array ( 'en' => 'English' );
2004-08-11 11:26:20 +00:00
}
2005-10-22 15:14:46 +00:00
if ( $user -> uid && isset ( $languages [ $user -> language ])) {
2003-03-04 15:10:37 +00:00
return $user -> language ;
}
else {
return key ( $languages );
}
2001-12-27 15:27:44 +00:00
}
2004-01-06 19:52:14 +00:00
/**
2004-07-13 07:21:14 +00:00
* Translate strings to the current locale .
2004-01-06 19:52:14 +00:00
*
2004-01-11 20:31:26 +00:00
* When using t (), try to put entire sentences and strings in one t () call .
2004-09-09 05:51:08 +00:00
* This makes it easier for translators . HTML markup within translation strings
* is acceptable , if necessary . The suggested syntax for a link embedded
* within a translation string is :
* @ code
2004-07-13 07:21:14 +00:00
* $msg = t ( ' You must log in below or < a href = " %url " > create a new
* account </ a > before viewing the next page . ', array(' % url '
* => url ( 'user/register' )));
2004-09-09 05:51:08 +00:00
* @ endcode
2004-01-11 20:31:26 +00:00
* We suggest the same syntax for links to other sites . This makes it easy to
* change link URLs if needed ( which happens often ) without requiring updates
* to translations .
2004-01-06 19:52:14 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $string
2004-09-09 05:51:08 +00:00
* A string containing the English string to translate .
2004-07-13 07:21:14 +00:00
* @ param $args
* An associative array of replacements to make after translation . Incidences
2004-09-09 05:51:08 +00:00
* of any key in this array are replaced with the corresponding value .
2004-07-13 07:21:14 +00:00
* @ return
* The translated string .
2004-01-06 19:52:14 +00:00
*/
2002-04-20 11:52:50 +00:00
function t ( $string , $args = 0 ) {
2004-08-11 11:26:20 +00:00
global $locale ;
if ( function_exists ( 'locale' ) && $locale != 'en' ) {
$string = locale ( $string );
}
2002-04-24 20:55:20 +00:00
2002-04-20 11:52:50 +00:00
if ( ! $args ) {
return $string ;
2002-04-22 09:05:36 +00:00
}
else {
2002-04-20 11:52:50 +00:00
return strtr ( $string , $args );
}
2001-12-27 15:27:44 +00:00
}
2004-01-06 19:52:14 +00:00
/**
2004-09-09 05:51:08 +00:00
* @ defgroup validation Input validation
2004-02-08 17:12:44 +00:00
* @ {
2004-09-09 05:51:08 +00:00
* Functions to validate user input .
2004-01-06 19:52:14 +00:00
*/
2003-03-28 10:55:27 +00:00
/**
2004-07-13 07:21:14 +00:00
* Verify the syntax of the given e - mail address .
*
* Empty e - mail addresses are allowed . See RFC 2822 for details .
2003-03-28 10:55:27 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $mail
2006-01-13 07:33:13 +00:00
* A string containing an e - mail address .
2004-01-07 19:52:10 +00:00
* @ return
2004-07-13 07:21:14 +00:00
* TRUE if the address is in a valid format .
2003-03-28 10:55:27 +00:00
*/
2003-04-13 13:42:51 +00:00
function valid_email_address ( $mail ) {
2003-03-28 10:55:27 +00:00
$user = '[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\']+' ;
2004-05-24 18:09:28 +00:00
$domain = '(?:(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.?)+' ;
2003-03-28 10:55:27 +00:00
$ipv4 = '[0-9]{1,3}(\.[0-9]{1,3}){3}' ;
$ipv6 = '[0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7}' ;
2003-12-13 14:59:55 +00:00
return preg_match ( " /^ $user @( $domain |( \ [( $ipv4 | $ipv6 ) \ ])) $ / " , $mail );
2003-03-28 10:55:27 +00:00
}
2003-07-16 20:14:26 +00:00
/**
* Verify the syntax of the given URL .
*
2004-04-12 08:27:57 +00:00
* @ param $url
2004-07-13 07:21:14 +00:00
* The URL to verify .
2004-04-12 08:27:57 +00:00
* @ param $absolute
2004-09-09 05:51:08 +00:00
* Whether the URL is absolute ( beginning with a scheme such as " http: " ) .
2004-04-12 08:27:57 +00:00
* @ return
2004-07-13 07:21:14 +00:00
* TRUE if the URL is in a valid format .
2003-07-16 20:14:26 +00:00
*/
2004-04-12 08:27:57 +00:00
function valid_url ( $url , $absolute = FALSE ) {
2005-03-06 06:57:58 +00:00
$allowed_characters = '[a-z0-9\/:_\-_\.\?\$,~=#&%\+]' ;
2004-03-21 10:28:10 +00:00
if ( $absolute ) {
2005-03-06 06:57:58 +00:00
return preg_match ( " /^(http|https|ftp): \ / \ / " . $allowed_characters . " + $ /i " , $url );
2004-03-21 10:28:10 +00:00
}
else {
2005-03-06 06:57:58 +00:00
return preg_match ( " /^ " . $allowed_characters . " + $ /i " , $url );
2004-03-21 10:28:10 +00:00
}
2003-07-16 20:14:26 +00:00
}
2004-11-15 21:17:25 +00:00
/**
* Register an event for the current visitor ( hostname / IP ) to the flood control mechanism .
*
* @ param $name
* The name of the event .
*/
function flood_register_event ( $name ) {
db_query ( " INSERT INTO { flood} (event, hostname, timestamp) VALUES ('%s', '%s', %d) " , $name , $_SERVER [ 'REMOTE_ADDR' ], time ());
}
/**
* Check if the current visitor ( hostname / IP ) is allowed to proceed with the specified event .
* The user is allowed to proceed if he did not trigger the specified event more than
* $threshold times per hour .
*
* @ param $name
* The name of the event .
* @ param $number
* The maximum number of the specified event per hour ( per visitor ) .
* @ return
* True if the user did not exceed the hourly threshold . False otherwise .
*/
function flood_is_allowed ( $name , $threshold ) {
$number = db_num_rows ( db_query ( " SELECT event FROM { flood} WHERE event = '%s' AND hostname = '%s' AND timestamp > %d " , $name , $_SERVER [ 'REMOTE_ADDR' ], time () - 3600 ));
return ( $number < $threshold ? TRUE : FALSE );
}
2003-10-07 10:22:33 +00:00
function check_file ( $filename ) {
return is_uploaded_file ( $filename );
2001-12-01 15:20:48 +00:00
}
2005-11-30 10:27:13 +00:00
/**
* Prepare a URL for use in an HTML attribute . Strips harmful protocols .
*
*/
function check_url ( $uri ) {
2005-12-02 10:31:21 +00:00
return filter_xss_bad_protocol ( $uri , FALSE );
2005-11-30 10:27:13 +00:00
}
2004-02-08 17:12:44 +00:00
/**
2004-09-09 05:51:08 +00:00
* @ defgroup format Formatting
2004-02-08 17:12:44 +00:00
* @ {
2004-09-09 05:51:08 +00:00
* Functions to format numbers , strings , dates , etc .
2004-02-08 17:12:44 +00:00
*/
2004-07-13 07:21:14 +00:00
/**
* Formats an RSS channel .
*
* Arbitrary elements may be added using the $args associative array .
*/
function format_rss_channel ( $title , $link , $description , $items , $language = 'en' , $args = array ()) {
2002-04-27 13:19:37 +00:00
// arbitrary elements may be added using the $args associative array
2003-12-13 14:59:55 +00:00
$output = " <channel> \n " ;
2005-03-31 09:25:33 +00:00
$output .= ' <title>' . check_plain ( $title ) . " </title> \n " ;
$output .= ' <link>' . check_url ( $link ) . " </link> \n " ;
2006-03-01 21:30:17 +00:00
// The RSS 2.0 "spec" doesn't indicate HTML can be used in the description.
// We strip all HTML tags, but need to prevent double encoding from properly
// escaped source data (such as & becoming &amp;).
$output .= ' <description>' . check_plain ( decode_entities ( strip_tags ( $description ))) . " </description> \n " ;
2005-03-31 09:25:33 +00:00
$output .= ' <language>' . check_plain ( $language ) . " </language> \n " ;
2002-04-27 13:19:37 +00:00
foreach ( $args as $key => $value ) {
2005-03-31 09:25:33 +00:00
$output .= ' <' . $key . '>' . check_plain ( $value ) . " </ $key > \n " ;
2002-04-27 13:19:37 +00:00
}
2001-12-01 15:20:48 +00:00
$output .= $items ;
$output .= " </channel> \n " ;
return $output ;
}
2004-07-13 07:21:14 +00:00
/**
* Format a single RSS item .
*
* Arbitrary elements may be added using the $args associative array .
*/
2002-04-27 13:19:37 +00:00
function format_rss_item ( $title , $link , $description , $args = array ()) {
2003-12-13 14:59:55 +00:00
$output = " <item> \n " ;
2005-03-31 09:25:33 +00:00
$output .= ' <title>' . check_plain ( $title ) . " </title> \n " ;
$output .= ' <link>' . check_url ( $link ) . " </link> \n " ;
$output .= ' <description>' . check_plain ( $description ) . " </description> \n " ;
2002-04-27 13:19:37 +00:00
foreach ( $args as $key => $value ) {
2005-02-01 14:09:31 +00:00
if ( is_array ( $value )) {
if ( $value [ 'key' ]) {
$output .= ' <' . $value [ 'key' ];
2005-12-14 20:10:45 +00:00
if ( isset ( $value [ 'attributes' ]) && is_array ( $value [ 'attributes' ])) {
2005-02-01 14:09:31 +00:00
$output .= drupal_attributes ( $value [ 'attributes' ]);
}
if ( $value [ 'value' ]) {
$output .= '>' . $value [ 'value' ] . '</' . $value [ 'key' ] . " > \n " ;
}
else {
$output .= " /> \n " ;
}
}
}
else {
2005-03-31 09:25:33 +00:00
$output .= ' <' . $key . '>' . check_plain ( $value ) . " </ $key > \n " ;
2005-02-01 14:09:31 +00:00
}
2002-04-27 13:19:37 +00:00
}
2001-12-01 15:20:48 +00:00
$output .= " </item> \n " ;
return $output ;
}
2003-01-21 22:44:25 +00:00
/**
2004-07-13 07:21:14 +00:00
* Format a string containing a count of items .
2003-01-21 22:44:25 +00:00
*
2004-07-13 07:21:14 +00:00
* This function ensures that the string is pluralized correctly . Since t () is
* called by this function , make sure not to pass already - localized strings to it .
*
* @ param $count
* The item count to display .
* @ param $singular
* The string for the singular case . Please make sure it is clear this is
* singular , to ease translation ( e . g . use " 1 new comment " instead of " 1 new " ) .
* @ param $plural
* The string for the plural case . Please make sure it is clear this is plural ,
* to ease translation . Use % count in place of the item count , as in " %count
* new comments " .
* @ return
* A translated string .
2003-01-21 22:44:25 +00:00
*/
2001-12-01 15:20:48 +00:00
function format_plural ( $count , $singular , $plural ) {
2004-10-27 18:23:06 +00:00
if ( $count == 1 ) return t ( $singular , array ( " %count " => $count ));
2004-08-11 11:26:20 +00:00
// get the plural index through the gettext formula
2005-06-22 20:19:58 +00:00
$index = ( function_exists ( 'locale_get_plural' )) ? locale_get_plural ( $count ) : - 1 ;
2004-08-11 11:26:20 +00:00
if ( $index < 0 ) { // backward compatibility
return t ( $plural , array ( " %count " => $count ));
}
else {
switch ( $index ) {
case " 0 " :
2004-10-27 18:23:06 +00:00
return t ( $singular , array ( " %count " => $count ));
2004-08-11 11:26:20 +00:00
case " 1 " :
return t ( $plural , array ( " %count " => $count ));
default :
return t ( strtr ( $plural , array ( " %count " => '%count[' . $index . ']' )), array ( '%count[' . $index . ']' => $count ));
}
}
2001-12-01 15:20:48 +00:00
}
2004-02-08 17:12:44 +00:00
/**
2004-07-13 07:21:14 +00:00
* Generate a string representation for the given byte count .
2004-02-08 17:12:44 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $size
* The size in bytes .
* @ return
* A translated string representation of the size .
2004-02-08 17:12:44 +00:00
*/
2001-12-01 15:20:48 +00:00
function format_size ( $size ) {
2004-07-13 07:21:14 +00:00
$suffix = t ( 'bytes' );
2005-05-20 11:31:16 +00:00
if ( $size >= 1024 ) {
2001-12-01 15:20:48 +00:00
$size = round ( $size / 1024 , 2 );
2004-07-13 07:21:14 +00:00
$suffix = t ( 'KB' );
2001-12-01 15:20:48 +00:00
}
2005-05-20 11:31:16 +00:00
if ( $size >= 1024 ) {
2001-12-01 15:20:48 +00:00
$size = round ( $size / 1024 , 2 );
2004-07-13 07:21:14 +00:00
$suffix = t ( 'MB' );
2001-12-01 15:20:48 +00:00
}
2004-07-13 07:21:14 +00:00
return t ( '%size %suffix' , array ( '%size' => $size , '%suffix' => $suffix ));
2001-12-01 15:20:48 +00:00
}
2004-02-08 17:12:44 +00:00
/**
2004-07-13 07:21:14 +00:00
* Format a time interval with the requested granularity .
2004-02-08 17:12:44 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $timestamp
* The length of the interval in seconds .
* @ param $granularity
* How many different units to display in the string .
* @ return
* A translated string representation of the interval .
2004-02-08 17:12:44 +00:00
*/
2004-01-21 06:40:57 +00:00
function format_interval ( $timestamp , $granularity = 2 ) {
2004-07-13 07:21:14 +00:00
$units = array ( '1 year|%count years' => 31536000 , '1 week|%count weeks' => 604800 , '1 day|%count days' => 86400 , '1 hour|%count hours' => 3600 , '1 min|%count min' => 60 , '1 sec|%count sec' => 1 );
2004-04-12 08:27:57 +00:00
$output = '' ;
2003-12-24 12:40:28 +00:00
foreach ( $units as $key => $value ) {
2004-07-13 07:21:14 +00:00
$key = explode ( '|' , $key );
2001-12-01 15:20:48 +00:00
if ( $timestamp >= $value ) {
2004-07-13 07:21:14 +00:00
$output .= ( $output ? ' ' : '' ) . format_plural ( floor ( $timestamp / $value ), $key [ 0 ], $key [ 1 ]);
2001-12-01 15:20:48 +00:00
$timestamp %= $value ;
2004-01-21 06:40:57 +00:00
$granularity -- ;
}
if ( $granularity == 0 ) {
break ;
2001-12-01 15:20:48 +00:00
}
}
2004-07-13 07:21:14 +00:00
return $output ? $output : t ( '0 sec' );
2001-12-01 15:20:48 +00:00
}
2004-02-08 17:12:44 +00:00
/**
2004-07-13 07:21:14 +00:00
* Format a date with the given configured format or a custom format string .
*
2004-02-08 17:12:44 +00:00
* Drupal allows administrators to select formatting strings for 'small' ,
* 'medium' and 'large' date formats . This function can handle these formats ,
* as well as any custom format .
*
2004-07-13 07:21:14 +00:00
* @ param $timestamp
* The exact date to format , as a UNIX timestamp .
* @ param $type
* The format to use . Can be " small " , " medium " or " large " for the preconfigured
* date formats . If " custom " is specified , then $format is required as well .
* @ param $format
2004-12-03 20:38:22 +00:00
* A PHP date format string as required by date () . A backslash should be used
* before a character to avoid interpreting the character as part of a date
* format .
2004-07-13 07:21:14 +00:00
* @ param $timezone
* Time zone offset in seconds ; if omitted , the user ' s time zone is used .
* @ return
* A translated date string in the requested format .
2004-02-08 17:12:44 +00:00
*/
2004-02-08 21:42:59 +00:00
function format_date ( $timestamp , $type = 'medium' , $format = '' , $timezone = NULL ) {
2006-01-17 15:39:07 +00:00
if ( ! isset ( $timezone )) {
2004-02-08 21:42:59 +00:00
global $user ;
2004-08-10 01:30:09 +00:00
if ( variable_get ( 'configurable_timezones' , 1 ) && $user -> uid && strlen ( $user -> timezone )) {
$timezone = $user -> timezone ;
}
else {
$timezone = variable_get ( 'date_default_timezone' , 0 );
}
2004-02-08 21:42:59 +00:00
}
2001-12-01 15:20:48 +00:00
2004-02-08 21:42:59 +00:00
$timestamp += $timezone ;
2001-12-01 15:20:48 +00:00
switch ( $type ) {
2004-02-08 21:42:59 +00:00
case 'small' :
$format = variable_get ( 'date_format_short' , 'm/d/Y - H:i' );
2001-12-01 15:20:48 +00:00
break ;
2004-02-08 21:42:59 +00:00
case 'large' :
$format = variable_get ( 'date_format_long' , 'l, F j, Y - H:i' );
2001-12-01 15:20:48 +00:00
break ;
2004-02-08 21:42:59 +00:00
case 'custom' :
2003-09-29 18:20:38 +00:00
// No change to format
2001-12-01 15:20:48 +00:00
break ;
2004-02-08 21:42:59 +00:00
case 'medium' :
2001-12-01 15:20:48 +00:00
default :
2004-02-08 21:42:59 +00:00
$format = variable_get ( 'date_format_medium' , 'D, m/d/Y - H:i' );
2003-09-29 18:20:38 +00:00
}
2004-02-08 21:42:59 +00:00
$max = strlen ( $format );
2004-04-12 08:27:57 +00:00
$date = '' ;
2004-07-02 18:46:42 +00:00
for ( $i = 0 ; $i < $max ; $i ++ ) {
2006-01-15 07:14:14 +00:00
$c = $format [ $i ];
2004-07-21 15:30:35 +00:00
if ( strpos ( 'AaDFlM' , $c ) !== false ) {
2004-02-21 14:08:09 +00:00
$date .= t ( gmdate ( $c , $timestamp ));
2004-02-08 21:42:59 +00:00
}
2004-07-21 15:30:35 +00:00
else if ( strpos ( 'BdgGhHiIjLmnsStTUwWYyz' , $c ) !== false ) {
2004-02-08 21:42:59 +00:00
$date .= gmdate ( $c , $timestamp );
}
else if ( $c == 'r' ) {
$date .= format_date ( $timestamp - $timezone , 'custom' , 'D, d M Y H:i:s O' , $timezone );
2003-09-29 18:20:38 +00:00
}
2004-02-08 21:42:59 +00:00
else if ( $c == 'O' ) {
$date .= sprintf ( '%s%02d%02d' , ( $timezone < 0 ? '-' : '+' ), abs ( $timezone / 3600 ), abs ( $timezone % 3600 ) / 60 );
}
else if ( $c == 'Z' ) {
$date .= $timezone ;
2003-09-29 18:20:38 +00:00
}
2004-12-03 20:38:22 +00:00
else if ( $c == '\\' ) {
$date .= $format [ ++ $i ];
}
2003-09-29 18:20:38 +00:00
else {
2004-02-08 21:42:59 +00:00
$date .= $c ;
2003-09-29 18:20:38 +00:00
}
2001-12-01 15:20:48 +00:00
}
2004-02-08 21:42:59 +00:00
2001-12-01 15:20:48 +00:00
return $date ;
}
2004-09-09 05:51:08 +00:00
/**
* @ } End of " defgroup format " .
*/
2001-12-01 15:20:48 +00:00
2004-07-13 07:21:14 +00:00
/**
2005-12-29 05:28:53 +00:00
* Generate a URL from a Drupal menu path . Will also pass - through existing URLs .
2004-07-13 07:21:14 +00:00
*
* @ param $path
2005-12-29 05:28:53 +00:00
* The Drupal path being linked to , such as " admin/node " , or an existing URL
* like " http://drupal.org/ " .
2004-07-13 07:21:14 +00:00
* @ param $query
2005-12-29 05:28:53 +00:00
* A query string to append to the link or URL .
2004-07-13 07:21:14 +00:00
* @ param $fragment
2005-12-29 05:28:53 +00:00
* A fragment identifier ( named anchor ) to append to the link . If an existing
* URL with a fragment identifier is used , it will be replaced . Note , do not
* include the '#' .
2004-07-13 07:21:14 +00:00
* @ param $absolute
* Whether to force the output to be an absolute link ( beginning with http : ) .
2005-12-29 05:28:53 +00:00
* Useful for links that will be displayed outside the site , such as in an
* RSS feed .
2004-07-13 07:21:14 +00:00
* @ return
* an HTML string containing a link to the given path .
*
* When creating links in modules , consider whether l () could be a better
* alternative than url () .
*/
function url ( $path = NULL , $query = NULL , $fragment = NULL , $absolute = FALSE ) {
2005-12-29 05:28:53 +00:00
if ( isset ( $fragment )) {
$fragment = '#' . $fragment ;
}
// Return an external link if $path contains an allowed absolute URL.
// Only call the slow filter_xss_bad_protocol if $path contains a ':'.
2006-03-10 16:53:09 +00:00
if ( strpos ( $path , ':' ) !== FALSE && filter_xss_bad_protocol ( $path , FALSE ) == check_plain ( $path )) {
2005-12-29 05:28:53 +00:00
// Split off the fragment
if ( strpos ( $path , '#' )) {
list ( $path , $old_fragment ) = explode ( '#' , $path , 2 );
if ( isset ( $old_fragment ) && ! isset ( $fragment )) {
$fragment = '#' . $old_fragment ;
}
}
// Append the query
if ( isset ( $query )) {
$path .= ( strpos ( $path , '?' ) ? '&' : '?' ) . $query ;
}
// Reassemble
return $path . $fragment ;
}
2004-01-17 23:19:02 +00:00
2006-02-02 12:44:57 +00:00
global $base_url ;
2003-05-31 13:05:06 +00:00
static $script ;
2005-12-27 10:36:16 +00:00
static $clean_url ;
2003-05-31 13:05:06 +00:00
if ( empty ( $script )) {
2004-09-09 05:51:08 +00:00
// On some web servers, such as IIS, we can't omit "index.php". So, we
// generate "index.php?q=foo" instead of "?q=foo" on anything that is not
// Apache.
2004-07-13 07:21:14 +00:00
$script = ( strpos ( $_SERVER [ 'SERVER_SOFTWARE' ], 'Apache' ) === false ) ? 'index.php' : '' ;
2003-05-31 13:05:06 +00:00
}
2005-10-07 06:51:43 +00:00
2005-12-27 10:36:16 +00:00
// Cache the clean_url variable to improve performance.
2006-01-17 15:39:07 +00:00
if ( ! isset ( $clean_url )) {
$clean_url = ( bool ) variable_get ( 'clean_url' , '0' );
2005-12-27 10:36:16 +00:00
}
2003-09-30 17:01:34 +00:00
2006-02-02 12:44:57 +00:00
$base = ( $absolute ? $base_url . '/' : base_path ());
2004-02-11 19:21:14 +00:00
2005-12-27 10:36:16 +00:00
// The special path '<front>' links to the default front page.
if ( isset ( $path ) && $path != '<front>' ) {
$path = drupal_get_path_alias ( $path );
$path = drupal_urlencode ( $path );
if ( ! $clean_url ) {
2003-02-14 19:52:45 +00:00
if ( isset ( $query )) {
2005-03-31 09:25:33 +00:00
return $base . $script . '?q=' . $path . '&' . $query . $fragment ;
2003-02-14 19:52:45 +00:00
}
else {
2004-07-13 07:21:14 +00:00
return $base . $script . '?q=' . $path . $fragment ;
2003-02-14 19:52:45 +00:00
}
2003-01-06 21:24:21 +00:00
}
else {
2003-02-14 19:52:45 +00:00
if ( isset ( $query )) {
2005-12-27 10:36:16 +00:00
return $base . $path . '?' . $query . $fragment ;
2003-02-14 19:52:45 +00:00
}
else {
2005-12-27 10:36:16 +00:00
return $base . $path . $fragment ;
2003-02-14 19:52:45 +00:00
}
2003-01-06 21:24:21 +00:00
}
}
else {
2005-12-27 10:36:16 +00:00
if ( isset ( $query )) {
return $base . $script . '?' . $query . $fragment ;
2003-01-06 21:24:21 +00:00
}
2003-01-11 10:46:11 +00:00
else {
2005-12-27 10:36:16 +00:00
return $base . $fragment ;
2003-01-11 10:46:11 +00:00
}
2003-01-06 21:24:21 +00:00
}
2002-04-20 11:52:50 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format an attribute string to insert in a tag .
*
* @ param $attributes
* An associative array of HTML attributes .
* @ return
* An HTML string ready for insertion in a tag .
*/
2004-03-10 19:32:37 +00:00
function drupal_attributes ( $attributes = array ()) {
2005-05-14 09:23:47 +00:00
if ( is_array ( $attributes )) {
2006-03-07 14:57:05 +00:00
$t = '' ;
2003-08-12 20:37:16 +00:00
foreach ( $attributes as $key => $value ) {
2006-03-07 14:57:05 +00:00
$t .= " $key = " . '"' . check_plain ( $value ) . '"' ;
2003-08-12 20:37:16 +00:00
}
2006-03-07 14:57:05 +00:00
return $t ;
2002-04-27 13:19:37 +00:00
}
2003-08-12 20:37:16 +00:00
}
2003-01-06 19:51:01 +00:00
2004-07-13 07:21:14 +00:00
/**
* Format an internal Drupal link .
*
* This function correctly handles aliased paths , and allows themes to highlight
* links to the current page correctly , so all internal links output by modules
* should be generated by this function if possible .
*
* @ param $text
* The text to be enclosed with the anchor tag .
* @ param $path
2005-05-14 09:23:47 +00:00
* The Drupal path being linked to , such as " admin/node " . Note , this must be a
* system URL as the url () function will generate the alias .
2004-07-13 07:21:14 +00:00
* @ param $attributes
* An associative array of HTML attributes to apply to the anchor tag .
* @ param $query
* A query string to append to the link .
* @ param $fragment
* A fragment identifier ( named anchor ) to append to the link .
* @ param $absolute
* Whether to force the output to be an absolute link ( beginning with http : ) .
* Useful for links that will be displayed outside the site , such as in an RSS feed .
2005-03-31 09:25:33 +00:00
* @ param $html
* Whether the title is HTML , or just plain - text .
2004-07-13 07:21:14 +00:00
* @ return
* an HTML string containing a link to the given path .
*/
2005-03-31 09:25:33 +00:00
function l ( $text , $path , $attributes = array (), $query = NULL , $fragment = NULL , $absolute = FALSE , $html = FALSE ) {
2005-05-14 09:23:47 +00:00
if ( $path == $_GET [ 'q' ]) {
2004-01-19 21:57:42 +00:00
if ( isset ( $attributes [ 'class' ])) {
$attributes [ 'class' ] .= ' active' ;
}
else {
$attributes [ 'class' ] = 'active' ;
}
}
2005-03-31 09:25:33 +00:00
return '<a href="' . check_url ( url ( $path , $query , $fragment , $absolute )) . '"' . drupal_attributes ( $attributes ) . '>' . ( $html ? $text : check_plain ( $text )) . '</a>' ;
2002-04-20 11:52:50 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Perform end - of - request tasks .
*
* This function sets the page cache if appropriate , and allows modules to
* react to the closing of the page by calling hook_exit () .
*/
2003-05-18 09:48:49 +00:00
function drupal_page_footer () {
2004-07-13 07:21:14 +00:00
if ( variable_get ( 'cache' , 0 )) {
2002-01-05 16:28:34 +00:00
page_set_cache ();
2001-12-01 15:20:48 +00:00
}
2003-01-26 13:22:02 +00:00
2004-07-13 07:21:14 +00:00
module_invoke_all ( 'exit' );
2001-12-01 15:20:48 +00:00
}
2004-02-12 19:37:04 +00:00
/**
2004-07-13 07:21:14 +00:00
* Form an associative array from a linear array .
2004-02-12 19:37:04 +00:00
*
2004-07-13 07:21:14 +00:00
* This function walks through the provided array and constructs an associative
* array out of it . The keys of the resulting array will be the values of the
* input array . The values will be the same as the keys unless a function is
* specified , in which case the output of the function is used for the values
* instead .
*
* @ param $array
* A linear array .
* @ param $function
* The name of a function to apply to all values before output .
* @ result
* An associative array .
2004-02-12 19:37:04 +00:00
*/
function drupal_map_assoc ( $array , $function = NULL ) {
if ( ! isset ( $function )) {
$result = array ();
foreach ( $array as $value ) {
$result [ $value ] = $value ;
}
return $result ;
}
elseif ( function_exists ( $function )) {
$result = array ();
foreach ( $array as $value ) {
$result [ $value ] = $function ( $value );
}
return $result ;
}
}
The Input formats - filter patch has landed. I still need to make update instructions for modules and update the hook docs.
Here's an overview of the changes:
1) Multiple Input formats: they are complete filter configurations (what filters to use, in what order and with which settings). Input formats are admin-definable, and usage of them is role-dependant. For example, you can set it up so that regular users can only use limited HTML, while admins can free HTML without any tag limitations.
The input format can be chosen per content item (nodes, comments, blocks, ...) when you add/edit them. If only a single format is available, there is no choice, and nothing changes with before.
The default install (and the upgrade) contains a basic set of formats which should satisfy the average user's needs.
2) Filters have toggles
Because now you might want to enable a filter only on some input formats, an explicit toggle is provided by the filter system. Modules do not need to worry about it and filters that still have their own on/off switch should get rid of it.
3) Multiple filters per module
This was necessary to accomodate the next change, and it's also a logical extension of the filter system.
4) Embedded PHP is now a filter
Thanks to the multiple input formats, I was able to move the 'embedded PHP' feature from block.module, page.module and book.module into a simple filter which executes PHP code. This filter is part of filter.module, and by default there is an input format 'PHP', restricted to the administrator only, which contains this filter.
This change means that block.module now passes custom block contents through the filter system.
As well as from reducing code duplication and avoiding two type selectors for page/book nodes, you can now combine PHP code with other filters.
5) User-supplied PHP code now requires <?php ?> tags.
This is required for teasers to work with PHP code. Because PHP evaluation is now just another step in the filter process, we can't do this. Also, because teasers are generated before filtering, this would result in errors when the teaser generation would cut off a piece of PHP code.
Also, regular PHP syntax explicitly includes the <?php ?> tags for PHP files, so it makes sense to use the same convention for embedded PHP in Drupal.
6) Filter caching was added.
Benchmarking shows that even for a simple setup (basic html filtering + legacy URL rewriting), filtercache can offer speedups. Unlike the old filtercache, this uses the normal cache table.
7) Filtertips were moved from help into a hook_filter_tips(). This was required to accomodate the fact that there are multiple filters per module, and that filter settings are format dependant. Shoehorning filter tips into _help was ugly and silly. The display of the filter tips is done through the input format selector, so filter_tips_short() no longer exists.
8) A more intelligent linebreak convertor was added, which doesn't stop working if you use block-level tags and which adds <p> tags.
2004-08-10 18:34:29 +00:00
/**
2004-09-09 05:51:08 +00:00
* Evaluate a string of PHP code .
The Input formats - filter patch has landed. I still need to make update instructions for modules and update the hook docs.
Here's an overview of the changes:
1) Multiple Input formats: they are complete filter configurations (what filters to use, in what order and with which settings). Input formats are admin-definable, and usage of them is role-dependant. For example, you can set it up so that regular users can only use limited HTML, while admins can free HTML without any tag limitations.
The input format can be chosen per content item (nodes, comments, blocks, ...) when you add/edit them. If only a single format is available, there is no choice, and nothing changes with before.
The default install (and the upgrade) contains a basic set of formats which should satisfy the average user's needs.
2) Filters have toggles
Because now you might want to enable a filter only on some input formats, an explicit toggle is provided by the filter system. Modules do not need to worry about it and filters that still have their own on/off switch should get rid of it.
3) Multiple filters per module
This was necessary to accomodate the next change, and it's also a logical extension of the filter system.
4) Embedded PHP is now a filter
Thanks to the multiple input formats, I was able to move the 'embedded PHP' feature from block.module, page.module and book.module into a simple filter which executes PHP code. This filter is part of filter.module, and by default there is an input format 'PHP', restricted to the administrator only, which contains this filter.
This change means that block.module now passes custom block contents through the filter system.
As well as from reducing code duplication and avoiding two type selectors for page/book nodes, you can now combine PHP code with other filters.
5) User-supplied PHP code now requires <?php ?> tags.
This is required for teasers to work with PHP code. Because PHP evaluation is now just another step in the filter process, we can't do this. Also, because teasers are generated before filtering, this would result in errors when the teaser generation would cut off a piece of PHP code.
Also, regular PHP syntax explicitly includes the <?php ?> tags for PHP files, so it makes sense to use the same convention for embedded PHP in Drupal.
6) Filter caching was added.
Benchmarking shows that even for a simple setup (basic html filtering + legacy URL rewriting), filtercache can offer speedups. Unlike the old filtercache, this uses the normal cache table.
7) Filtertips were moved from help into a hook_filter_tips(). This was required to accomodate the fact that there are multiple filters per module, and that filter settings are format dependant. Shoehorning filter tips into _help was ugly and silly. The display of the filter tips is done through the input format selector, so filter_tips_short() no longer exists.
8) A more intelligent linebreak convertor was added, which doesn't stop working if you use block-level tags and which adds <p> tags.
2004-08-10 18:34:29 +00:00
*
2004-09-09 05:51:08 +00:00
* This is a wrapper around PHP ' s eval () . It uses output buffering to capture both
* returned and printed text . Unlike eval (), we require code to be surrounded by
* < ? php ?> tags; in other words, we evaluate the code as if it were a stand-alone
* PHP file .
*
2004-09-16 16:12:21 +00:00
* Using this wrapper also ensures that the PHP code which is evaluated can not
* overwrite any variables in the calling code , unlike a regular eval () call .
*
2004-09-09 05:51:08 +00:00
* @ param $code
* The code to evaluate .
* @ return
* A string containing the printed output of the code , followed by the returned
* output of the code .
The Input formats - filter patch has landed. I still need to make update instructions for modules and update the hook docs.
Here's an overview of the changes:
1) Multiple Input formats: they are complete filter configurations (what filters to use, in what order and with which settings). Input formats are admin-definable, and usage of them is role-dependant. For example, you can set it up so that regular users can only use limited HTML, while admins can free HTML without any tag limitations.
The input format can be chosen per content item (nodes, comments, blocks, ...) when you add/edit them. If only a single format is available, there is no choice, and nothing changes with before.
The default install (and the upgrade) contains a basic set of formats which should satisfy the average user's needs.
2) Filters have toggles
Because now you might want to enable a filter only on some input formats, an explicit toggle is provided by the filter system. Modules do not need to worry about it and filters that still have their own on/off switch should get rid of it.
3) Multiple filters per module
This was necessary to accomodate the next change, and it's also a logical extension of the filter system.
4) Embedded PHP is now a filter
Thanks to the multiple input formats, I was able to move the 'embedded PHP' feature from block.module, page.module and book.module into a simple filter which executes PHP code. This filter is part of filter.module, and by default there is an input format 'PHP', restricted to the administrator only, which contains this filter.
This change means that block.module now passes custom block contents through the filter system.
As well as from reducing code duplication and avoiding two type selectors for page/book nodes, you can now combine PHP code with other filters.
5) User-supplied PHP code now requires <?php ?> tags.
This is required for teasers to work with PHP code. Because PHP evaluation is now just another step in the filter process, we can't do this. Also, because teasers are generated before filtering, this would result in errors when the teaser generation would cut off a piece of PHP code.
Also, regular PHP syntax explicitly includes the <?php ?> tags for PHP files, so it makes sense to use the same convention for embedded PHP in Drupal.
6) Filter caching was added.
Benchmarking shows that even for a simple setup (basic html filtering + legacy URL rewriting), filtercache can offer speedups. Unlike the old filtercache, this uses the normal cache table.
7) Filtertips were moved from help into a hook_filter_tips(). This was required to accomodate the fact that there are multiple filters per module, and that filter settings are format dependant. Shoehorning filter tips into _help was ugly and silly. The display of the filter tips is done through the input format selector, so filter_tips_short() no longer exists.
8) A more intelligent linebreak convertor was added, which doesn't stop working if you use block-level tags and which adds <p> tags.
2004-08-10 18:34:29 +00:00
*/
function drupal_eval ( $code ) {
ob_start ();
print eval ( '?>' . $code );
2004-08-21 16:44:05 +00:00
$output = ob_get_contents ();
ob_end_clean ();
return $output ;
The Input formats - filter patch has landed. I still need to make update instructions for modules and update the hook docs.
Here's an overview of the changes:
1) Multiple Input formats: they are complete filter configurations (what filters to use, in what order and with which settings). Input formats are admin-definable, and usage of them is role-dependant. For example, you can set it up so that regular users can only use limited HTML, while admins can free HTML without any tag limitations.
The input format can be chosen per content item (nodes, comments, blocks, ...) when you add/edit them. If only a single format is available, there is no choice, and nothing changes with before.
The default install (and the upgrade) contains a basic set of formats which should satisfy the average user's needs.
2) Filters have toggles
Because now you might want to enable a filter only on some input formats, an explicit toggle is provided by the filter system. Modules do not need to worry about it and filters that still have their own on/off switch should get rid of it.
3) Multiple filters per module
This was necessary to accomodate the next change, and it's also a logical extension of the filter system.
4) Embedded PHP is now a filter
Thanks to the multiple input formats, I was able to move the 'embedded PHP' feature from block.module, page.module and book.module into a simple filter which executes PHP code. This filter is part of filter.module, and by default there is an input format 'PHP', restricted to the administrator only, which contains this filter.
This change means that block.module now passes custom block contents through the filter system.
As well as from reducing code duplication and avoiding two type selectors for page/book nodes, you can now combine PHP code with other filters.
5) User-supplied PHP code now requires <?php ?> tags.
This is required for teasers to work with PHP code. Because PHP evaluation is now just another step in the filter process, we can't do this. Also, because teasers are generated before filtering, this would result in errors when the teaser generation would cut off a piece of PHP code.
Also, regular PHP syntax explicitly includes the <?php ?> tags for PHP files, so it makes sense to use the same convention for embedded PHP in Drupal.
6) Filter caching was added.
Benchmarking shows that even for a simple setup (basic html filtering + legacy URL rewriting), filtercache can offer speedups. Unlike the old filtercache, this uses the normal cache table.
7) Filtertips were moved from help into a hook_filter_tips(). This was required to accomodate the fact that there are multiple filters per module, and that filter settings are format dependant. Shoehorning filter tips into _help was ugly and silly. The display of the filter tips is done through the input format selector, so filter_tips_short() no longer exists.
8) A more intelligent linebreak convertor was added, which doesn't stop working if you use block-level tags and which adds <p> tags.
2004-08-10 18:34:29 +00:00
}
2004-11-24 22:44:01 +00:00
/**
* Returns the path to a system item ( module , theme , etc . ) .
*
* @ param $type
* The type of the item ( i . e . theme , theme_engine , module ) .
* @ param $name
* The name of the item for which the path is requested .
*
* @ return
* The path to the requested item .
*/
function drupal_get_path ( $type , $name ) {
return dirname ( drupal_get_filename ( $type , $name ));
}
2006-02-02 12:44:57 +00:00
/**
* Returns the base URL path of the Drupal installation .
* At the very least , this will always default to /.
*/
function base_path () {
return $GLOBALS [ 'base_path' ];
}
2005-02-04 20:14:05 +00:00
/**
* Provide a substitute clone () function for PHP4 .
*/
2005-06-22 20:19:58 +00:00
function drupal_clone ( $object ) {
return version_compare ( phpversion (), '5.0' ) < 0 ? $object : clone ( $object );
2005-02-04 20:14:05 +00:00
}
2005-05-31 21:14:27 +00:00
/**
* Add a < link > tag to the page ' s HEAD .
*/
function drupal_add_link ( $attributes ) {
2005-06-05 19:10:53 +00:00
drupal_set_html_head ( '<link' . drupal_attributes ( $attributes ) . " /> \n " );
2005-05-31 21:14:27 +00:00
}
2005-05-24 06:00:22 +00:00
/**
* Add a JavaScript file to the output .
*
* The first time this function is invoked per page request ,
* it adds " misc/drupal.js " to the output . Other scripts
* depends on the 'killswitch' inside it .
*/
2006-03-15 08:46:57 +00:00
function drupal_add_js ( $file , $nocache = FALSE ) {
2005-05-24 06:00:22 +00:00
static $sent = array ();
2006-01-29 07:36:29 +00:00
2006-03-15 08:46:57 +00:00
$postfix = $nocache ? '?' . time () : '' ;
2005-05-24 06:00:22 +00:00
if ( ! isset ( $sent [ 'misc/drupal.js' ])) {
2006-03-15 08:46:57 +00:00
drupal_set_html_head ( '<script type="text/javascript" src="' . base_path () . 'misc/drupal.js' . $postfix . '"></script>' );
2005-05-24 06:00:22 +00:00
$sent [ 'misc/drupal.js' ] = true ;
}
if ( ! isset ( $sent [ $file ])) {
2006-03-15 08:46:57 +00:00
drupal_set_html_head ( '<script type="text/javascript" src="' . check_url ( base_path () . $file ) . $postfix . '"></script>' );
2005-05-24 06:00:22 +00:00
$sent [ $file ] = true ;
}
}
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
/**
* Generates a Javascript call , while importing the arguments as is .
* PHP arrays are turned into JS objects to preserve keys . This means the array
* keys must conform to JS ' s member naming rules .
*
* @ param $function
* The name of the function to call .
* @ param $arguments
* An array of arguments .
*/
function drupal_call_js ( $function ) {
$arguments = func_get_args ();
array_shift ( $arguments );
$args = array ();
foreach ( $arguments as $arg ) {
$args [] = drupal_to_js ( $arg );
}
$output = '<script type="text/javascript">' . $function . '(' . implode ( ', ' , $args ) . ');</script>' ;
return $output ;
}
/**
* Converts a PHP variable into its Javascript equivalent .
2006-02-05 19:04:58 +00:00
*
* We use HTML - safe strings , i . e . with < , > and & escaped .
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
*/
function drupal_to_js ( $var ) {
switch ( gettype ( $var )) {
case 'boolean' :
2006-03-10 13:08:05 +00:00
return $var ? 'true' : 'false' ; // Lowercase necessary!
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
case 'integer' :
case 'double' :
return $var ;
case 'resource' :
case 'string' :
2006-02-05 19:04:58 +00:00
return '"' . str_replace ( array ( " \r " , " \n " , " < " , " > " , " & " ),
array ( '\r' , '\n' , '\x3c' , '\x3e' , '\x26' ),
addslashes ( $var )) . '"' ;
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
case 'array' :
2006-02-05 19:04:58 +00:00
if ( array_keys ( $var ) === range ( 0 , sizeof ( $var ) - 1 )) {
$output = array ();
foreach ( $var as $v ) {
$output [] = drupal_to_js ( $v );
}
return '[ ' . implode ( ', ' , $output ) . ' ]' ;
}
2006-02-10 05:25:57 +00:00
// Fall through
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
case 'object' :
$output = array ();
foreach ( $var as $k => $v ) {
2006-03-10 17:06:48 +00:00
$output [] = drupal_to_js ( strval ( $k )) . ': ' . drupal_to_js ( $v );
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
}
return '{ ' . implode ( ', ' , $output ) . ' }' ;
default :
return 'null' ;
}
}
2005-10-21 11:14:55 +00:00
/**
* Wrapper around urlencode () which avoids Apache quirks .
*
2005-12-22 22:58:12 +00:00
* Should be used when placing arbitrary data in an URL . Note that Drupal paths
* are urlencoded () when passed through url () and do not require urlencoding ()
* of individual components .
2005-10-21 11:14:55 +00:00
*
* @ param $text
* String to encode
*/
function drupal_urlencode ( $text ) {
2005-12-22 22:58:12 +00:00
return str_replace ( '%2F' , '/' , urlencode ( $text ));
2005-10-21 11:14:55 +00:00
}
2005-08-17 15:01:14 +00:00
/**
2005-08-17 19:14:08 +00:00
* Performs one or more XML - RPC request ( s ) .
*
* @ param $url
* An absolute URL of the XML - RPC endpoint .
* Example :
* http :// www . domain . com / xmlrpc . php
* @ param ...
* For one request :
* The method name followed by a variable number of arguments to the method .
* For multiple requests ( system . multicall ) :
* An array of call arrays . Each call array follows the pattern of the single
* request : method name followed by the arguments to the method .
* @ return
* For one request :
* Either the return value of the method on success , or FALSE .
* If FALSE is returned , see xmlrpc_errno () and xmlrpc_error_msg () .
* For multiple requests :
* An array of results . Each result will either be the result
* returned by the method called , or an xmlrpc_error object if the call
* failed . See xmlrpc_error () .
*/
2005-08-17 15:01:14 +00:00
function xmlrpc ( $url ) {
require_once './includes/xmlrpc.inc' ;
$args = func_get_args ();
return call_user_func_array ( '_xmlrpc' , $args );
}
2005-06-22 20:19:58 +00:00
function _drupal_bootstrap_full () {
static $called ;
2005-07-27 01:58:43 +00:00
global $locale ;
2003-03-17 07:01:12 +00:00
2005-06-22 20:19:58 +00:00
if ( $called ) {
return ;
}
$called = 1 ;
require_once './includes/theme.inc' ;
require_once './includes/pager.inc' ;
require_once './includes/menu.inc' ;
require_once './includes/tablesort.inc' ;
require_once './includes/file.inc' ;
2005-07-25 20:38:30 +00:00
require_once './includes/unicode.inc' ;
2005-06-22 20:19:58 +00:00
require_once './includes/image.inc' ;
2005-10-07 06:11:12 +00:00
require_once './includes/form.inc' ;
2005-06-22 20:19:58 +00:00
// Set the Drupal custom error handler.
set_error_handler ( 'error_handler' );
// Emit the correct charset HTTP header.
drupal_set_header ( 'Content-Type: text/html; charset=utf-8' );
2005-07-25 20:40:35 +00:00
// Detect string handling method
2005-07-27 01:58:43 +00:00
unicode_check ();
2005-06-22 20:19:58 +00:00
// Initialize all enabled modules.
module_init ();
2005-11-29 20:17:10 +00:00
// Undo magic quotes
2005-06-22 20:19:58 +00:00
fix_gpc_magic ();
// Initialize the localization system.
$locale = locale_initialize ();
2003-11-18 19:44:36 +00:00
}
2006-01-23 07:54:08 +00:00
/**
* Store the current page in the cache .
*
* We try to store a gzipped version of the cache . This requires the
* PHP zlib extension ( http :// php . net / manual / en / ref . zlib . php ) .
* Presence of the extension is checked by testing for the function
* gzencode . There are two compression algorithms : gzip and deflate .
* The majority of all modern browsers support gzip or both of them .
* We thus only deal with the gzip variant and unzip the cache in case
* the browser does not accept gzip encoding .
*
* @ see drupal_page_header
*/
function page_set_cache () {
global $user , $base_url ;
if ( ! $user -> uid && $_SERVER [ 'REQUEST_METHOD' ] == 'GET' ) {
// This will fail in some cases, see page_get_cache() for the explanation.
if ( $data = ob_get_contents ()) {
$cache = TRUE ;
if ( function_exists ( 'gzencode' )) {
// We do not store the data in case the zlib mode is deflate.
// This should be rarely happening.
if ( zlib_get_coding_type () == 'deflate' ) {
$cache = FALSE ;
}
else if ( zlib_get_coding_type () == FALSE ) {
$data = gzencode ( $data , 9 , FORCE_GZIP );
}
// The remaining case is 'gzip' which means the data is
// already compressed and nothing left to do but to store it.
}
ob_end_flush ();
if ( $cache && $data ) {
cache_set ( $base_url . request_uri (), $data , CACHE_TEMPORARY , drupal_get_headers ());
}
}
}
2006-03-01 21:30:17 +00:00
}