2001-12-01 15:20:48 +00:00
< ? php
2003-12-13 14:59:55 +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 .
*/
2004-01-06 19:52:14 +00:00
/**
* @ name Page title
2003-12-08 06:32:19 +00:00
*
* Functions to get and set the title of the current page .
* @ {
*/
2003-11-23 10:41:04 +00:00
function drupal_set_title ( $title = NULL ) {
static $stored_title ;
if ( isset ( $title )) {
2004-08-06 20:15:32 +00:00
$stored_title = $title ;
2003-11-23 10:41:04 +00:00
}
return $stored_title ;
}
function drupal_get_title () {
$title = drupal_set_title ();
if ( ! isset ( $title )) {
$title = menu_get_active_title ();
}
return $title ;
}
2004-01-06 19:52:14 +00:00
/* @} */
2003-11-23 10:41:04 +00:00
/**
2004-01-06 19:52:14 +00:00
* @ name Page breadcrumbs
2003-12-08 06:32:19 +00:00
*
* Functions to get and set the breadcrumb trail of the current page .
* @ {
*/
2004-01-06 19:52:14 +00:00
/**
* @ param $breadcrumb Array of links , starting with " home " and proceeding up
* to but not including the current page .
*/
2003-11-23 10:41:04 +00:00
function drupal_set_breadcrumb ( $breadcrumb = NULL ) {
static $stored_breadcrumb ;
if ( isset ( $breadcrumb )) {
$stored_breadcrumb = $breadcrumb ;
}
return $stored_breadcrumb ;
}
function drupal_get_breadcrumb () {
$breadcrumb = drupal_set_breadcrumb ();
if ( ! isset ( $breadcrumb )) {
$breadcrumb = menu_get_active_breadcrumb ();
}
return $breadcrumb ;
}
2004-01-06 19:52:14 +00:00
/* @} */
2003-11-23 10:41:04 +00:00
2004-01-14 22:30:09 +00:00
/**
* @ name HTML head contents
*
* Set and get output that should be in the \ < head\ > tag .
* @ {
*/
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 ;
}
function drupal_get_html_head () {
global $base_url ;
2004-01-29 06:47:19 +00:00
$output = " <meta http-equiv= \" Content-Type \" content= \" text/html; charset=utf-8 \" /> \n " ;
2004-01-14 22:30:09 +00:00
$output .= " <base href= \" $base_url / \" /> \n " ;
2004-01-29 06:47:19 +00:00
$output .= " <style type= \" text/css \" media= \" all \" > \n " ;
2004-01-14 22:30:09 +00:00
$output .= " @import url(misc/drupal.css); \n " ;
$output .= " </style> \n " ;
return $output . drupal_set_html_head ();
}
/* @} */
2003-09-30 17:01:34 +00:00
/**
2004-02-08 17:12:44 +00:00
* @ name URL path alias
2004-01-06 19:52:14 +00:00
*
2004-02-08 17:12:44 +00:00
* Functions to handle path aliases .
2003-12-08 06:32:19 +00:00
*/
2004-07-13 07:21:14 +00:00
function drupal_get_path_map ( $action = '' ) {
2003-12-13 14:59:55 +00:00
static $map = NULL ;
2003-09-30 17:01:34 +00:00
2004-07-13 07:21:14 +00:00
if ( $action == 'rebuild' ) {
2003-10-03 14:10:05 +00:00
$map = NULL ;
}
2003-12-13 14:59:55 +00:00
if ( is_null ( $map )) {
2004-01-25 09:09:00 +00:00
$map = array (); // make $map non-null in case no aliases are defined
2004-07-13 07:21:14 +00:00
$result = db_query ( 'SELECT * FROM {url_alias}' );
2003-09-30 17:01:34 +00:00
while ( $data = db_fetch_object ( $result )) {
2003-10-01 05:18:03 +00:00
$map [ $data -> dst ] = $data -> src ;
2003-09-30 17:01:34 +00:00
}
}
return $map ;
}
2003-10-03 14:10:05 +00:00
function drupal_rebuild_path_map () {
2004-07-13 07:21:14 +00:00
drupal_get_path_map ( 'rebuild' );
2003-10-03 14:10:05 +00:00
}
2004-01-06 19:52:14 +00:00
/**
2004-07-13 07:21:14 +00:00
* Given an internal Drupal path , return the alias set by the administrator .
2004-01-06 19:52:14 +00:00
*/
2004-02-08 17:12:44 +00:00
function drupal_get_path_alias ( $path ) {
if (( $map = drupal_get_path_map ()) && ( $newpath = array_search ( $path , $map ))) {
return $newpath ;
}
2004-07-13 07:21:14 +00:00
elseif ( function_exists ( 'conf_url_rewrite' )) {
2004-02-08 17:12:44 +00:00
return conf_url_rewrite ( $path , 'outgoing' );
}
2004-06-01 21:58:46 +00:00
else {
// No alias found. Return the normal path.
return $path ;
}
2004-02-08 17:12:44 +00:00
}
/**
2004-07-13 07:21:14 +00:00
* Given a path alias , return the internal path it represents .
2004-02-08 17:12:44 +00:00
*/
function drupal_get_normal_path ( $path ) {
if (( $map = drupal_get_path_map ()) && isset ( $map [ $path ])) {
return $map [ $path ];
}
2004-07-13 07:21:14 +00:00
elseif ( function_exists ( 'conf_url_rewrite' )) {
2004-02-08 17:12:44 +00:00
return conf_url_rewrite ( $path , 'incoming' );
}
else {
return $path ;
}
}
/* @} */
2004-01-06 19:52:14 +00:00
2004-01-14 22:30:09 +00:00
/**
* @ name HTTP headers
*
* Functions to get and set the HTTP headers of the current page .
* @ {
*/
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.
// This can cause header("") to get called when serving the page later, which
// 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
}
function drupal_get_headers () {
return drupal_set_header ();
}
/* @} */
2004-02-08 17:12:44 +00:00
/**
* @ name HTTP handling
*
* Functions to properly handle HTTP responses .
* @ {
*/
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
*
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 ) .
2004-01-06 19:52:14 +00:00
*/
2004-07-11 07:31:11 +00:00
function drupal_goto ( $path = '' , $query = NULL , $fragment = NULL ) {
// Translate & to simply & in the absolute URL.
$url = str_replace ( '&' , '&' , url ( $path , $query , $fragment , TRUE ));
2004-01-06 19:52:14 +00:00
2004-07-11 07:31:11 +00:00
if ( ini_get ( 'session.use_trans_sid' ) && session_id () && ! strstr ( $url , session_id ())) {
$sid = session_name () . '=' . session_id ();
2003-10-03 14:10:05 +00:00
2004-07-11 07:31:11 +00:00
if ( strstr ( $url , '?' ) && ! strstr ( $url , $sid )) {
$url = $url . '&' . $sid ;
2004-01-06 19:52:14 +00:00
}
else {
2004-07-11 07:31:11 +00:00
$url = $url . '?' . $sid ;
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 ();
}
/**
* Generates a 404 error if the request can not be handled .
*/
2003-12-16 21:06:34 +00:00
function drupal_not_found () {
2004-04-21 13:56:38 +00:00
header ( 'HTTP/1.0 404 Not Found' );
2004-07-13 07:21:14 +00:00
watchdog ( 'httpd' , t ( '404 error: "%page" not found' , array ( '%page' => check_query ( $_GET [ 'q' ]))));
2003-12-16 21:06:34 +00:00
$path = drupal_get_normal_path ( variable_get ( 'site_404' , '' ));
2004-07-02 18:46:42 +00:00
$status = MENU_NOT_FOUND ;
2003-12-16 21:06:34 +00:00
if ( $path ) {
menu_set_active_item ( $path );
2004-04-21 13:56:38 +00:00
$status = menu_execute_active_handler ();
2003-12-16 21:06:34 +00:00
}
2004-04-21 13:56:38 +00:00
if ( $status != MENU_FOUND ) {
2004-03-08 18:35:04 +00:00
print theme ( 'page' , '' , t ( 'Page not found' ));
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 () {
header ( 'HTTP/1.0 403 Forbidden' );
$path = drupal_get_normal_path ( variable_get ( 'site_403' , '' ));
2004-07-02 18:46:42 +00:00
$status = MENU_NOT_FOUND ;
2004-04-21 13:56:38 +00:00
if ( $path ) {
menu_set_active_item ( $path );
$status = menu_execute_active_handler ();
}
if ( $status != MENU_FOUND ) {
print theme ( 'page' , message_access (), t ( 'Access denied' ));
}
}
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 ) {
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' :
$fp = @ fsockopen ( $uri [ 'host' ], ( $uri [ 'port' ] ? $uri [ 'port' ] : 80 ), $errno , $errstr , 15 );
break ;
case 'https' :
2004-07-13 07:21:14 +00:00
// Note: Only works for PHP 4.3 compiled with OpenSSL.
$fp = @ fsockopen ( 'ssl://' . $uri [ 'host' ], ( $uri [ 'port' ] ? $uri [ 'port' ] : 443 ), $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.
2004-01-07 19:52:10 +00:00
$path = $uri [ 'path' ] ? $uri [ 'path' ] : '/' ;
if ( $uri [ 'query' ]) {
2004-07-13 07:21:14 +00:00
$path .= '?' . $uri [ 'query' ];
2004-01-07 19:52:10 +00:00
}
2004-07-13 07:21:14 +00:00
// Create http request.
2004-01-07 19:52:10 +00:00
$defaults = array (
2004-07-13 07:21:14 +00:00
'Host' => 'Host: ' . $uri [ 'host' ],
2004-01-07 20:43:26 +00:00
'User-Agent' => 'User-Agent: Drupal (+http://www.drupal.org/)' ,
'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 = '' ;
2004-04-21 19:43:23 +00:00
while ( ! feof ( $fp ) && $data = fread ( $fp , 1024 )) {
2004-04-27 18:17:17 +00:00
$response .= $data ;
2004-01-07 19:52:10 +00:00
}
fclose ( $fp );
// Parse response.
2004-06-21 20:14:41 +00:00
list ( $headers , $result -> data ) = explode ( " \r \n \r \n " , $response , 2 );
$headers = preg_split ( " / \r \n | \n | \r / " , $headers );
list ( $protocol , $code , $text ) = explode ( ' ' , trim ( array_shift ( $headers )), 3 );
2004-01-07 19:52:10 +00:00
$result -> headers = array ();
// Parse headers.
2004-06-21 20:14:41 +00:00
while ( $line = trim ( array_shift ( $headers ))) {
2004-01-07 19:52:10 +00:00
list ( $header , $value ) = explode ( ':' , $line , 2 );
$result -> headers [ $header ] = trim ( $value );
}
$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
// the base code in their class:
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-01-06 19:52:14 +00:00
/* @} */
2003-12-16 21:06:34 +00:00
2004-07-13 07:21:14 +00:00
/**
* Log errors in the database rather than displaying them to the user .
*/
2001-12-01 15:20:48 +00:00
function error_handler ( $errno , $message , $filename , $line , $variables ) {
2004-07-13 07:21:14 +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' );
$entry = $types [ $errno ] . ': ' . $message . ' in ' . $filename . ' on line ' . $line . '.' ;
2003-04-21 12:36:09 +00:00
if ( $errno & E_ALL ^ E_NOTICE ) {
2004-06-02 19:01:40 +00:00
watchdog ( 'error' , t ( '%error: %message in %file on line %line.' , array ( '%error' => $types [ $errno ], '%message' => $message , '%file' => $filename , '%line' => $line )));
2003-12-13 14:59:55 +00:00
if ( error_reporting ()) {
2004-07-13 07:21:14 +00:00
print '<pre>' . $entry . '</pre>' ;
2003-12-13 14:59:55 +00:00
}
2001-12-01 15:20:48 +00:00
}
}
2003-12-13 14:59:55 +00:00
function _fix_gpc_magic ( & $item , $key ) {
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 Conversion
*
* Converts data structures to a different type .
* @ {
*/
2004-07-13 07:21:14 +00:00
/**
* Convert an associative array to an anonymous object .
*/
2003-12-13 14:59:55 +00:00
function array2object ( $array ) {
if ( is_array ( $array )) {
foreach ( $array as $key => $value ) {
2001-12-30 16:16:38 +00:00
$object -> $key = $value ;
}
}
else {
2003-12-13 14:59:55 +00:00
$object = $array ;
2001-12-30 16:16:38 +00:00
}
return $object ;
}
2004-07-13 07:21:14 +00:00
/**
* Convert an object to an associative array .
*/
2003-12-13 14:59:55 +00:00
function object2array ( $object ) {
if ( is_object ( $object )) {
foreach ( $object as $key => $value ) {
2001-12-30 16:16:38 +00:00
$array [ $key ] = $value ;
}
}
else {
2003-12-13 14:59:55 +00:00
$array = $object ;
2001-12-30 16:16:38 +00:00
}
return $array ;
}
2004-01-06 19:52:14 +00:00
/* @} */
2001-12-30 16:16:38 +00:00
2004-01-06 19:52:14 +00:00
/**
* @ name Messages
*
* Frequently used messages .
* @ {
*/
2004-07-13 07:21:14 +00:00
/**
* Return a string with an " access denied " message .
*
* Always consider whether to use drupal_access_denied () instead to return a
* proper ( and customizable ) 403 error .
*/
2001-12-01 15:20:48 +00:00
function message_access () {
2004-07-13 07:21:14 +00:00
return t ( 'You are not authorized to access this page.' );
2001-12-01 15:20:48 +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-01-06 19:52:14 +00:00
/* @} */
2001-12-01 15:20:48 +00:00
2004-07-13 07:21:14 +00:00
/**
* Initialize the localization system .
*/
2001-12-27 15:27:44 +00:00
function locale_init () {
global $languages , $user ;
2003-03-04 15:10:37 +00:00
if ( $user -> uid && $languages [ $user -> language ]) {
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 .
* This makes it easier for translators . We are unafraid of HTML markup within
* translation strings if necessary . The suggested syntax for a link embedded
* within a translation string is for example :
2004-07-13 07:21:14 +00:00
* @ verbatim
* $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' )));
* @ endverbatim
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
* A string containing the english string to translate .
* @ param $args
* An associative array of replacements to make after translation . Incidences
* of any key in this array are replaces with the corresponding value .
* @ 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 ) {
2001-12-27 15:27:44 +00:00
global $languages ;
2002-04-24 20:55:20 +00:00
2004-07-13 07:21:14 +00:00
$string = ( $languages && module_exist ( 'locale' ) ? locale ( $string ) : $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-07-13 07:21:14 +00:00
/**
* Encode special characters in a string for display as HTML .
*
* Note that we 'd like to use htmlspecialchars($input, $quotes, ' utf - 8 ' )
* as outlined in the PHP manual , but we can 't because there' s a bug in
* PHP < 4.3 that makes it mess up multibyte charsets if we specify the
* charset . This will be changed later once we make PHP 4.3 a requirement .
*/
2003-06-12 17:24:06 +00:00
function drupal_specialchars ( $input , $quotes = ENT_NOQUOTES ) {
2003-06-19 17:26:27 +00:00
return htmlspecialchars ( $input , $quotes );
2003-06-05 18:09:39 +00:00
}
2004-01-06 19:52:14 +00:00
/**
* @ name Validation
*
* Functions to validate user input .
2004-02-08 17:12:44 +00:00
* @ {
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
* A string containing an email 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-07-13 07:21:14 +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 ) {
2004-03-21 10:28:10 +00:00
if ( $absolute ) {
2004-03-27 09:32:12 +00:00
return preg_match ( " /^(http|https|ftp): \ / \ /[a-z0-9 \ /:_ \ -_ \ . \ ?,~=#&]+ $ /i " , $url );
2004-03-21 10:28:10 +00:00
}
else {
2004-03-27 09:32:12 +00:00
return preg_match ( " /^[a-z0-9 \ /:_ \ -_ \ .,]+ $ /i " , $url );
2004-03-21 10:28:10 +00:00
}
2003-07-16 20:14:26 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Validate data input by a user .
*
* Ensures that user data cannot be used to perform attacks on the site .
*
* @ param $data
* The input to check .
* @ return
* TRUE if the input data is acceptable .
*/
2004-01-06 19:52:14 +00:00
function valid_input_data ( $data ) {
if ( is_array ( $data ) || is_object ( $data )) {
2004-07-13 07:21:14 +00:00
// Form data can contain a number of nested arrays.
2004-01-06 19:52:14 +00:00
foreach ( $data as $key => $value ) {
2004-01-17 23:19:02 +00:00
if ( ! valid_input_data ( $key ) || ! valid_input_data ( $value )) {
2004-07-13 07:21:14 +00:00
return FALSE ;
2004-01-06 19:52:14 +00:00
}
}
}
else {
2004-07-13 07:21:14 +00:00
// Detect dangerous input data.
2004-01-06 19:52:14 +00:00
2004-07-13 07:21:14 +00:00
// Check strings:
$match = preg_match ( '/\Wjavascript\s*:/i' , $data );
$match += preg_match ( '/\Wexpression\s*\(/i' , $data );
$match += preg_match ( '/\Walert\s*\(/i' , $data );
2004-01-06 19:52:14 +00:00
2004-07-13 07:21:14 +00:00
// Check attributes:
2004-01-06 19:52:14 +00:00
$match += preg_match ( " / \ W(dynsrc|datasrc|data|lowsrc|on[a-z]+) \ s*=[^>]+?>/i " , $data );
2004-07-13 07:21:14 +00:00
// Check tags:
2004-01-06 19:52:14 +00:00
$match += preg_match ( " /< \ s*(applet|script|object|style|embed|form|blink|meta|html|frame|iframe|layer|ilayer|head|frameset|xml)/i " , $data );
if ( $match ) {
2004-06-02 19:01:40 +00:00
watchdog ( 'warning' , t ( 'terminated request because of suspicious input data: %data' , array ( '%data' => drupal_specialchars ( $data ))));
2004-07-13 07:21:14 +00:00
return FALSE ;
2004-01-06 19:52:14 +00:00
}
}
2004-07-13 07:21:14 +00:00
return TRUE ;
2004-01-06 19:52:14 +00:00
}
/* @} */
/**
* @ defgroup search Search interface
* @ {
*/
2004-07-13 07:21:14 +00:00
2002-03-05 20:15:17 +00:00
/**
* Format a single result entry of a search query :
*
2003-12-08 06:32:19 +00:00
* @ param $item a single search result as returned by < i > module </ i > _search of
2004-07-13 07:21:14 +00:00
* type array ( 'count' => ... , 'link' => ... , 'title' => ... , 'user' => ... ,
* 'date' => ... , 'keywords' => ... )
2003-12-08 06:32:19 +00:00
* @ param $type module type of this item
2002-03-05 20:15:17 +00:00
*/
2001-12-27 15:27:44 +00:00
function search_item ( $item , $type ) {
2002-04-27 13:19:37 +00:00
/*
2004-07-13 07:21:14 +00:00
** Modules may implement hook_search_item () hook in order to overwrite
2002-04-27 13:19:37 +00:00
** the default function to display search results .
*/
2004-07-13 07:21:14 +00:00
if ( module_hook ( $type , 'search_item' )) {
$output = module_invoke ( $type , 'search_item' , $item );
2002-04-27 13:19:37 +00:00
}
else {
2004-07-13 07:21:14 +00:00
$output = ' <dt class="title"><a href="' . $item [ 'link' ] . '">' . $item [ 'title' ] . '</a></dt>' ;
$output .= ' <dd class="small">' . t ( $type ) . ( $item [ 'user' ] ? ' - ' . $item [ 'user' ] : '' ) . '' . ( $item [ 'date' ] ? ' - ' . format_date ( $item [ 'date' ], 'small' ) : '' ) . '</dd>' ;
2002-04-27 13:19:37 +00:00
}
2001-12-27 15:27:44 +00:00
return $output ;
}
2002-03-05 20:15:17 +00:00
/**
* Render a generic search form .
*
* " Generic " means " universal usable " - that is , usable not only from
2004-06-21 20:05:37 +00:00
* 'site.com/search' , but also as a simple search box ( without " Restrict search
2003-12-08 06:32:19 +00:00
* to " , help text, etc) from theme's header etc. This means: provide options to
* only conditionally render certain parts of this form .
2002-03-05 20:15:17 +00:00
*
2003-12-08 06:32:19 +00:00
* @ param $action Form action . Defaults to 'site.com/search' .
* @ param $keys string containing keywords for the search .
* @ param $options != 0 : Render additional form fields / text ( " Restrict search
* to " , help text, etc).
2002-03-05 20:15:17 +00:00
*/
2003-06-30 19:18:47 +00:00
function search_form ( $action = NULL , $keys = NULL , $options = NULL ) {
2004-01-02 12:15:37 +00:00
$edit = $_POST [ 'edit' ];
2001-12-27 15:27:44 +00:00
if ( ! $action ) {
2004-07-13 07:21:14 +00:00
$action = url ( 'search' );
2001-12-27 15:27:44 +00:00
}
2004-07-13 07:21:14 +00:00
$output = ' <div class="search-form"><br /><input type="text" class="form-text" size="50" value="' . check_form ( $keys ) . '" name="keys" />' ;
$output .= ' <input type="submit" class="form-submit" value="' . t ( 'Search' ) . " \" /> \n " ;
2001-12-27 15:27:44 +00:00
2003-12-13 14:59:55 +00:00
if ( $options ) {
2004-07-13 07:21:14 +00:00
$output .= '<br />' ;
$output .= t ( 'Restrict search to' ) . ': ' ;
2001-12-27 15:27:44 +00:00
foreach ( module_list () as $name ) {
2004-07-13 07:21:14 +00:00
if ( module_hook ( $name , 'search' )) {
$output .= ' <input type="checkbox" name="edit[type][' . $name . ']" ' . ( $edit [ 'type' ][ $name ] ? ' checked="checked"' : '' ) . ' /> ' . t ( $name );
2001-12-27 15:27:44 +00:00
}
}
}
2004-08-06 20:18:25 +00:00
$output .= '</div>' ;
2001-12-27 15:27:44 +00:00
2004-07-13 07:21:14 +00:00
return form ( $output , 'post' , $action );
2001-12-27 15:27:44 +00:00
}
/*
2002-03-05 20:15:17 +00:00
* Collect the search results :
*/
2003-06-25 22:10:54 +00:00
function search_data ( $keys = NULL ) {
2004-07-13 07:21:14 +00:00
$edit = $_POST [ 'edit' ];
2004-04-12 08:27:57 +00:00
$output = '' ;
2001-12-27 15:27:44 +00:00
2003-01-09 20:06:00 +00:00
if ( isset ( $keys )) {
2001-12-27 15:27:44 +00:00
foreach ( module_list () as $name ) {
2004-07-13 07:21:14 +00:00
if ( module_hook ( $name , 'search' ) && ( ! $edit [ 'type' ] || $edit [ 'type' ][ $name ])) {
list ( $title , $results ) = module_invoke ( $name , 'search' , $keys );
2004-02-01 19:07:36 +00:00
if ( $results ) {
2004-07-13 07:21:14 +00:00
$output .= '<h2>' . $title . '</h2>' ;
$output .= '<dl class="search-results">' ;
2004-02-01 19:07:36 +00:00
foreach ( $results as $entry ) {
$output .= search_item ( $entry , $name );
}
2004-07-13 07:21:14 +00:00
$output .= '</dl>' ;
2001-12-27 15:27:44 +00:00
}
}
}
}
return $output ;
}
2002-03-05 20:15:17 +00:00
/**
* Display the search form and the resulting data .
*
2003-12-08 06:32:19 +00:00
* @ param $type If set , search only nodes of this type . Otherwise , search all
* types .
* @ param $action Form action . Defaults to 'site.com/search' .
* @ param $keys Query string . Defaults to global $keys .
* @ param $options != 0 : Render additional form fields / text ( " Restrict search
* to " , help text, etc).
2002-03-05 20:15:17 +00:00
*/
2003-06-30 19:18:47 +00:00
function search_type ( $type , $action = NULL , $keys = NULL , $options = NULL ) {
2004-07-13 07:21:14 +00:00
$_POST [ 'edit' ][ 'type' ][ $type ] = 'on' ;
2001-12-27 15:27:44 +00:00
2004-07-13 07:21:14 +00:00
return search_form ( $action , $keys , $options ) . '<br />' . search_data ( $keys );
2001-12-27 15:27:44 +00:00
}
2004-07-22 16:06:54 +00:00
/**
* @ } end of defgroup search
*/
2003-06-06 21:08:35 +00:00
2001-12-01 15:20:48 +00:00
function check_form ( $text ) {
2003-06-23 07:24:56 +00:00
return drupal_specialchars ( $text , ENT_QUOTES );
2001-12-01 15:20:48 +00:00
}
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
}
2004-02-08 17:12:44 +00:00
/**
* @ name Formatting
*
* Functions to format numbers , strings , dates , etc .
* @ {
*/
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 " ;
2004-07-13 07:21:14 +00:00
$output .= ' <title>' . drupal_specialchars ( strip_tags ( $title )) . " </title> \n " ;
$output .= ' <link>' . drupal_specialchars ( strip_tags ( $link )) . " </link> \n " ;
$output .= ' <description>' . drupal_specialchars ( strip_tags ( $description )) . " </description> \n " ;
$output .= ' <language>' . drupal_specialchars ( strip_tags ( $language )) . " </language> \n " ;
2002-04-27 13:19:37 +00:00
foreach ( $args as $key => $value ) {
2004-07-13 07:21:14 +00:00
$output .= ' <' . $key . '>' . drupal_specialchars ( strip_tags ( $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 " ;
2004-07-13 07:21:14 +00:00
$output .= ' <title>' . drupal_specialchars ( strip_tags ( $title )) . " </title> \n " ;
$output .= ' <link>' . drupal_specialchars ( strip_tags ( $link )) . " </link> \n " ;
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
$output .= ' <description>' . drupal_specialchars ( $description ) . " </description> \n " ;
2002-04-27 13:19:37 +00:00
foreach ( $args as $key => $value ) {
2004-07-13 07:21:14 +00:00
$output .= ' <' . $key . '>' . drupal_specialchars ( strip_tags ( $value )) . " </ $key > \n " ;
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-07-13 07:21:14 +00:00
return t ( $count == 1 ? $singular : $plural , array ( '%count' => $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' );
2001-12-01 15:20:48 +00:00
if ( $size > 1024 ) {
$size = round ( $size / 1024 , 2 );
2004-07-13 07:21:14 +00:00
$suffix = t ( 'KB' );
2001-12-01 15:20:48 +00:00
}
if ( $size > 1024 ) {
$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
* A PHP date format string as required by date () .
* @ 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 ) {
if ( $timezone === NULL ) {
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 ++ ) {
$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
}
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-02-08 17:12:44 +00:00
/**
2004-07-13 07:21:14 +00:00
* Format a username .
2004-02-08 17:12:44 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $object
* The user object to format , usually returned from user_load () .
* @ return
* A string containing an HTML link to the user ' s page if the passed object
* suggests that this is a site user . Otherwise , only the username is returned .
2004-02-08 17:12:44 +00:00
*/
2001-12-01 15:20:48 +00:00
function format_name ( $object ) {
if ( $object -> uid && $object -> name ) {
2004-07-13 07:21:14 +00:00
// Shorten the name when it is too long or it will break many tables.
2003-08-22 21:35:25 +00:00
if ( strlen ( $object -> name ) > 20 ) {
2004-07-13 07:21:14 +00:00
$name = truncate_utf8 ( $object -> name , 15 ) . '...' ;
2003-08-22 21:35:25 +00:00
}
else {
$name = $object -> name ;
}
2004-07-13 07:21:14 +00:00
$output = l ( $name , 'user/' . $object -> uid , array ( 'title' => t ( 'View user profile.' )));
2001-12-01 15:20:48 +00:00
}
2003-02-02 10:13:13 +00:00
else if ( $object -> name ) {
2004-07-13 07:21:14 +00:00
// Sometimes modules display content composed by people who are
// not registered members of the site (e.g. mailing list or news
// aggregator modules). This clause enables modules to display
// the true author of the content.
2004-05-18 18:41:46 +00:00
if ( $object -> homepage ) {
2004-07-13 07:21:14 +00:00
$output = '<a href="' . $object -> homepage . '">' . $object -> name . '</a>' ;
2004-05-18 18:41:46 +00:00
}
else {
$output = $object -> name ;
}
$output .= ' (' . t ( 'not verified' ) . ')' ;
2003-02-02 10:13:13 +00:00
}
2001-12-01 15:20:48 +00:00
else {
2004-07-13 07:21:14 +00:00
$output = t ( variable_get ( 'anonymous' , 'Anonymous' ));
2001-12-01 15:20:48 +00:00
}
2001-12-05 18:54:14 +00:00
return $output ;
2001-12-01 15:20:48 +00:00
}
2004-02-08 17:12:44 +00:00
/* @} */
2001-12-01 15:20:48 +00:00
2004-01-06 19:52:14 +00:00
/**
2004-07-13 07:21:14 +00:00
* @ defgroup form Form generation
2004-01-06 19:52:14 +00:00
* @ {
2004-07-22 16:06:54 +00:00
*
*
2004-01-06 19:52:14 +00:00
*/
2004-07-13 07:21:14 +00:00
/**
* Generate a form from a set of form elements .
*
* @ param $form
* An HTML string containing one or more form elements .
* @ param $method
* The query method to use ( " post " or " get " ) .
* @ param $action
* The URL to send the form contents to , if not the current page .
* @ param $attributes
* An associative array of attributes to add to the form tag .
* @ result
* An HTML string with the contents of $form wrapped in a form tag .
*/
function form ( $form , $method = 'post' , $action = NULL , $attributes = NULL ) {
2003-05-19 18:26:49 +00:00
if ( ! $action ) {
2003-06-03 18:04:47 +00:00
$action = request_uri ();
2003-05-19 18:26:49 +00:00
}
2004-07-13 07:21:14 +00:00
return '<form action="' . $action . '" method="' . $method . '"' . drupal_attributes ( $attributes ) . " > \n " . $form . " \n </form> \n " ;
2001-12-01 15:20:48 +00:00
}
2004-05-31 09:40:56 +00:00
/**
2004-07-13 07:21:14 +00:00
* File an error against the form element with the specified name .
2004-05-31 09:40:56 +00:00
*/
function form_set_error ( $name , $message ) {
$GLOBALS [ 'form' ][ $name ] = $message ;
drupal_set_message ( $message , 'error' );
}
/**
2004-07-04 16:50:02 +00:00
* Return an associative array of all errors .
2004-05-31 09:40:56 +00:00
*/
2004-07-04 16:50:02 +00:00
function form_get_errors () {
2004-07-04 06:19:41 +00:00
if ( array_key_exists ( 'form' , $GLOBALS )) {
return $GLOBALS [ 'form' ];
}
2004-05-31 09:40:56 +00:00
}
/**
* Return the error message filed against the form with the specified name .
*/
function _form_get_error ( $name ) {
2004-07-02 18:46:42 +00:00
if ( array_key_exists ( 'form' , $GLOBALS )) {
return $GLOBALS [ 'form' ][ $name ];
}
2004-05-31 09:40:56 +00:00
}
function _form_get_class ( $name , $required , $error ) {
return $name . ( $required ? ' required' : '' ) . ( $error ? ' error' : '' );
}
2004-07-13 07:21:14 +00:00
/**
* Format a general form item .
*
* @ param $title
* The label for the form item .
* @ param $value
* The contents of the form item .
* @ param $description
* Explanatory text to display after the form item .
* @ param $id
* A unique identifier for the form item .
* @ param $required
* Whether the user must fill in this form element before submitting the form .
* @ param $error
* An error message to display alongside the form element .
* @ return
* A themed HTML string representing the form item .
*/
2004-05-31 09:40:56 +00:00
function form_item ( $title , $value , $description = NULL , $id = NULL , $required = FALSE , $error = FALSE ) {
2004-07-08 11:31:12 +00:00
return theme ( 'form_element' , $title , $value , $description , $id , $required , $error );
2001-12-01 15:20:48 +00:00
}
2003-11-17 19:16:55 +00:00
2004-07-13 07:21:14 +00:00
/**
* Format a group of form items .
*
* @ param $legend
* The label for the form item group .
* @ param $group
* The form items within the group , as an HTML string .
* @ param $description
* Explanatory text to display after the form item group .
* @ return
* A themed HTML string representing the form item group .
*/
2003-12-22 14:45:00 +00:00
function form_group ( $legend , $group , $description = NULL ) {
2004-07-13 07:21:14 +00:00
return '<fieldset>' . ( $legend ? '<legend>' . $legend . '</legend>' : '' ) . $group . ( $description ? '<div class="description">' . $description . '</div>' : '' ) . " </fieldset> \n " ;
2003-11-06 18:27:58 +00:00
}
2001-12-01 15:20:48 +00:00
2004-07-13 07:21:14 +00:00
/**
* Format a radio button .
*
* @ param $title
* The label for the radio button .
* @ param $name
* The internal name used to refer to the button .
* @ param $value
* The value that the form element takes on when selected .
* @ param $checked
* Whether the button will be initially selected when the page is rendered .
* @ param $description
* Explanatory text to display after the form item .
* @ param $attributes
* An associative array of HTML attributes to add to the button .
* @ param $required
* Whether the user must select this radio button before submitting the form .
* @ return
* A themed HTML string representing the radio button .
*/
function form_radio ( $title , $name , $value = 1 , $checked = FALSE , $description = NULL , $attributes = NULL , $required = FALSE ) {
$element = '<input type="radio" class="' . _form_get_class ( 'form-radio' , $required , _form_get_error ( $name )) . '" name="edit[' . $name . ']" value="' . $value . '"' . ( $checked ? ' checked="checked"' : '' ) . drupal_attributes ( $attributes ) . ' />' ;
2004-02-24 20:22:45 +00:00
if ( ! is_null ( $title )) {
2004-07-13 07:21:14 +00:00
$element = '<label class="option">' . $element . ' ' . $title . '</label>' ;
2004-02-24 20:22:45 +00:00
}
2004-07-08 11:31:12 +00:00
return theme ( 'form_element' , NULL , $element , $description , $name , $required , _form_get_error ( $name ));
2003-12-24 12:40:28 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format a set of radio buttons .
*
* @ param $title
* The label for the radio buttons as a group .
* @ param $name
* The internal name used to refer to the buttons .
* @ param $value
* The currently selected radio button ' s key .
* @ param $options
* An associative array of buttons to display . The keys in this array are
* button values , while the values are the labels to display for each button .
* @ param $description
* Explanatory text to display after the form item .
* @ param $required
* Whether the user must select a radio button before submitting the form .
* @ param $attributes
* An associative array of HTML attributes to add to each button .
* @ return
* A themed HTML string representing the radio button set .
*/
2004-06-04 18:10:05 +00:00
function form_radios ( $title , $name , $value , $options , $description = NULL , $required = FALSE , $attributes = NULL ) {
2003-12-24 12:40:28 +00:00
if ( count ( $options ) > 0 ) {
2004-04-12 08:27:57 +00:00
$choices = '' ;
2003-12-24 12:40:28 +00:00
foreach ( $options as $key => $choice ) {
2004-07-13 07:21:14 +00:00
$choices .= '<label class="option"><input type="radio" class="form-radio" name="edit[' . $name . ']" value="' . $key . '"' . ( $key == $value ? ' checked="checked"' : '' ) . drupal_attributes ( $attributes ) . ' /> ' . $choice . '</label><br />' ;
2003-12-24 12:40:28 +00:00
}
2004-07-08 11:31:12 +00:00
return theme ( 'form_element' , $title , $choices , $description , $name , $required , _form_get_error ( $name ));
2003-12-24 12:40:28 +00:00
}
2003-04-13 13:42:51 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format a checkbox .
*
* @ param $title
* The label for the checkbox .
* @ param $name
* The internal name used to refer to the button .
* @ param $value
* The value that the form element takes on when selected .
* @ param $checked
* Whether the button will be initially selected when the page is rendered .
* @ param $description
* Explanatory text to display after the form item .
* @ param $attributes
* An associative array of HTML attributes to add to the button .
* @ param $required
* Whether the user must check this box before submitting the form .
* @ return
* A themed HTML string representing the checkbox .
*/
function form_checkbox ( $title , $name , $value = 1 , $checked = FALSE , $description = NULL , $attributes = NULL , $required = FALSE ) {
$element = '<input type="checkbox" class="' . _form_get_class ( 'form-checkbox' , $required , _form_get_error ( $name )) . '" name="edit[' . $name . ']" id="edit-' . $name . '" value="' . $value . '"' . ( $checked ? ' checked="checked"' : '' ) . drupal_attributes ( $attributes ) . ' />' ;
2004-02-24 20:22:45 +00:00
if ( ! is_null ( $title )) {
2004-07-13 07:21:14 +00:00
$element = '<label class="option">' . $element . ' ' . $title . '</label>' ;
2004-02-24 20:22:45 +00:00
}
2004-07-08 11:31:12 +00:00
return form_hidden ( $name , 0 ) . theme ( 'form_element' , NULL , $element , $description , $name , $required , _form_get_error ( $name ));
2001-12-01 15:20:48 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format a set of checkboxes .
*
* @ param $title
* The label for the checkboxes as a group .
* @ param $name
* The internal name used to refer to the buttons .
* @ param $values
* A linear array of keys of the initally checked boxes .
* @ param $options
* An associative array of buttons to display . The keys in this array are
* button values , while the values are the labels to display for each button .
* @ param $description
* Explanatory text to display after the form item .
* @ param $attributes
* An associative array of HTML attributes to add to each button .
* @ param $required
* Whether the user must check a box before submitting the form .
* @ return
* A themed HTML string representing the radio button set .
*/
2004-07-08 11:31:12 +00:00
function form_checkboxes ( $title , $name , $values , $options , $description = NULL , $attributes = NULL , $required = FALSE ) {
2004-05-15 15:42:47 +00:00
if ( count ( $options ) > 0 ) {
if ( ! isset ( $values )) {
$values = array ();
}
$choices = '' ;
foreach ( $options as $key => $choice ) {
2004-07-13 07:21:14 +00:00
$choices .= '<label class="option"><input type="checkbox" class="form-checkbox" name="edit[' . $name . '][]" value="' . $key . '"' . ( in_array ( $key , $values ) ? ' checked="checked"' : '' ) . drupal_attributes ( $attributes ) . ' /> ' . $choice . '</label><br />' ;
2004-05-15 15:42:47 +00:00
}
2004-07-08 11:31:12 +00:00
return theme ( 'form_element' , $title , $choices , $description , $name , $required , _form_get_error ( $name ));
2004-05-15 15:42:47 +00:00
}
}
2004-07-13 07:21:14 +00:00
/**
* Format a single - line text field .
*
* @ param $title
* The label for the text field .
* @ param $name
* The internal name used to refer to the field .
* @ param $value
* The initial value for the field at page load time .
* @ param $size
* A measure of the visible size of the field ( passed directly to HTML ) .
* @ param $maxlength
* The maximum number of characters that may be entered in the field .
* @ param $description
* Explanatory text to display after the form item .
* @ param $attributes
* An associative array of HTML attributes to add to the form item .
* @ param $required
* Whether the user must enter some text in the field .
* @ return
* A themed HTML string representing the field .
*/
2004-04-24 15:39:31 +00:00
function form_textfield ( $title , $name , $value , $size , $maxlength , $description = NULL , $attributes = NULL , $required = FALSE ) {
2004-07-13 07:21:14 +00:00
$size = $size ? ' size="' . $size . '"' : '' ;
return theme ( 'form_element' , $title , '<input type="text" maxlength="' . $maxlength . '" class="' . _form_get_class ( 'form-text' , $required , _form_get_error ( $name )) . '" name="edit[' . $name . ']" id="' . $name . '"' . $size . ' value="' . check_form ( $value ) . '"' . drupal_attributes ( $attributes ) . ' />' , $description , $name , $required , _form_get_error ( $name ));
2001-12-01 15:20:48 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format a single - line text field that does not display its contents visibly .
*
* @ param $title
* The label for the text field .
* @ param $name
* The internal name used to refer to the field .
* @ param $value
* The initial value for the field at page load time .
* @ param $size
* A measure of the visible size of the field ( passed directly to HTML ) .
* @ param $maxlength
* The maximum number of characters that may be entered in the field .
* @ param $description
* Explanatory text to display after the form item .
* @ param $attributes
* An associative array of HTML attributes to add to the form item .
* @ param $required
* Whether the user must enter some text in the field .
* @ return
* A themed HTML string representing the field .
*/
2004-04-24 15:39:31 +00:00
function form_password ( $title , $name , $value , $size , $maxlength , $description = NULL , $attributes = NULL , $required = FALSE ) {
2004-07-13 07:21:14 +00:00
$size = $size ? ' size="' . $size . '"' : '' ;
return theme ( 'form_element' , $title , '<input type="password" class="' . _form_get_class ( 'form-password' , $required , _form_get_error ( $name )) . '" maxlength="' . $maxlength . '" name="edit[' . $name . ']" id="' . $name . '"' . $size . ' value="' . check_form ( $value ) . '"' . drupal_attributes ( $attributes ) . ' />' , $description , $name , $required , _form_get_error ( $name ));
2001-12-01 15:20:48 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format a multiple - line text field .
*
* @ param $title
* The label for the text field .
* @ param $name
* The internal name used to refer to the field .
* @ param $value
* The initial value for the field at page load time .
* @ param $cols
* The width of the field , in columns of text .
* @ param $rows
* The height of the field , in rows of text .
* @ param $description
* Explanatory text to display after the form item .
* @ param $attributes
* An associative array of HTML attributes to add to the form item .
* @ param $required
* Whether the user must enter some text in the field .
* @ return
* A themed HTML string representing the field .
*/
2004-04-24 15:39:31 +00:00
function form_textarea ( $title , $name , $value , $cols , $rows , $description = NULL , $attributes = NULL , $required = FALSE ) {
2004-07-13 07:21:14 +00:00
$cols = $cols ? ' cols="' . $cols . '"' : '' ;
module_invoke_all ( 'textarea' , $name ); // eg. optionally plug in a WYSIWYG editor
return theme ( 'form_element' , $title , '<textarea wrap="virtual"' . $cols . ' rows="' . $rows . '" name="edit[' . $name . ']" id="' . $name . '" class="' . _form_get_class ( 'textarea' , $required , _form_get_error ( $name )) . '"' . drupal_attributes ( $attributes ) . '>' . check_form ( $value ) . '</textarea>' , $description , $name , $required , _form_get_error ( $name ));
2001-12-01 15:20:48 +00:00
}
2004-05-05 15:58:26 +00:00
/**
2004-07-13 07:21:14 +00:00
* Format a dropdown menu or scrolling selection box .
2004-05-05 15:58:26 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $title
* The label for the form element .
* @ param $name
* The internal name used to refer to the form element .
* @ param $value
* The key of the currently selected item , or a linear array of keys of all the
* currently selected items if multiple selections are allowed .
* @ param $options
* An associative array of buttons to display . The keys in this array are
* button values , while the values are the labels to display for each button .
* @ param $description
* Explanatory text to display after the form item .
* @ param $extra
* Additional HTML to inject into the select element tag .
* @ param $multiple
* Whether the user may select more than one item .
* @ param $required
* Whether the user must select a value before submitting the form .
* @ return
* A themed HTML string representing the form element .
2004-05-05 15:58:26 +00:00
*
2004-07-13 07:21:14 +00:00
* It is possible to group options together ; to do this , change the format of
* $options to an associative array in which the keys are group labels , and the
* values are associative arrays in the normal $options format .
2004-05-05 15:58:26 +00:00
*/
2004-07-13 07:21:14 +00:00
function form_select ( $title , $name , $value , $options , $description = NULL , $extra = 0 , $multiple = FALSE , $required = FALSE ) {
2004-04-12 08:27:57 +00:00
$select = '' ;
2003-12-24 12:40:28 +00:00
foreach ( $options as $key => $choice ) {
2004-05-05 15:58:26 +00:00
if ( is_array ( $choice )) {
2004-07-13 07:21:14 +00:00
$select .= '<optgroup label="' . $key . '">' ;
2004-05-05 15:58:26 +00:00
foreach ( $choice as $key => $choice ) {
2004-07-13 07:21:14 +00:00
$select .= '<option value="' . $key . '"' . ( is_array ( $value ) ? ( in_array ( $key , $value ) ? ' selected="selected"' : '' ) : ( $value == $key ? ' selected="selected"' : '' )) . '>' . check_form ( $choice ) . '</option>' ;
2004-05-05 15:58:26 +00:00
}
2004-07-13 07:21:14 +00:00
$select .= '</optgroup>' ;
2004-05-05 15:58:26 +00:00
}
else {
2004-07-13 07:21:14 +00:00
$select .= '<option value="' . $key . '"' . ( is_array ( $value ) ? ( in_array ( $key , $value ) ? ' selected="selected"' : '' ) : ( $value == $key ? ' selected="selected"' : '' )) . '>' . check_form ( $choice ) . '</option>' ;
2004-05-05 15:58:26 +00:00
}
2003-06-05 18:09:39 +00:00
}
2004-07-13 07:21:14 +00:00
return theme ( 'form_element' , $title , '<select name="edit[' . $name . ']' . ( $multiple ? '[]' : '' ) . '"' . ( $multiple ? ' multiple="multiple" ' : '' ) . ( $extra ? ' ' . $extra : '' ) . ' id="' . $name . '">' . $select . '</select>' , $description , $name , $required , _form_get_error ( $name ));
2003-06-05 18:09:39 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format a file upload field .
*
* @ param $title
* The label for the file upload field .
* @ param $name
* The internal name used to refer to the field .
* @ param $size
* A measure of the visible size of the field ( passed directly to HTML ) .
* @ param $description
* Explanatory text to display after the form item .
* @ param $required
* Whether the user must upload a file to the field .
* @ return
* A themed HTML string representing the field .
*
* For assistance with handling the uploaded file correctly , see the API
* provided by file . inc .
*/
2004-04-24 15:39:31 +00:00
function form_file ( $title , $name , $size , $description = NULL , $required = FALSE ) {
2004-07-13 07:21:14 +00:00
return theme ( 'form_element' , $title , '<input type="file" class="' . _form_get_class ( 'form-file' , $required , _form_get_error ( $name )) . '" name="edit[' . $name . ']" id="' . $name . '" size="' . $size . " \" /> \n " , $description , $name , $required , _form_get_error ( $error ));
2001-12-01 15:20:48 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Store data in a hidden form field .
*
* @ param $name
* The internal name used to refer to the field .
* @ param $value
* The stored data .
* @ return
* A themed HTML string representing the hidden field .
*
* This function can be useful in retaining information between page requests ,
* but be sure to validate the data on the receiving page as it is possible for
* an attacker to change the value before it is submitted .
*/
2001-12-01 15:20:48 +00:00
function form_hidden ( $name , $value ) {
2004-07-13 07:21:14 +00:00
return '<input type="hidden" name="edit[' . $name . ']" value="' . check_form ( $value ) . " \" /> \n " ;
2001-12-01 15:20:48 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format an action button .
*
* @ param $value
* Both the label for the button , and the value passed to the target page
* when this button is clicked .
* @ param $name
* The internal name used to refer to the button .
* @ param $type
* What type to pass to the HTML input tag .
* @ param $attributes
* An associative array of HTML attributes to add to the form item .
* @ return
* A themed HTML string representing the button .
*/
function form_button ( $value , $name = 'op' , $type = 'submit' , $attributes = NULL ) {
return '<input type="' . $type . '" class="form-' . $type . '" name="' . $name . '" value="' . check_form ( $value ) . '" ' . drupal_attributes ( $attributes ) . " /> \n " ;
2003-12-15 19:58:53 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format a form submit button .
*
* @ param $value
* Both the label for the button , and the value passed to the target page
* when this button is clicked .
* @ param $name
* The internal name used to refer to the button .
* @ param $attributes
* An associative array of HTML attributes to add to the form item .
* @ return
* A themed HTML string representing the button .
*/
function form_submit ( $value , $name = 'op' , $attributes = NULL ) {
return form_button ( $value , $name , 'submit' , $attributes );
2001-12-01 15:20:48 +00:00
}
2004-07-13 07:21:14 +00:00
/**
* Format a weight selection menu .
*
* @ param $title
* The label for the form element .
* @ param $name
* The internal name used to refer to the form element .
* @ param $value
* The selected weight value at page load time .
* @ param $delta
* The largest in absolute value the weight can be . For example , if set to 10 ,
* weights could range from - 10 to 10 inclusive .
* @ param $description
* Explanatory text to display after the form item .
* @ param $extra
* Additional HTML to inject into the select element tag .
* @ return
* A themed HTML string representing the form element .
*/
function form_weight ( $title = NULL , $name = 'weight' , $value = 0 , $delta = 10 , $description = NULL , $extra = 0 ) {
2003-04-03 22:18:27 +00:00
for ( $n = ( - 1 * $delta ); $n <= $delta ; $n ++ ) {
2002-10-26 15:17:26 +00:00
$weights [ $n ] = $n ;
}
return form_select ( $title , $name , $value , $weights , $description , $extra );
}
2004-07-22 16:06:54 +00:00
/**
* @ } end of defgroup form
*/
2003-06-19 17:26:27 +00:00
2004-07-13 07:21:14 +00:00
/**
* Generate an internal Drupal URL .
*
* @ param $path
* The Drupal path being linked to , such as " admin/node " .
* @ 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 .
* @ 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 ) {
2004-01-14 22:41:15 +00:00
global $base_url ;
2004-01-17 23:19:02 +00:00
2003-05-31 13:05:06 +00:00
static $script ;
if ( empty ( $script )) {
/*
** On some webservers such as IIS we can ' t omit " index.php " . As such 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
}
2004-07-13 07:21:14 +00:00
$path = drupal_get_path_alias ( $path );
2003-09-30 17:01:34 +00:00
2003-12-29 19:10:26 +00:00
if ( isset ( $fragment )) {
2004-07-13 07:21:14 +00:00
$fragment = '#' . $fragment ;
2003-12-29 19:10:26 +00:00
}
2004-02-11 19:21:14 +00:00
$base = ( $absolute ? $base_url . '/' : '' );
2004-07-13 07:21:14 +00:00
if ( variable_get ( 'clean_url' , '0' ) == '0' ) {
if ( isset ( $path )) {
2003-02-14 19:52:45 +00:00
if ( isset ( $query )) {
2004-07-13 07:21:14 +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 )) {
2004-07-13 07:21:14 +00:00
return $base . $script . '?' . $query . $fragment ;
2003-02-14 19:52:45 +00:00
}
else {
2004-07-13 07:21:14 +00:00
return $base . $fragment ;
2003-02-14 19:52:45 +00:00
}
2003-01-06 21:24:21 +00:00
}
}
else {
2004-07-13 07:21:14 +00:00
if ( isset ( $path )) {
2003-02-14 19:52:45 +00:00
if ( isset ( $query )) {
2004-07-13 07:21:14 +00:00
return $base . $path . '?' . $query . $fragment ;
2003-02-14 19:52:45 +00:00
}
else {
2004-07-13 07:21:14 +00:00
return $base . $path . $fragment ;
2003-02-14 19:52:45 +00:00
}
2003-01-06 21:24:21 +00:00
}
2003-01-11 10:46:11 +00:00
else {
2003-02-14 19:52:45 +00:00
if ( isset ( $query )) {
2004-07-13 07:21:14 +00:00
return $base . $script . '?' . $query . $fragment ;
2003-02-14 19:52:45 +00:00
}
else {
2004-07-13 07:21:14 +00:00
return $base . $fragment ;
2003-02-14 19:52:45 +00:00
}
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 ()) {
2004-07-08 11:31:12 +00:00
if ( $attributes ) {
2003-08-12 20:37:16 +00:00
$t = array ();
foreach ( $attributes as $key => $value ) {
2004-07-13 07:21:14 +00:00
$t [] = $key . '="' . $value . '"' ;
2003-08-12 20:37:16 +00:00
}
2004-03-10 19:32:37 +00:00
2004-07-13 07:21:14 +00:00
return ' ' . implode ( $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
* The Drupal path being linked to , such as " admin/node " .
* @ 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 .
* @ return
* an HTML string containing a link to the given path .
*/
function l ( $text , $path , $attributes = array (), $query = NULL , $fragment = NULL , $absolute = FALSE ) {
if ( drupal_get_normal_path ( $path ) == $_GET [ 'q' ]) {
2004-01-19 21:57:42 +00:00
if ( isset ( $attributes [ 'class' ])) {
$attributes [ 'class' ] .= ' active' ;
}
else {
$attributes [ 'class' ] = 'active' ;
}
}
2004-07-13 07:21:14 +00:00
return '<a href="' . url ( $path , $query , $fragment , $absolute ) . '"' . drupal_attributes ( $attributes ) . '>' . $text . '</a>' ;
2002-04-20 11:52:50 +00:00
}
2001-12-01 15:20:48 +00:00
function field_get ( $string , $name ) {
2004-01-23 15:31:29 +00:00
ereg ( " , $name =([^,]+) " , " , $string " , $regs );
2001-12-01 15:20:48 +00:00
return $regs [ 1 ];
}
function field_set ( $string , $name , $value ) {
$rval = ereg_replace ( " , $name =[^,]+ " , " " , " , $string " );
2003-01-09 20:06:00 +00:00
if ( isset ( $value )) {
2004-07-13 07:21:14 +00:00
$rval .= ( $rval == ',' ? '' : ',' ) . $name . '=' . $value ;
2002-03-05 20:15:17 +00:00
}
2001-12-01 15:20:48 +00:00
return substr ( $rval , 1 );
}
2004-07-13 07:21:14 +00:00
/**
* Fetch a set of global navigation links .
*
* The links are gathered by calls to hook_link ( 'page' ) in each module .
*/
2001-12-01 15:20:48 +00:00
function link_page () {
2003-08-11 20:41:37 +00:00
global $custom_links ;
2002-04-14 20:46:41 +00:00
2003-09-05 13:19:00 +00:00
if ( is_array ( $custom_links )) {
2002-04-02 09:45:57 +00:00
return $custom_links ;
}
else {
2004-07-13 07:21:14 +00:00
$links = module_invoke_all ( 'link' , 'page' );
array_unshift ( $links , l ( t ( 'home' ), '' , array ( 'title' => t ( 'Return to the main page.' ))));
2002-04-02 09:45:57 +00:00
return $links ;
2001-12-01 15:20:48 +00:00
}
2002-04-14 20:46:41 +00:00
}
2001-12-01 15:20:48 +00:00
2004-07-13 07:21:14 +00:00
/**
* Fetch a set of links to display after a given node .
*
* The links are gathered by calls to hook_link ( 'node' ) in each module .
*/
2001-12-01 15:20:48 +00:00
function link_node ( $node , $main = 0 ) {
2004-07-13 07:21:14 +00:00
return module_invoke_all ( 'link' , 'node' , $node , $main );
2001-12-01 15:20:48 +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 ;
}
}
2004-01-06 12:09:42 +00:00
/**
2004-07-13 07:21:14 +00:00
* Prepare a new XML parser .
*
* This is a wrapper around xml_parser_create () which extracts the encoding from
* the XML data first and sets the output encoding to UTF - 8. This function should
* be used instead of xml_parser_create (), because PHP 's XML parser doesn' t check
2004-01-06 12:09:42 +00:00
* the input encoding itself .
*
* This is also where unsupported encodings should be converted .
* Callers should take this into account : $data might have been changed after
* the call .
*
2004-07-13 07:21:14 +00:00
* @ param & $data
* The XML data which will be parsed later .
* @ return
* An XML parser object .
2004-01-06 12:09:42 +00:00
*/
function drupal_xml_parser_create ( & $data ) {
$encoding = 'utf-8' ;
if ( ereg ( '^<\?xml[^>]+encoding="([^"]+)"' , $data , $match )) {
$encoding = $match [ 1 ];
}
/*
2004-02-17 23:36:22 +00:00
* Unsupported encodings are converted here into UTF - 8.
2004-07-12 21:35:31 +00:00
* Requires the iconv , GNU recode or mbstring PHP extension .
2004-01-06 12:09:42 +00:00
*/
2004-02-17 23:36:22 +00:00
$php_supported = array ( 'utf-8' , 'iso-8859-1' , 'us-ascii' );
if ( ! in_array ( strtolower ( $encoding ), $php_supported )) {
if ( function_exists ( 'iconv' )) {
2004-07-12 21:35:31 +00:00
$out = @ iconv ( $encoding , 'utf-8' , $data );
2004-02-17 23:36:22 +00:00
}
2004-07-12 21:35:31 +00:00
else if ( function_exists ( 'mb_convert_encoding' )) {
$out = @ mb_convert_encoding ( $data , 'utf-8' , $encoding );
}
else if ( function_exists ( 'recode_string' )) {
$out = @ recode_string ( $encoding . '..utf-8' , $data );
}
else {
2004-07-13 07:21:14 +00:00
watchdog ( t ( " Unsupported XML encoding '%s'. Please install iconv, GNU recode or mbstring for PHP. " , $encoding ));
2004-07-12 21:35:31 +00:00
return 0 ;
}
2004-07-12 21:38:41 +00:00
if ( $out !== false ) {
$data = $out ;
$encoding = 'utf-8' ;
}
else {
2004-07-13 07:21:14 +00:00
watchdog ( t ( " Could not convert XML encoding '%s' to UTF-8. " , $encoding ));
2004-07-12 21:38:41 +00:00
return 0 ;
}
2004-02-17 23:36:22 +00:00
}
2004-01-06 12:09:42 +00:00
$xml_parser = xml_parser_create ( $encoding );
xml_parser_set_option ( $xml_parser , XML_OPTION_TARGET_ENCODING , 'utf-8' );
return $xml_parser ;
}
2004-04-15 14:07:08 +00:00
/**
2004-07-13 07:21:14 +00:00
* Truncate a UTF - 8 - encoded string safely .
*
2004-04-15 14:07:08 +00:00
* If the end position is in the middle of a UTF - 8 sequence , it scans backwards
* until the beginning of the byte sequence .
*
* Use this function whenever you want to chop off a string at an unsure
* location . On the other hand , if you 're sure that you' re splitting on a
* character boundary ( e . g . after using strpos or similar ), you can safely use
* substr () instead .
*
2004-07-13 07:21:14 +00:00
* @ param $string
* The string to truncate .
* @ param $len
* An upper limit on the returned string length .
* @ return
* The truncated string .
2004-04-15 14:07:08 +00:00
*/
function truncate_utf8 ( $string , $len ) {
$slen = strlen ( $string );
if ( $slen <= $len ) {
return $string ;
}
if (( ord ( $string [ $len ]) < 0x80 ) || ( ord ( $string [ $len ]) >= 0xC0 )) {
return substr ( $string , 0 , $len );
}
while ( ord ( $string [ -- $len ]) < 0xC0 ) {};
return substr ( $string , 0 , $len );
}
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
/**
* Wrapper around PHP ' s eval () . 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 ) .
*
* @ param $code The code to evaluate
*/
function drupal_eval ( $code ) {
ob_start ();
print eval ( '?>' . $code );
return ob_get_clean ();
}
2004-07-13 07:21:14 +00:00
include_once 'includes/theme.inc' ;
include_once 'includes/pager.inc' ;
include_once 'includes/menu.inc' ;
include_once 'includes/tablesort.inc' ;
include_once 'includes/file.inc' ;
2003-02-12 16:21:48 +00:00
2003-03-04 06:19:01 +00:00
// set error handler:
2004-07-13 07:21:14 +00:00
set_error_handler ( 'error_handler' );
2003-03-04 06:19:01 +00:00
2003-06-04 18:24:39 +00:00
// spit out the correct charset http header
2004-07-13 07:21:14 +00:00
drupal_set_header ( 'Content-Type: text/html; charset=utf-8' );
2003-06-04 18:24:39 +00:00
2004-07-13 07:21:14 +00:00
// initialize the _GET['q'] prior to loading the modules and invoking their 'init' hook:
if ( ! empty ( $_GET [ 'q' ])) {
$_GET [ 'q' ] = drupal_get_normal_path ( trim ( $_GET [ 'q' ], '/' ));
2003-09-30 17:01:34 +00:00
}
else {
2004-07-13 07:21:14 +00:00
$_GET [ 'q' ] = drupal_get_normal_path ( variable_get ( 'site_frontpage' , 'node' ));
2003-09-30 17:01:34 +00:00
}
2003-03-17 07:01:12 +00:00
// initialize installed modules:
module_init ();
2004-07-13 07:21:14 +00:00
if ( $_REQUEST && ! user_access ( 'bypass input data check' )) {
2003-11-18 19:44:36 +00:00
if ( ! valid_input_data ( $_REQUEST )) {
2004-07-13 07:21:14 +00:00
die ( 'terminated request because of suspicious input data' );
2003-11-18 19:44:36 +00:00
}
}
2001-12-01 15:20:48 +00:00
// initialize localization system:
$locale = locale_init ();
// initialize theme:
2003-11-09 23:27:22 +00:00
$theme = init_theme ();
2003-11-18 19:44:36 +00:00
2003-03-04 15:10:37 +00:00
?>