home *** CD-ROM | disk | FTP | other *** search
/ PCGUIA 117 / PC Guia 117.iso / Software / Produtividade / Software2 / Product4 / Setup.exe / drupal-4.6.0 / includes / common.inc < prev    next >
Encoding:
Text File  |  2005-04-12  |  59.4 KB  |  1,914 lines

  1. <?php
  2. /* $Id: common.inc,v 1.434.2.3 2005/04/11 22:50:41 unconed Exp $ */
  3.  
  4. /**
  5.  * @file
  6.  * Common functions that many Drupal modules will need to reference.
  7.  *
  8.  * The functions that are critical and need to be available even when serving
  9.  * a cached page are instead located in bootstrap.inc.
  10.  */
  11.  
  12. /**
  13.  * Set the breadcrumb trail for the current page.
  14.  *
  15.  * @param $breadcrumb
  16.  *   Array of links, starting with "home" and proceeding up to but not including
  17.  *   the current page.
  18.  */
  19. function drupal_set_breadcrumb($breadcrumb = NULL) {
  20.   static $stored_breadcrumb;
  21.  
  22.   if (isset($breadcrumb)) {
  23.     $stored_breadcrumb = $breadcrumb;
  24.   }
  25.   return $stored_breadcrumb;
  26. }
  27.  
  28. /**
  29.  * Get the breadcrumb trail for the current page.
  30.  */
  31. function drupal_get_breadcrumb() {
  32.   $breadcrumb = drupal_set_breadcrumb();
  33.  
  34.   if (!isset($breadcrumb)) {
  35.     $breadcrumb = menu_get_active_breadcrumb();
  36.   }
  37.  
  38.   return $breadcrumb;
  39. }
  40.  
  41. /**
  42.  * Add output to the head tag of the HTML page.
  43.  * This function can be called as long the headers aren't sent.
  44.  */
  45. function drupal_set_html_head($data = NULL) {
  46.   static $stored_head = '';
  47.  
  48.   if (!is_null($data)) {
  49.     $stored_head .= $data ."\n";
  50.   }
  51.   return $stored_head;
  52. }
  53.  
  54. /**
  55.  * Retrieve output to be displayed in the head tag of the HTML page.
  56.  */
  57. function drupal_get_html_head() {
  58.   global $base_url;
  59.  
  60.   $output = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
  61.   $output .= "<base href=\"$base_url/\" />\n";
  62.   $output .= theme('stylesheet_import', 'misc/drupal.css');
  63.  
  64.   return $output . drupal_set_html_head();
  65. }
  66.  
  67. /**
  68.  * Regenerate the path map from the information in the database.
  69.  */
  70. function drupal_rebuild_path_map() {
  71.   drupal_get_path_map('rebuild');
  72. }
  73.  
  74. /**
  75.  * Given a path alias, return the internal path it represents.
  76.  */
  77. function drupal_get_normal_path($path) {
  78.   if (($map = drupal_get_path_map()) && isset($map[$path])) {
  79.     return $map[$path];
  80.   }
  81.   elseif (function_exists('conf_url_rewrite')) {
  82.     return conf_url_rewrite($path, 'incoming');
  83.   }
  84.   else {
  85.     return $path;
  86.   }
  87. }
  88.  
  89. /**
  90.  * Set an HTTP response header for the current page.
  91.  */
  92. function drupal_set_header($header = NULL) {
  93.   // We use an array to guarantee there are no leading or trailing delimiters.
  94.   // Otherwise, header('') could get called when serving the page later, which
  95.   // ends HTTP headers prematurely on some PHP versions.
  96.   static $stored_headers = array();
  97.  
  98.   if (strlen($header)) {
  99.     header($header);
  100.     $stored_headers[] = $header;
  101.   }
  102.   return implode("\n", $stored_headers);
  103. }
  104.  
  105. /**
  106.  * Get the HTTP response headers for the current page.
  107.  */
  108. function drupal_get_headers() {
  109.   return drupal_set_header();
  110. }
  111.  
  112. /**
  113.  * @name HTTP handling
  114.  * @{
  115.  * Functions to properly handle HTTP responses.
  116.  */
  117.  
  118. /**
  119.  * Prepare a destination query string for use in combination with
  120.  * drupal_goto().  Used to direct the user back to the referring page
  121.  * after completing a form.
  122.  *
  123.  * @see drupal_goto()
  124.  */
  125. function drupal_get_destination() {
  126.   $destination[] = $_GET['q'];
  127.   $params = array('from', 'sort', 'order');
  128.   foreach ($params as $param) {
  129.     if (isset($_GET[$param])) {
  130.       $destination[] = "$param=". $_GET[$param];
  131.     }
  132.   }
  133.   return 'destination='. urlencode(implode('&', $destination));
  134. }
  135.  
  136. /**
  137.  * Send the user to a different Drupal page.
  138.  *
  139.  * This issues an on-site HTTP redirect. The function makes sure the redirected
  140.  * URL is formatted correctly.
  141.  *
  142.  * Usually the redirected URL is constructed from this function's input
  143.  * parameters.  However you may override that behavior by setting a
  144.  * <em>destination</em> in either the $_REQUEST-array (i.e. by using
  145.  * the query string of an URI) or the $_REQUEST['edit']-array (i.e. by
  146.  * using a hidden form field).  This is used to direct the user back to
  147.  * the proper page after completing a form.  For example, after editing
  148.  * a post on the 'admin/node'-page or after having logged on using the
  149.  * 'user login'-block in a sidebar.  The function drupal_get_destination()
  150.  * can be used to help set the destination URL.
  151.  *
  152.  * It is advised to use drupal_goto() instead of PHP's header(), because
  153.  * drupal_goto() will append the user's session ID to the URI when PHP is
  154.  * compiled with "--enable-trans-sid".
  155.  *
  156.  * This function ends the request; use it rather than a print theme('page')
  157.  * statement in your menu callback.
  158.  *
  159.  * @param $path
  160.  *   A Drupal path.
  161.  * @param $query
  162.  *   The query string component, if any.
  163.  * @param $fragment
  164.  *   The destination fragment identifier (named anchor).
  165.  *
  166.  * @see drupal_get_destination()
  167.  */
  168. function drupal_goto($path = '', $query = NULL, $fragment = NULL) {
  169.   if ($_REQUEST['destination']) {
  170.     extract(parse_url($_REQUEST['destination']));
  171.   }
  172.   else if ($_REQUEST['edit']['destination']) {
  173.     extract(parse_url($_REQUEST['edit']['destination']));
  174.   }
  175.  
  176.   $url = url($path, $query, $fragment, TRUE);
  177.  
  178.   if (ini_get('session.use_trans_sid') && session_id() && !strstr($url, session_id())) {
  179.     $sid = session_name() . '=' . session_id();
  180.  
  181.     if (strstr($url, '?') && !strstr($url, $sid)) {
  182.       $url = $url .'&'. $sid;
  183.     }
  184.     else {
  185.       $url = $url .'?'. $sid;
  186.     }
  187.   }
  188.  
  189.   // Before the redirect, allow modules to react to the end of the page request.
  190.   module_invoke_all('exit', $url);
  191.  
  192.   header('Location: '. $url);
  193.  
  194.   // The "Location" header sends a REDIRECT status code to the http
  195.   // daemon. In some cases this can go wrong, so we make sure none
  196.   // of the code below the drupal_goto() call gets executed when we redirect.
  197.   exit();
  198. }
  199.  
  200. /**
  201.  * Generates a 404 error if the request can not be handled.
  202.  */
  203. function drupal_not_found() {
  204.   header('HTTP/1.0 404 Not Found');
  205.   watchdog('page not found', t('%page not found.', array('%page' => theme('placeholder', $_GET['q']))), WATCHDOG_WARNING);
  206.  
  207.   $path = drupal_get_normal_path(variable_get('site_404', ''));
  208.   $status = MENU_NOT_FOUND;
  209.   if ($path) {
  210.     menu_set_active_item($path);
  211.     $status = menu_execute_active_handler();
  212.   }
  213.  
  214.   if ($status != MENU_FOUND) {
  215.     drupal_set_title(t('Page not found'));
  216.     print theme('page', '');
  217.   }
  218. }
  219.  
  220. /**
  221.  * Generates a 403 error if the request is not allowed.
  222.  */
  223. function drupal_access_denied() {
  224.   header('HTTP/1.0 403 Forbidden');
  225.   watchdog('access denied', t('%page denied access.', array('%page' => theme('placeholder', $_GET['q']))), WATCHDOG_WARNING, l(t('view'), $_GET['q']));
  226.  
  227.   $path = drupal_get_normal_path(variable_get('site_403', ''));
  228.   $status = MENU_NOT_FOUND;
  229.   if ($path) {
  230.     menu_set_active_item($path);
  231.     $status = menu_execute_active_handler();
  232.   }
  233.  
  234.   if ($status != MENU_FOUND) {
  235.     drupal_set_title(t('Access denied'));
  236.     print theme('page', message_access());
  237.   }
  238. }
  239.  
  240. /**
  241.  * Perform an HTTP request.
  242.  *
  243.  * This is a flexible and powerful HTTP client implementation. Correctly handles
  244.  * GET, POST, PUT or any other HTTP requests. Handles redirects.
  245.  *
  246.  * @param $url
  247.  *   A string containing a fully qualified URI.
  248.  * @param $headers
  249.  *   An array containing an HTTP header => value pair.
  250.  * @param $method
  251.  *   A string defining the HTTP request to use.
  252.  * @param $data
  253.  *   A string containing data to include in the request.
  254.  * @param $retry
  255.  *   An integer representing how many times to retry the request in case of a
  256.  *   redirect.
  257.  * @return
  258.  *   An object containing the HTTP request headers, response code, headers,
  259.  *   data, and redirect status.
  260.  */
  261. function drupal_http_request($url, $headers = array(), $method = 'GET', $data = NULL, $retry = 3) {
  262.   $result = new StdClass();
  263.  
  264.   // Parse the URL, and make sure we can handle the schema.
  265.   $uri = parse_url($url);
  266.   switch ($uri['scheme']) {
  267.     case 'http':
  268.       $fp = @fsockopen($uri['host'], ($uri['port'] ? $uri['port'] : 80), $errno, $errstr, 15);
  269.       break;
  270.     case 'https':
  271.       // Note: Only works for PHP 4.3 compiled with OpenSSL.
  272.       $fp = @fsockopen('ssl://'. $uri['host'], ($uri['port'] ? $uri['port'] : 443), $errno, $errstr, 20);
  273.       break;
  274.     default:
  275.       $result->error = 'invalid schema '. $uri['scheme'];
  276.       return $result;
  277.   }
  278.  
  279.   // Make sure the socket opened properly.
  280.   if (!$fp) {
  281.     $result->error = trim($errno .' '. $errstr);
  282.     return $result;
  283.   }
  284.  
  285.   // Construct the path to act on.
  286.   $path = $uri['path'] ? $uri['path'] : '/';
  287.   if ($uri['query']) {
  288.     $path .= '?'. $uri['query'];
  289.   }
  290.  
  291.   // Create HTTP request.
  292.   $defaults = array(
  293.     'Host' => 'Host: '. $uri['host'],
  294.     'User-Agent' => 'User-Agent: Drupal (+http://www.drupal.org/)',
  295.     'Content-Length' => 'Content-Length: '. strlen($data)
  296.   );
  297.  
  298.   foreach ($headers as $header => $value) {
  299.     $defaults[$header] = $header .': '. $value;
  300.   }
  301.  
  302.   $request = $method .' '. $path ." HTTP/1.0\r\n";
  303.   $request .= implode("\r\n", $defaults);
  304.   $request .= "\r\n\r\n";
  305.   if ($data) {
  306.     $request .= $data ."\r\n";
  307.   }
  308.   $result->request = $request;
  309.  
  310.   fwrite($fp, $request);
  311.  
  312.   // Fetch response.
  313.   $response = '';
  314.   while (!feof($fp) && $data = fread($fp, 1024)) {
  315.     $response .= $data;
  316.   }
  317.   fclose($fp);
  318.  
  319.   // Parse response.
  320.   list($headers, $result->data) = explode("\r\n\r\n", $response, 2);
  321.   $headers = preg_split("/\r\n|\n|\r/", $headers);
  322.  
  323.   list($protocol, $code, $text) = explode(' ', trim(array_shift($headers)), 3);
  324.   $result->headers = array();
  325.  
  326.   // Parse headers.
  327.   while ($line = trim(array_shift($headers))) {
  328.     list($header, $value) = explode(':', $line, 2);
  329.     $result->headers[$header] = trim($value);
  330.   }
  331.  
  332.   $responses = array(
  333.     100 => 'Continue', 101 => 'Switching Protocols',
  334.     200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
  335.     300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
  336.     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',
  337.     500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
  338.   );
  339.   // RFC 2616 states that all unknown HTTP codes must be treated the same as
  340.   // the base code in their class.
  341.   if (!isset($responses[$code])) {
  342.     $code = floor($code / 100) * 100;
  343.   }
  344.  
  345.   switch ($code) {
  346.     case 200: // OK
  347.     case 304: // Not modified
  348.       break;
  349.     case 301: // Moved permanently
  350.     case 302: // Moved temporarily
  351.     case 307: // Moved temporarily
  352.       $location = $result->headers['Location'];
  353.  
  354.       if ($retry) {
  355.         $result = drupal_http_request($result->headers['Location'], $headers, $method, $data, --$retry);
  356.         $result->redirect_code = $result->code;
  357.       }
  358.       $result->redirect_url = $location;
  359.  
  360.       break;
  361.     default:
  362.       $result->error = $text;
  363.   }
  364.  
  365.   $result->code = $code;
  366.   return $result;
  367. }
  368. /**
  369.  * @} End of "HTTP handling".
  370.  */
  371.  
  372. /**
  373.  * Log errors as defined by administrator
  374.  * Error levels:
  375.  *  1 = Log errors to database.
  376.  *  2 = Log errors to database and to screen.
  377.  */
  378. function error_handler($errno, $message, $filename, $line) {
  379.   if ($errno & (E_ALL ^ E_NOTICE)) {
  380.     $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');
  381.     $entry = $types[$errno] .': '. $message .' in '. $filename .' on line '. $line .'.';
  382.  
  383.     if (variable_get('error_level', 1) == 1) {
  384.       print '<pre>'. $entry .'</pre>';
  385.     }
  386.  
  387.     watchdog('php', t('%message in %file on line %line.', array('%error' => $types[$errno], '%message' => $message, '%file' => $filename, '%line' => $line)), WATCHDOG_ERROR);
  388.   }
  389. }
  390.  
  391. function _fix_gpc_magic(&$item) {
  392.   if (is_array($item)) {
  393.     array_walk($item, '_fix_gpc_magic');
  394.   }
  395.   else {
  396.     $item = stripslashes($item);
  397.   }
  398. }
  399.  
  400. /**
  401.  * Correct double-escaping problems caused by "magic quotes" in some PHP
  402.  * installations.
  403.  */
  404. function fix_gpc_magic() {
  405.   static $fixed = false;
  406.   if (!$fixed && ini_get('magic_quotes_gpc')) {
  407.     array_walk($_GET, '_fix_gpc_magic');
  408.     array_walk($_POST, '_fix_gpc_magic');
  409.     array_walk($_COOKIE, '_fix_gpc_magic');
  410.     array_walk($_REQUEST, '_fix_gpc_magic');
  411.     $fixed = true;
  412.   }
  413. }
  414.  
  415. /**
  416.  * @name Conversion
  417.  * @{
  418.  * Converts data structures to different types.
  419.  */
  420.  
  421. /**
  422.  * Convert an associative array to an anonymous object.
  423.  */
  424. function array2object($array) {
  425.   if (is_array($array)) {
  426.     $object = new StdClass();
  427.     foreach ($array as $key => $value) {
  428.       $object->$key = $value;
  429.     }
  430.   }
  431.   else {
  432.     $object = $array;
  433.   }
  434.  
  435.   return $object;
  436. }
  437.  
  438. /**
  439.  * Convert an object to an associative array.
  440.  */
  441. function object2array($object) {
  442.   if (is_object($object)) {
  443.     foreach ($object as $key => $value) {
  444.       $array[$key] = $value;
  445.     }
  446.   }
  447.   else {
  448.     $array = $object;
  449.   }
  450.  
  451.   return $array;
  452. }
  453.  
  454. /**
  455.  * @} End of "Conversion".
  456.  */
  457.  
  458. /**
  459.  * @name Messages
  460.  * @{
  461.  * Frequently used messages.
  462.  */
  463.  
  464. /**
  465.  * Return a string with an "access denied" message.
  466.  *
  467.  * Always consider whether to use drupal_access_denied() instead to return a
  468.  * proper (and customizable) 403 error.
  469.  */
  470. function message_access() {
  471.   return t('You are not authorized to access this page.');
  472. }
  473.  
  474. /**
  475.  * Return a string with a "not applicable" message.
  476.  */
  477. function message_na() {
  478.   return t('n/a');
  479. }
  480.  
  481. /**
  482.  * @} End of "Messages".
  483.  */
  484.  
  485. /**
  486.  * Initialize the localization system.
  487.  */
  488. function locale_initialize() {
  489.   global $user;
  490.  
  491.   if (function_exists('i18n_get_lang')) {
  492.     return i18n_get_lang();
  493.   }
  494.  
  495.   if (function_exists('locale')) {
  496.     $languages = locale_supported_languages();
  497.     $languages = $languages['name'];
  498.   }
  499.   else {
  500.     // Ensure the locale/language is correctly returned, even without locale.module.
  501.     // Useful for e.g. XML/HTML 'lang' attributes.
  502.     $languages = array('en' => 'English');
  503.   }
  504.   if ($user->uid && $languages[$user->language]) {
  505.     return $user->language;
  506.   }
  507.   else {
  508.     return key($languages);
  509.   }
  510. }
  511.  
  512. /**
  513.  * Translate strings to the current locale.
  514.  *
  515.  * When using t(), try to put entire sentences and strings in one t() call.
  516.  * This makes it easier for translators. HTML markup within translation strings
  517.  * is acceptable, if necessary. The suggested syntax for a link embedded
  518.  * within a translation string is:
  519.  * @code
  520.  *   $msg = t('You must log in below or <a href="%url">create a new
  521.  *             account</a> before viewing the next page.', array('%url'
  522.  *             => url('user/register')));
  523.  * @endcode
  524.  * We suggest the same syntax for links to other sites. This makes it easy to
  525.  * change link URLs if needed (which happens often) without requiring updates
  526.  * to translations.
  527.  *
  528.  * @param $string
  529.  *   A string containing the English string to translate.
  530.  * @param $args
  531.  *   An associative array of replacements to make after translation. Incidences
  532.  *   of any key in this array are replaced with the corresponding value.
  533.  * @return
  534.  *   The translated string.
  535.  */
  536. function t($string, $args = 0) {
  537.   global $locale;
  538.   if (function_exists('locale') && $locale != 'en') {
  539.     $string = locale($string);
  540.   }
  541.  
  542.   if (!$args) {
  543.     return $string;
  544.   }
  545.   else {
  546.     return strtr($string, $args);
  547.   }
  548. }
  549.  
  550. /**
  551.  * Encode special characters in a plain-text string for display as HTML.
  552.  */
  553. function check_plain($text) {
  554.   return htmlspecialchars($text, ENT_QUOTES);
  555. }
  556.  
  557. /**
  558.  * @defgroup validation Input validation
  559.  * @{
  560.  * Functions to validate user input.
  561.  */
  562.  
  563. /**
  564.  * Verify the syntax of the given e-mail address.
  565.  *
  566.  * Empty e-mail addresses are allowed. See RFC 2822 for details.
  567.  *
  568.  * @param $mail
  569.  *   A string containing an email address.
  570.  * @return
  571.  *   TRUE if the address is in a valid format.
  572.  */
  573. function valid_email_address($mail) {
  574.   $user = '[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\']+';
  575.   $domain = '(?:(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.?)+';
  576.   $ipv4 = '[0-9]{1,3}(\.[0-9]{1,3}){3}';
  577.   $ipv6 = '[0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7}';
  578.  
  579.   return preg_match("/^$user@($domain|(\[($ipv4|$ipv6)\]))$/", $mail);
  580. }
  581.  
  582. /**
  583.  * Verify the syntax of the given URL.
  584.  *
  585.  * @param $url
  586.  *   The URL to verify.
  587.  * @param $absolute
  588.  *   Whether the URL is absolute (beginning with a scheme such as "http:").
  589.  * @return
  590.  *   TRUE if the URL is in a valid format.
  591.  */
  592. function valid_url($url, $absolute = FALSE) {
  593.   $allowed_characters = '[a-z0-9\/:_\-_\.\?\$,~=#&%\+]';
  594.   if ($absolute) {
  595.     return preg_match("/^(http|https|ftp):\/\/". $allowed_characters ."+$/i", $url);
  596.   }
  597.   else {
  598.     return preg_match("/^". $allowed_characters ."+$/i", $url);
  599.   }
  600. }
  601.  
  602. /**
  603.  * Validate data input by a user.
  604.  *
  605.  * Ensures that user data cannot be used to perform attacks on the site.
  606.  *
  607.  * @param $data
  608.  *   The input to check.
  609.  * @return
  610.  *   TRUE if the input data is acceptable.
  611.  */
  612. function valid_input_data($data) {
  613.   if (is_array($data) || is_object($data)) {
  614.     // Form data can contain a number of nested arrays.
  615.     foreach ($data as $key => $value) {
  616.       if (!valid_input_data($key) || !valid_input_data($value)) {
  617.         return FALSE;
  618.       }
  619.     }
  620.   }
  621.   else if (isset($data)) {
  622.     // Detect dangerous input data.
  623.  
  624.     // Decode all normal character entities.
  625.     $data = decode_entities($data, array('<', '&', '"'));
  626.  
  627.     // Check strings:
  628.     $match  = preg_match('/\Wjavascript\s*:/i', $data);
  629.     $match += preg_match('/\Wexpression\s*\(/i', $data);
  630.     $match += preg_match('/\Walert\s*\(/i', $data);
  631.  
  632.     // Check attributes:
  633.     $match += preg_match("/\W(dynsrc|datasrc|data|lowsrc|on[a-z]+)\s*=[^>]+?>/i", $data);
  634.  
  635.     // Check tags:
  636.     $match += preg_match("/<\s*(applet|script|object|style|embed|form|blink|meta|html|frame|iframe|layer|ilayer|head|frameset|xml)/i", $data);
  637.  
  638.     if ($match) {
  639.       watchdog('security', t('Terminated request because of suspicious input data: %data.', array('%data' => theme('placeholder', $data))));
  640.       return FALSE;
  641.     }
  642.   }
  643.  
  644.   return TRUE;
  645. }
  646. /**
  647.  * @} End of "defgroup validation".
  648.  */
  649.  
  650. /**
  651.  * Register an event for the current visitor (hostname/IP) to the flood control mechanism.
  652.  *
  653.  * @param $name
  654.  *   The name of the event.
  655.  */
  656. function flood_register_event($name) {
  657.   db_query("INSERT INTO {flood} (event, hostname, timestamp) VALUES ('%s', '%s', %d)", $name, $_SERVER['REMOTE_ADDR'], time());
  658. }
  659.  
  660. /**
  661.  * Check if the current visitor (hostname/IP) is allowed to proceed with the specified event.
  662.  * The user is allowed to proceed if he did not trigger the specified event more than
  663.  * $threshold times per hour.
  664.  *
  665.  * @param $name
  666.  *   The name of the event.
  667.  * @param $number
  668.  *   The maximum number of the specified event per hour (per visitor).
  669.  * @return
  670.  *   True if the user did not exceed the hourly threshold.  False otherwise.
  671.  */
  672. function flood_is_allowed($name, $threshold) {
  673.   $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));
  674.   return ($number < $threshold ? TRUE : FALSE);
  675. }
  676.  
  677. function check_file($filename) {
  678.   return is_uploaded_file($filename);
  679. }
  680.  
  681. /**
  682.  * @defgroup format Formatting
  683.  * @{
  684.  * Functions to format numbers, strings, dates, etc.
  685.  */
  686.  
  687. /**
  688.  * Formats an RSS channel.
  689.  *
  690.  * Arbitrary elements may be added using the $args associative array.
  691.  */
  692. function format_rss_channel($title, $link, $description, $items, $language = 'en', $args = array()) {
  693.   // arbitrary elements may be added using the $args associative array
  694.  
  695.   $output = "<channel>\n";
  696.   $output .= ' <title>'. check_plain($title) ."</title>\n";
  697.   $output .= ' <link>'. check_url($link) ."</link>\n";
  698.   $output .= ' <description>'. check_plain($description) ."</description>\n";
  699.   $output .= ' <language>'. check_plain($language) ."</language>\n";
  700.   foreach ($args as $key => $value) {
  701.     $output .= ' <'. $key .'>'. check_plain($value) ."</$key>\n";
  702.   }
  703.   $output .= $items;
  704.   $output .= "</channel>\n";
  705.  
  706.   return $output;
  707. }
  708.  
  709. /**
  710.  * Format a single RSS item.
  711.  *
  712.  * Arbitrary elements may be added using the $args associative array.
  713.  */
  714. function format_rss_item($title, $link, $description, $args = array()) {
  715.   $output = "<item>\n";
  716.   $output .= ' <title>'. check_plain($title) ."</title>\n";
  717.   $output .= ' <link>'. check_url($link) ."</link>\n";
  718.   $output .= ' <description>'. check_plain($description) ."</description>\n";
  719.   foreach ($args as $key => $value) {
  720.     if (is_array($value)) {
  721.       if ($value['key']) {
  722.         $output .= ' <'. $value['key'];
  723.         if (is_array($value['attributes'])) {
  724.           $output .= drupal_attributes($value['attributes']);
  725.         }
  726.  
  727.         if ($value['value']) {
  728.           $output .= '>'. $value['value'] .'</'. $value['key'] .">\n";
  729.         }
  730.         else {
  731.           $output .= " />\n";
  732.         }
  733.       }
  734.     }
  735.     else {
  736.       $output .= ' <'. $key .'>'. check_plain($value) ."</$key>\n";
  737.     }
  738.   }
  739.   $output .= "</item>\n";
  740.  
  741.   return $output;
  742. }
  743.  
  744. /**
  745.  * Format a string containing a count of items.
  746.  *
  747.  * This function ensures that the string is pluralized correctly. Since t() is
  748.  * called by this function, make sure not to pass already-localized strings to it.
  749.  *
  750.  * @param $count
  751.  *   The item count to display.
  752.  * @param $singular
  753.  *   The string for the singular case. Please make sure it is clear this is
  754.  *   singular, to ease translation (e.g. use "1 new comment" instead of "1 new").
  755.  * @param $plural
  756.  *   The string for the plural case. Please make sure it is clear this is plural,
  757.  *   to ease translation. Use %count in place of the item count, as in "%count
  758.  *   new comments".
  759.  * @return
  760.  *   A translated string.
  761.  */
  762. function format_plural($count, $singular, $plural) {
  763.   if ($count == 1) return t($singular, array("%count" => $count));
  764.  
  765.   // get the plural index through the gettext formula
  766.   $index = (function_exists('locale')) ? locale_get_plural($count) : -1;
  767.   if ($index < 0) { // backward compatibility
  768.     return t($plural, array("%count" => $count));
  769.   }
  770.   else {
  771.     switch ($index) {
  772.       case "0":
  773.         return t($singular, array("%count" => $count));
  774.       case "1":
  775.         return t($plural, array("%count" => $count));
  776.       default:
  777.         return t(strtr($plural, array("%count" => '%count['. $index .']')), array('%count['. $index .']' => $count));
  778.     }
  779.   }
  780. }
  781.  
  782. /**
  783.  * Generate a string representation for the given byte count.
  784.  *
  785.  * @param $size
  786.  *   The size in bytes.
  787.  * @return
  788.  *   A translated string representation of the size.
  789.  */
  790. function format_size($size) {
  791.   $suffix = t('bytes');
  792.   if ($size > 1024) {
  793.     $size = round($size / 1024, 2);
  794.     $suffix = t('KB');
  795.   }
  796.   if ($size > 1024) {
  797.     $size = round($size / 1024, 2);
  798.     $suffix = t('MB');
  799.   }
  800.   return t('%size %suffix', array('%size' => $size, '%suffix' => $suffix));
  801. }
  802.  
  803. /**
  804.  * Format a time interval with the requested granularity.
  805.  *
  806.  * @param $timestamp
  807.  *   The length of the interval in seconds.
  808.  * @param $granularity
  809.  *   How many different units to display in the string.
  810.  * @return
  811.  *   A translated string representation of the interval.
  812.  */
  813. function format_interval($timestamp, $granularity = 2) {
  814.   $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);
  815.   $output = '';
  816.   foreach ($units as $key => $value) {
  817.     $key = explode('|', $key);
  818.     if ($timestamp >= $value) {
  819.       $output .= ($output ? ' ' : '') . format_plural(floor($timestamp / $value), $key[0], $key[1]);
  820.       $timestamp %= $value;
  821.       $granularity--;
  822.     }
  823.  
  824.     if ($granularity == 0) {
  825.       break;
  826.     }
  827.   }
  828.   return $output ? $output : t('0 sec');
  829. }
  830.  
  831. /**
  832.  * Format a date with the given configured format or a custom format string.
  833.  *
  834.  * Drupal allows administrators to select formatting strings for 'small',
  835.  * 'medium' and 'large' date formats. This function can handle these formats,
  836.  * as well as any custom format.
  837.  *
  838.  * @param $timestamp
  839.  *   The exact date to format, as a UNIX timestamp.
  840.  * @param $type
  841.  *   The format to use. Can be "small", "medium" or "large" for the preconfigured
  842.  *   date formats. If "custom" is specified, then $format is required as well.
  843.  * @param $format
  844.  *   A PHP date format string as required by date(). A backslash should be used
  845.  *   before a character to avoid interpreting the character as part of a date
  846.  *   format.
  847.  * @param $timezone
  848.  *   Time zone offset in seconds; if omitted, the user's time zone is used.
  849.  * @return
  850.  *   A translated date string in the requested format.
  851.  */
  852. function format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL) {
  853.   if ($timezone === NULL) {
  854.     global $user;
  855.     if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) {
  856.       $timezone = $user->timezone;
  857.     }
  858.     else {
  859.       $timezone = variable_get('date_default_timezone', 0);
  860.     }
  861.   }
  862.  
  863.   $timestamp += $timezone;
  864.  
  865.   switch ($type) {
  866.     case 'small':
  867.       $format = variable_get('date_format_short', 'm/d/Y - H:i');
  868.       break;
  869.     case 'large':
  870.       $format = variable_get('date_format_long', 'l, F j, Y - H:i');
  871.       break;
  872.     case 'custom':
  873.       // No change to format
  874.       break;
  875.     case 'medium':
  876.     default:
  877.       $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
  878.   }
  879.  
  880.   $max = strlen($format);
  881.   $date = '';
  882.   for ($i = 0; $i < $max; $i++) {
  883.     $c = $format{$i};
  884.     if (strpos('AaDFlM', $c) !== false) {
  885.       $date .= t(gmdate($c, $timestamp));
  886.     }
  887.     else if (strpos('BdgGhHiIjLmnsStTUwWYyz', $c) !== false) {
  888.       $date .= gmdate($c, $timestamp);
  889.     }
  890.     else if ($c == 'r') {
  891.       $date .= format_date($timestamp - $timezone, 'custom', 'D, d M Y H:i:s O', $timezone);
  892.     }
  893.     else if ($c == 'O') {
  894.       $date .= sprintf('%s%02d%02d', ($timezone < 0 ? '-' : '+'), abs($timezone / 3600), abs($timezone % 3600) / 60);
  895.     }
  896.     else if ($c == 'Z') {
  897.       $date .= $timezone;
  898.     }
  899.     else if ($c == '\\') {
  900.       $date .= $format[++$i];
  901.     }
  902.     else {
  903.       $date .= $c;
  904.     }
  905.   }
  906.  
  907.   return $date;
  908. }
  909.  
  910. /**
  911.  * Format a username.
  912.  *
  913.  * @param $object
  914.  *   The user object to format, usually returned from user_load().
  915.  * @return
  916.  *   A string containing an HTML link to the user's page if the passed object
  917.  *   suggests that this is a site user. Otherwise, only the username is returned.
  918.  */
  919. function format_name($object) {
  920.  
  921.   if ($object->uid && $object->name) {
  922.     // Shorten the name when it is too long or it will break many tables.
  923.     if (strlen($object->name) > 20) {
  924.       $name = truncate_utf8($object->name, 15) .'...';
  925.     }
  926.     else {
  927.       $name = $object->name;
  928.     }
  929.  
  930.     if (user_access('access user profiles')) {
  931.       $output = l($name, 'user/'. $object->uid, array('title' => t('View user profile.')));
  932.     }
  933.     else {
  934.       $output = $name;
  935.     }
  936.   }
  937.   else if ($object->name) {
  938.     // Sometimes modules display content composed by people who are
  939.     // not registered members of the site (e.g. mailing list or news
  940.     // aggregator modules). This clause enables modules to display
  941.     // the true author of the content.
  942.     if ($object->homepage) {
  943.       $output = '<a href="'. $object->homepage .'">'. $object->name .'</a>';
  944.     }
  945.     else {
  946.       $output = $object->name;
  947.     }
  948.  
  949.     $output .= ' ('. t('not verified') .')';
  950.   }
  951.   else {
  952.     $output = variable_get('anonymous', 'Anonymous');
  953.   }
  954.  
  955.   return $output;
  956. }
  957. /**
  958.  * @} End of "defgroup format".
  959.  */
  960.  
  961. /**
  962.  * @defgroup form Form generation
  963.  * @{
  964.  * Functions to enable output of HTML forms and form elements.
  965.  *
  966.  * Drupal uses these functions to achieve consistency in its form presentation,
  967.  * while at the same time simplifying code and reducing the amount of HTML that
  968.  * must be explicitly generated by modules.
  969.  */
  970.  
  971. /**
  972.  * Generate a form from a set of form elements.
  973.  *
  974.  * @param $form
  975.  *   An HTML string containing one or more form elements.
  976.  * @param $method
  977.  *   The query method to use ("post" or "get").
  978.  * @param $action
  979.  *   The URL to send the form contents to, if not the current page.
  980.  * @param $attributes
  981.  *   An associative array of attributes to add to the form tag.
  982.  * @result
  983.  *   An HTML string with the contents of $form wrapped in a form tag.
  984.  */
  985. function form($form, $method = 'post', $action = NULL, $attributes = NULL) {
  986.   if (!$action) {
  987.     $action = request_uri();
  988.   }
  989.   return '<form action="'. check_url($action) .'" method="'. $method .'"'. drupal_attributes($attributes) .">\n". $form ."\n</form>\n";
  990. }
  991.  
  992. /**
  993.  * File an error against the form element with the specified name.
  994.  */
  995. function form_set_error($name, $message) {
  996.   $GLOBALS['form'][$name] = $message;
  997.   drupal_set_message($message, 'error');
  998. }
  999.  
  1000. /**
  1001.  * Return an associative array of all errors.
  1002.  */
  1003. function form_get_errors() {
  1004.   if (array_key_exists('form', $GLOBALS)) {
  1005.     return $GLOBALS['form'];
  1006.   }
  1007. }
  1008.  
  1009. /**
  1010.  * Return the error message filed against the form with the specified name.
  1011.  */
  1012. function _form_get_error($name) {
  1013.   if (array_key_exists('form', $GLOBALS)) {
  1014.     return $GLOBALS['form'][$name];
  1015.   }
  1016. }
  1017.  
  1018. function _form_get_class($name, $required, $error) {
  1019.   return $name. ($required ? ' required' : '') . ($error ? ' error' : '');
  1020. }
  1021.  
  1022. /**
  1023.  * Format a general form item.
  1024.  *
  1025.  * @param $title
  1026.  *   The label for the form item.
  1027.  * @param $value
  1028.  *   The contents of the form item.
  1029.  * @param $description
  1030.  *   Explanatory text to display after the form item.
  1031.  * @param $id
  1032.  *   A unique identifier for the form item.
  1033.  * @param $required
  1034.  *   Whether the user must fill in this form element before submitting the form.
  1035.  * @param $error
  1036.  *   An error message to display alongside the form element.
  1037.  * @return
  1038.  *   A themed HTML string representing the form item.
  1039.  */
  1040. function form_item($title, $value, $description = NULL, $id = NULL, $required = FALSE, $error = FALSE) {
  1041.   return theme('form_element', $title, $value, $description, $id, $required, $error);
  1042. }
  1043.  
  1044. /**
  1045.  * Format a group of form items.
  1046.  *
  1047.  * @param $legend
  1048.  *   The label for the form item group.
  1049.  * @param $group
  1050.  *   The form items within the group, as an HTML string.
  1051.  * @param $description
  1052.  *   Explanatory text to display after the form item group.
  1053.  * @return
  1054.  *   A themed HTML string representing the form item group.
  1055.  */
  1056. function form_group($legend, $group, $description = NULL) {
  1057.   return '<fieldset>' . ($legend ? '<legend>'. $legend .'</legend>' : '') . $group . ($description ? '<div class="description">'. $description .'</div>' : '') . "</fieldset>\n";
  1058. }
  1059.  
  1060. /**
  1061.  * Format a radio button.
  1062.  *
  1063.  * @param $title
  1064.  *   The label for the radio button.
  1065.  * @param $name
  1066.  *   The internal name used to refer to the button.
  1067.  * @param $value
  1068.  *   The value that the form element takes on when selected.
  1069.  * @param $checked
  1070.  *   Whether the button will be initially selected when the page is rendered.
  1071.  * @param $description
  1072.  *   Explanatory text to display after the form item.
  1073.  * @param $attributes
  1074.  *   An associative array of HTML attributes to add to the button.
  1075.  * @param $required
  1076.  *   Whether the user must select this radio button before submitting the form.
  1077.  * @return
  1078.  *   A themed HTML string representing the radio button.
  1079.  */
  1080. function form_radio($title, $name, $value = 1, $checked = FALSE, $description = NULL, $attributes = NULL, $required = FALSE) {
  1081.   $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) .' />';
  1082.   if (!is_null($title)) {
  1083.     $element = '<label class="option">'. $element .' '. $title .'</label>';
  1084.   }
  1085.   return theme('form_element', NULL, $element, $description, $name, $required, _form_get_error($name));
  1086. }
  1087.  
  1088. /**
  1089.  * Format a set of radio buttons.
  1090.  *
  1091.  * @param $title
  1092.  *   The label for the radio buttons as a group.
  1093.  * @param $name
  1094.  *   The internal name used to refer to the buttons.
  1095.  * @param $value
  1096.  *   The currently selected radio button's key.
  1097.  * @param $options
  1098.  *   An associative array of buttons to display. The keys in this array are
  1099.  *   button values, while the values are the labels to display for each button.
  1100.  * @param $description
  1101.  *   Explanatory text to display after the form item.
  1102.  * @param $required
  1103.  *   Whether the user must select a radio button before submitting the form.
  1104.  * @param $attributes
  1105.  *   An associative array of HTML attributes to add to each button.
  1106.  * @return
  1107.  *   A themed HTML string representing the radio button set.
  1108.  */
  1109. function form_radios($title, $name, $value, $options, $description = NULL, $required = FALSE, $attributes = NULL) {
  1110.   if (count($options) > 0) {
  1111.     $choices = '';
  1112.     foreach ($options as $key => $choice) {
  1113.       $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 />';
  1114.     }
  1115.     return theme('form_element', $title, $choices, $description, NULL, $required, _form_get_error($name));
  1116.   }
  1117. }
  1118.  
  1119. /**
  1120.  * Format a checkbox.
  1121.  *
  1122.  * @param $title
  1123.  *   The label for the checkbox.
  1124.  * @param $name
  1125.  *   The internal name used to refer to the button.
  1126.  * @param $value
  1127.  *   The value that the form element takes on when selected.
  1128.  * @param $checked
  1129.  *   Whether the button will be initially selected when the page is rendered.
  1130.  * @param $description
  1131.  *   Explanatory text to display after the form item.
  1132.  * @param $attributes
  1133.  *   An associative array of HTML attributes to add to the button.
  1134.  * @param $required
  1135.  *   Whether the user must check this box before submitting the form.
  1136.  * @return
  1137.  *   A themed HTML string representing the checkbox.
  1138.  */
  1139. function form_checkbox($title, $name, $value = 1, $checked = FALSE, $description = NULL, $attributes = NULL, $required = FALSE) {
  1140.   $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) .' />';
  1141.   if (!is_null($title)) {
  1142.     $element = '<label class="option">'. $element .' '. $title .'</label>';
  1143.   }
  1144.   // Note: because unchecked boxes are not included in the POST data, we include
  1145.   // a form_hidden() which will be overwritten for a checked box.
  1146.   return form_hidden($name, 0) . theme('form_element', NULL, $element, $description, $name, $required, _form_get_error($name));
  1147. }
  1148.  
  1149. /**
  1150.  * Format a set of checkboxes.
  1151.  *
  1152.  * @param $title
  1153.  *   The label for the checkboxes as a group.
  1154.  * @param $name
  1155.  *   The internal name used to refer to the buttons.
  1156.  * @param $values
  1157.  *   A linear array of keys of the initially checked boxes.
  1158.  * @param $options
  1159.  *   An associative array of buttons to display. The keys in this array are
  1160.  *   button values, while the values are the labels to display for each button.
  1161.  * @param $description
  1162.  *   Explanatory text to display after the form item.
  1163.  * @param $attributes
  1164.  *   An associative array of HTML attributes to add to each button.
  1165.  * @param $required
  1166.  *   Whether the user must check a box before submitting the form.
  1167.  * @return
  1168.  *   A themed HTML string representing the radio button set.
  1169.  */
  1170. function form_checkboxes($title, $name, $values, $options, $description = NULL, $attributes = NULL, $required = FALSE) {
  1171.   if (count($options) > 0) {
  1172.     if (!isset($values) || $values == 0) {
  1173.       $values = array();
  1174.     }
  1175.     $choices = '';
  1176.     foreach ($options as $key => $choice) {
  1177.       $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 />';
  1178.     }
  1179.     // Note: because unchecked boxes are not included in the POST data, we
  1180.     // include a form_hidden() which will be overwritten as soon as there is at
  1181.     // least one checked box.
  1182.     return form_hidden($name, 0) . theme('form_element', $title, $choices, $description, NULL, $required, _form_get_error($name));
  1183.   }
  1184. }
  1185.  
  1186. /**
  1187.  * Format a single-line text field.
  1188.  *
  1189.  * @param $title
  1190.  *   The label for the text field.
  1191.  * @param $name
  1192.  *   The internal name used to refer to the field.
  1193.  * @param $value
  1194.  *   The initial value for the field at page load time.
  1195.  * @param $size
  1196.  *   A measure of the visible size of the field (passed directly to HTML).
  1197.  * @param $maxlength
  1198.  *   The maximum number of characters that may be entered in the field.
  1199.  * @param $description
  1200.  *   Explanatory text to display after the form item.
  1201.  * @param $attributes
  1202.  *   An associative array of HTML attributes to add to the form item.
  1203.  * @param $required
  1204.  *   Whether the user must enter some text in the field.
  1205.  * @return
  1206.  *   A themed HTML string representing the field.
  1207.  */
  1208. function form_textfield($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL, $required = FALSE) {
  1209.   $size = $size ? ' size="'. $size .'"' : '';
  1210.   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="edit-'. $name .'"'. $size .' value="'. check_plain($value) .'"'. drupal_attributes($attributes) .' />', $description, 'edit-'. $name, $required, _form_get_error($name));
  1211. }
  1212.  
  1213. /**
  1214.  * Format a single-line text field that does not display its contents visibly.
  1215.  *
  1216.  * @param $title
  1217.  *   The label for the text field.
  1218.  * @param $name
  1219.  *   The internal name used to refer to the field.
  1220.  * @param $value
  1221.  *   The initial value for the field at page load time.
  1222.  * @param $size
  1223.  *   A measure of the visible size of the field (passed directly to HTML).
  1224.  * @param $maxlength
  1225.  *   The maximum number of characters that may be entered in the field.
  1226.  * @param $description
  1227.  *   Explanatory text to display after the form item.
  1228.  * @param $attributes
  1229.  *   An associative array of HTML attributes to add to the form item.
  1230.  * @param $required
  1231.  *   Whether the user must enter some text in the field.
  1232.  * @return
  1233.  *   A themed HTML string representing the field.
  1234.  */
  1235. function form_password($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL, $required = FALSE) {
  1236.   $size = $size ? ' size="'. $size .'"' : '';
  1237.   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="edit-'. $name .'"'. $size .' value="'. check_plain($value) .'"'. drupal_attributes($attributes) .' />', $description, 'edit-'. $name, $required, _form_get_error($name));
  1238. }
  1239.  
  1240. /**
  1241.  * Format a multiple-line text field.
  1242.  *
  1243.  * @param $title
  1244.  *   The label for the text field.
  1245.  * @param $name
  1246.  *   The internal name used to refer to the field.
  1247.  * @param $value
  1248.  *   The initial value for the field at page load time.
  1249.  * @param $cols
  1250.  *   The width of the field, in columns of text.
  1251.  * @param $rows
  1252.  *   The height of the field, in rows of text.
  1253.  * @param $description
  1254.  *   Explanatory text to display after the form item.
  1255.  * @param $attributes
  1256.  *   An associative array of HTML attributes to add to the form item.
  1257.  * @param $required
  1258.  *   Whether the user must enter some text in the field.
  1259.  * @return
  1260.  *   A themed HTML string representing the field.
  1261.  */
  1262. function form_textarea($title, $name, $value, $cols, $rows, $description = NULL, $attributes = NULL, $required = FALSE) {
  1263.   $cols = $cols ? ' cols="'. $cols .'"' : '';
  1264.   $pre = '';
  1265.   $post = '';
  1266.  
  1267.   // optionally plug in a WYSIWYG editor
  1268.   foreach (module_list() as $module_name) {
  1269.     if (module_hook($module_name, 'textarea')) {
  1270.       $pre  .= module_invoke($module_name, 'textarea', 'pre', $name);
  1271.       $post .= module_invoke($module_name, 'textarea', 'post', $name);
  1272.     }
  1273.   }
  1274.  
  1275.   return theme('form_element', $title, $pre .'<textarea wrap="virtual"'. $cols .' rows="'. $rows .'" name="edit['. $name .']" id="edit-'. $name .'" class="'. _form_get_class('textarea', $required, _form_get_error($name)) .'"'. drupal_attributes($attributes) .'>'. check_plain($value) .'</textarea>'. $post, $description, 'edit-'. $name, $required, _form_get_error($name));
  1276. }
  1277.  
  1278. /**
  1279.  * Format a dropdown menu or scrolling selection box.
  1280.  *
  1281.  * @param $title
  1282.  *   The label for the form element.
  1283.  * @param $name
  1284.  *   The internal name used to refer to the form element.
  1285.  * @param $value
  1286.  *   The key of the currently selected item, or a linear array of keys of all the
  1287.  *   currently selected items if multiple selections are allowed.
  1288.  * @param $options
  1289.  *   An associative array of buttons to display. The keys in this array are
  1290.  *   button values, while the values are the labels to display for each button.
  1291.  * @param $description
  1292.  *   Explanatory text to display after the form item.
  1293.  * @param $extra
  1294.  *   Additional HTML to inject into the select element tag.
  1295.  * @param $multiple
  1296.  *   Whether the user may select more than one item.
  1297.  * @param $required
  1298.  *   Whether the user must select a value before submitting the form.
  1299.  * @return
  1300.  *   A themed HTML string representing the form element.
  1301.  *
  1302.  * It is possible to group options together; to do this, change the format of
  1303.  * $options to an associative array in which the keys are group labels, and the
  1304.  * values are associative arrays in the normal $options format.
  1305.  */
  1306. function form_select($title, $name, $value, $options, $description = NULL, $extra = 0, $multiple = FALSE, $required = FALSE) {
  1307.   $select = '';
  1308.   foreach ($options as $key => $choice) {
  1309.     if (is_array($choice)) {
  1310.       $select .= '<optgroup label="'. $key .'">';
  1311.       foreach ($choice as $key => $choice) {
  1312.         $select .= '<option value="'. $key .'"'. (is_array($value) ? (in_array($key, $value) ? ' selected="selected"' : '') : ($value == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>';
  1313.       }
  1314.       $select .= '</optgroup>';
  1315.     }
  1316.     else {
  1317.       $select .= '<option value="'. $key .'"'. (is_array($value) ? (in_array($key, $value) ? ' selected="selected"' : '') : ($value == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>';
  1318.     }
  1319.   }
  1320.   return theme('form_element', $title, '<select name="edit['. $name .']'. ($multiple ? '[]' : '') .'"'. ($multiple ? ' multiple="multiple" ' : '') . ($extra ? ' '. $extra : '') .' id="edit-'. $name .'">'. $select .'</select>', $description, 'edit-'. $name, $required, _form_get_error($name));
  1321. }
  1322.  
  1323. /**
  1324.  * Format a file upload field.
  1325.  *
  1326.  * @param $title
  1327.  *   The label for the file upload field.
  1328.  * @param $name
  1329.  *   The internal name used to refer to the field.
  1330.  * @param $size
  1331.  *   A measure of the visible size of the field (passed directly to HTML).
  1332.  * @param $description
  1333.  *   Explanatory text to display after the form item.
  1334.  * @param $required
  1335.  *   Whether the user must upload a file to the field.
  1336.  * @return
  1337.  *   A themed HTML string representing the field.
  1338.  *
  1339.  * For assistance with handling the uploaded file correctly, see the API
  1340.  * provided by file.inc.
  1341.  */
  1342. function form_file($title, $name, $size, $description = NULL, $required = FALSE) {
  1343.   return theme('form_element', $title, '<input type="file" class="'. _form_get_class('form-file', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. $name .'" size="'. $size ."\" />\n", $description, 'edit-'. $name, $required, _form_get_error($name));
  1344. }
  1345.  
  1346. /**
  1347.  * Store data in a hidden form field.
  1348.  *
  1349.  * @param $name
  1350.  *   The internal name used to refer to the field.
  1351.  * @param $value
  1352.  *   The stored data.
  1353.  * @return
  1354.  *   A themed HTML string representing the hidden field.
  1355.  *
  1356.  * This function can be useful in retaining information between page requests,
  1357.  * but be sure to validate the data on the receiving page as it is possible for
  1358.  * an attacker to change the value before it is submitted.
  1359.  */
  1360. function form_hidden($name, $value) {
  1361.   return '<input type="hidden" name="edit['. $name .']" value="'. check_plain($value) ."\" />\n";
  1362. }
  1363.  
  1364. /**
  1365.  * Format an action button.
  1366.  *
  1367.  * @param $value
  1368.  *   Both the label for the button, and the value passed to the target page
  1369.  *   when this button is clicked.
  1370.  * @param $name
  1371.  *   The internal name used to refer to the button.
  1372.  * @param $type
  1373.  *   What type to pass to the HTML input tag.
  1374.  * @param $attributes
  1375.  *   An associative array of HTML attributes to add to the form item.
  1376.  * @return
  1377.  *   A themed HTML string representing the button.
  1378.  */
  1379. function form_button($value, $name = 'op', $type = 'submit', $attributes = NULL) {
  1380.   return '<input type="'. $type .'" class="form-'. $type .'" name="'. $name .'" value="'. check_plain($value) .'" '. drupal_attributes($attributes) ." />\n";
  1381. }
  1382.  
  1383. /**
  1384.  * Format a form submit button.
  1385.  *
  1386.  * @param $value
  1387.  *   Both the label for the button, and the value passed to the target page
  1388.  *   when this button is clicked.
  1389.  * @param $name
  1390.  *   The internal name used to refer to the button.
  1391.  * @param $attributes
  1392.  *   An associative array of HTML attributes to add to the form item.
  1393.  * @return
  1394.  *   A themed HTML string representing the button.
  1395.  */
  1396. function form_submit($value, $name = 'op', $attributes = NULL) {
  1397.   return form_button($value, $name, 'submit', $attributes);
  1398. }
  1399.  
  1400. /**
  1401.  * Format a weight selection menu.
  1402.  *
  1403.  * @param $title
  1404.  *   The label for the form element.
  1405.  * @param $name
  1406.  *   The internal name used to refer to the form element.
  1407.  * @param $value
  1408.  *   The selected weight value at page load time.
  1409.  * @param $delta
  1410.  *   The largest in absolute value the weight can be. For example, if set to 10,
  1411.  *   weights could range from -10 to 10 inclusive.
  1412.  * @param $description
  1413.  *   Explanatory text to display after the form item.
  1414.  * @param $extra
  1415.  *   Additional HTML to inject into the select element tag.
  1416.  * @return
  1417.  *   A themed HTML string representing the form element.
  1418.  */
  1419. function form_weight($title = NULL, $name = 'weight', $value = 0, $delta = 10, $description = NULL, $extra = 0) {
  1420.   for ($n = (-1 * $delta); $n <= $delta; $n++) {
  1421.     $weights[$n] = $n;
  1422.   }
  1423.  
  1424.   return form_select($title, $name, $value, $weights, $description, $extra);
  1425. }
  1426.  
  1427. /**
  1428.  * @} End of "defgroup form".
  1429.  */
  1430.  
  1431. /**
  1432.  * Generate an internal Drupal URL.
  1433.  *
  1434.  * @param $path
  1435.  *   The Drupal path being linked to, such as "admin/node".
  1436.  * @param $query
  1437.  *   A query string to append to the link.
  1438.  * @param $fragment
  1439.  *   A fragment identifier (named anchor) to append to the link.
  1440.  * @param $absolute
  1441.  *   Whether to force the output to be an absolute link (beginning with http:).
  1442.  *   Useful for links that will be displayed outside the site, such as in an RSS feed.
  1443.  * @return
  1444.  *   an HTML string containing a link to the given path.
  1445.  *
  1446.  * When creating links in modules, consider whether l() could be a better
  1447.  * alternative than url().
  1448.  */
  1449. function url($path = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE) {
  1450.   global $base_url;
  1451.  
  1452.   static $script;
  1453.  
  1454.   if (empty($script)) {
  1455.     // On some web servers, such as IIS, we can't omit "index.php".  So, we
  1456.     // generate "index.php?q=foo" instead of "?q=foo" on anything that is not
  1457.     // Apache.
  1458.     $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === false) ? 'index.php' : '';
  1459.   }
  1460.  
  1461.   $path = drupal_get_path_alias($path);
  1462.  
  1463.   if (isset($fragment)) {
  1464.     $fragment = '#'. $fragment;
  1465.   }
  1466.  
  1467.   $base = ($absolute ? $base_url .'/' : '');
  1468.  
  1469.   if (variable_get('clean_url', '0') == '0') {
  1470.     if (isset($path)) {
  1471.       if (isset($query)) {
  1472.         return $base . $script .'?q='. $path .'&'. $query . $fragment;
  1473.       }
  1474.       else {
  1475.         return $base . $script .'?q='. $path . $fragment;
  1476.       }
  1477.     }
  1478.     else {
  1479.       if (isset($query)) {
  1480.         return $base . $script .'?'. $query . $fragment;
  1481.       }
  1482.       else {
  1483.         return $base . $fragment;
  1484.       }
  1485.     }
  1486.   }
  1487.   else {
  1488.     if (isset($path)) {
  1489.       if (isset($query)) {
  1490.         return $base . $path .'?'. $query . $fragment;
  1491.       }
  1492.       else {
  1493.         return $base . $path . $fragment;
  1494.       }
  1495.     }
  1496.     else {
  1497.       if (isset($query)) {
  1498.         return $base . $script .'?'. $query . $fragment;
  1499.       }
  1500.       else {
  1501.         return $base . $fragment;
  1502.       }
  1503.     }
  1504.   }
  1505. }
  1506.  
  1507. /**
  1508.  * Format an attribute string to insert in a tag.
  1509.  *
  1510.  * @param $attributes
  1511.  *   An associative array of HTML attributes.
  1512.  * @return
  1513.  *   An HTML string ready for insertion in a tag.
  1514.  */
  1515. function drupal_attributes($attributes = array()) {
  1516.   if ($attributes) {
  1517.     $t = array();
  1518.     foreach ($attributes as $key => $value) {
  1519.       $t[] = $key .'="'. check_plain($value) .'"';
  1520.     }
  1521.  
  1522.     return ' '. implode($t, ' ');
  1523.   }
  1524. }
  1525.  
  1526. /**
  1527.  * Format an internal Drupal link.
  1528.  *
  1529.  * This function correctly handles aliased paths, and allows themes to highlight
  1530.  * links to the current page correctly, so all internal links output by modules
  1531.  * should be generated by this function if possible.
  1532.  *
  1533.  * @param $text
  1534.  *   The text to be enclosed with the anchor tag.
  1535.  * @param $path
  1536.  *   The Drupal path being linked to, such as "admin/node".
  1537.  * @param $attributes
  1538.  *   An associative array of HTML attributes to apply to the anchor tag.
  1539.  * @param $query
  1540.  *   A query string to append to the link.
  1541.  * @param $fragment
  1542.  *   A fragment identifier (named anchor) to append to the link.
  1543.  * @param $absolute
  1544.  *   Whether to force the output to be an absolute link (beginning with http:).
  1545.  *   Useful for links that will be displayed outside the site, such as in an RSS feed.
  1546.  * @param $html
  1547.  *   Whether the title is HTML, or just plain-text.
  1548.  * @return
  1549.  *   an HTML string containing a link to the given path.
  1550.  */
  1551. function l($text, $path, $attributes = array(), $query = NULL, $fragment = NULL, $absolute = FALSE, $html = FALSE) {
  1552.   if (drupal_get_normal_path($path) == $_GET['q']) {
  1553.     if (isset($attributes['class'])) {
  1554.       $attributes['class'] .= ' active';
  1555.     }
  1556.     else {
  1557.       $attributes['class'] = 'active';
  1558.     }
  1559.   }
  1560.   return '<a href="'. check_url(url($path, $query, $fragment, $absolute)) .'"'. drupal_attributes($attributes) .'>'. ($html ? $text : check_plain($text)) .'</a>';
  1561. }
  1562.  
  1563. /**
  1564.  * Perform end-of-request tasks.
  1565.  *
  1566.  * This function sets the page cache if appropriate, and allows modules to
  1567.  * react to the closing of the page by calling hook_exit().
  1568.  */
  1569. function drupal_page_footer() {
  1570.   if (variable_get('cache', 0)) {
  1571.     page_set_cache();
  1572.   }
  1573.  
  1574.   module_invoke_all('exit');
  1575. }
  1576.  
  1577. /**
  1578.  * Form an associative array from a linear array.
  1579.  *
  1580.  * This function walks through the provided array and constructs an associative
  1581.  * array out of it. The keys of the resulting array will be the values of the
  1582.  * input array. The values will be the same as the keys unless a function is
  1583.  * specified, in which case the output of the function is used for the values
  1584.  * instead.
  1585.  *
  1586.  * @param $array
  1587.  *   A linear array.
  1588.  * @param $function
  1589.  *   The name of a function to apply to all values before output.
  1590.  * @result
  1591.  *   An associative array.
  1592.  */
  1593. function drupal_map_assoc($array, $function = NULL) {
  1594.   if (!isset($function)) {
  1595.     $result = array();
  1596.     foreach ($array as $value) {
  1597.       $result[$value] = $value;
  1598.     }
  1599.     return $result;
  1600.   }
  1601.   elseif (function_exists($function)) {
  1602.     $result = array();
  1603.     foreach($array as $value) {
  1604.       $result[$value] = $function($value);
  1605.     }
  1606.     return $result;
  1607.   }
  1608. }
  1609.  
  1610. /**
  1611.  * Prepare a new XML parser.
  1612.  *
  1613.  * This is a wrapper around xml_parser_create() which extracts the encoding from
  1614.  * the XML data first and sets the output encoding to UTF-8. This function should
  1615.  * be used instead of xml_parser_create(), because PHP's XML parser doesn't check
  1616.  * the input encoding itself.
  1617.  *
  1618.  * This is also where unsupported encodings should be converted.
  1619.  * Callers should take this into account: $data might have been changed after
  1620.  * the call.
  1621.  *
  1622.  * @param &$data
  1623.  *   The XML data which will be parsed later.
  1624.  * @return
  1625.  *   An XML parser object.
  1626.  */
  1627. function drupal_xml_parser_create(&$data) {
  1628.   $encoding = 'utf-8';
  1629.   if (ereg('^<\?xml[^>]+encoding="([^"]+)"', $data, $match)) {
  1630.     $encoding = $match[1];
  1631.   }
  1632.  
  1633.   // Unsupported encodings are converted here into UTF-8.
  1634.   $php_supported = array('utf-8', 'iso-8859-1', 'us-ascii');
  1635.   if (!in_array(strtolower($encoding), $php_supported)) {
  1636.     $out = drupal_convert_to_utf8($data, $encoding);
  1637.     if ($out !== false) {
  1638.       $data = $out;
  1639.       $encoding = 'utf-8';
  1640.     }
  1641.     else {
  1642.       watchdog('php', t("Could not convert XML encoding '%s' to UTF-8.", $encoding), WATCHDOG_WARNING);
  1643.       return 0;
  1644.     }
  1645.   }
  1646.  
  1647.   $xml_parser = xml_parser_create($encoding);
  1648.   xml_parser_set_option($xml_parser, XML_OPTION_TARGET_ENCODING, 'utf-8');
  1649.   return $xml_parser;
  1650. }
  1651.  
  1652. /**
  1653.  * Convert data to UTF-8
  1654.  *
  1655.  * Requires the iconv, GNU recode or mbstring PHP extension.
  1656.  *
  1657.  * @param $data
  1658.  *   The data to be converted.
  1659.  * @param $encoding
  1660.  *   The encoding that the data is in
  1661.  * @return
  1662.  *   Converted data or FALSE.
  1663.  */
  1664. function drupal_convert_to_utf8($data, $encoding) {
  1665.   if (function_exists('iconv')) {
  1666.     $out = @iconv($encoding, 'utf-8', $data);
  1667.   }
  1668.   else if (function_exists('mb_convert_encoding')) {
  1669.     $out = @mb_convert_encoding($data, 'utf-8', $encoding);
  1670.   }
  1671.   else if (function_exists('recode_string')) {
  1672.     $out = @recode_string($encoding .'..utf-8', $data);
  1673.   }
  1674.   else {
  1675.     watchdog('php', t("Unsupported encoding '%s'. Please install iconv, GNU recode or mbstring for PHP.", $encoding), WATCHDOG_ERROR);
  1676.     return FALSE;
  1677.   }
  1678.  
  1679.   return $out;
  1680. }
  1681.  
  1682. /**
  1683.  * Truncate a UTF-8-encoded string safely.
  1684.  *
  1685.  * If the end position is in the middle of a UTF-8 sequence, it scans backwards
  1686.  * until the beginning of the byte sequence.
  1687.  *
  1688.  * Use this function whenever you want to chop off a string at an unsure
  1689.  * location. On the other hand, if you're sure that you're splitting on a
  1690.  * character boundary (e.g. after using strpos() or similar), you can safely use
  1691.  * substr() instead.
  1692.  *
  1693.  * @param $string
  1694.  *   The string to truncate.
  1695.  * @param $len
  1696.  *   An upper limit on the returned string length.
  1697.  * @param $wordsafe
  1698.  *   Flag to truncate at nearest space. Defaults to FALSE.
  1699.  * @return
  1700.  *   The truncated string.
  1701.  */
  1702. function truncate_utf8($string, $len, $wordsafe = FALSE) {
  1703.   $slen = strlen($string);
  1704.   if ($slen <= $len) {
  1705.     return $string;
  1706.   }
  1707.   if ($wordsafe) {
  1708.     while (($string[--$len] != ' ') && ($len > 0)) {};
  1709.   }
  1710.   if ((ord($string[$len]) < 0x80) || (ord($string[$len]) >= 0xC0)) {
  1711.     return substr($string, 0, $len);
  1712.   }
  1713.   while (ord($string[--$len]) < 0xC0) {};
  1714.   return substr($string, 0, $len);
  1715. }
  1716.  
  1717. /**
  1718.  * Encodes MIME/HTTP header values that contain non US-ASCII characters.
  1719.  *
  1720.  * For example, mime_header_encode('t├⌐st.txt') returns "=?UTF-8?B?dMOpc3QudHh0?=".
  1721.  *
  1722.  * See http://www.rfc-editor.org/rfc/rfc2047.txt for more information.
  1723.  *
  1724.  * Notes:
  1725.  * - Only encode strings that contain non-ASCII characters.
  1726.  * - The chunks come in groupings of 4 bytes when using base64 encoding.
  1727.  * - trim() is used to ensure that no extra spacing is added by chunk_split() or
  1728.  *   preg_replace().
  1729.  * - Using \n as the chunk separator may cause problems on some systems and may
  1730.  *   have to be changed to \r\n or \r.
  1731.  */
  1732. function mime_header_encode($string, $charset = 'UTF-8') {
  1733.   if (!preg_match('/^[\x20-\x7E]*$/', $string)) {
  1734.     $chunk_size = 75 - 7 - strlen($charset);
  1735.     $chunk_size -= $chunk_size % 4;
  1736.     $string = trim(chunk_split(base64_encode($string), $chunk_size, "\n"));
  1737.     $string = trim(preg_replace('/^(.*)$/m', " =?$charset?B?\\1?=", $string));
  1738.   }
  1739.   return $string;
  1740. }
  1741.  
  1742. /**
  1743.  * Decode all HTML entities (including numerical ones) to regular UTF-8 bytes.
  1744.  * Double-escaped entities will only be decoded once ("&lt;" becomes "<", not "<").
  1745.  *
  1746.  * @param $text
  1747.  *   The text to decode entities in.
  1748.  * @param $exclude
  1749.  *   An array of characters which should not be decoded. For example,
  1750.  *   array('<', '&', '"'). This affects both named and numerical entities.
  1751.  */
  1752. function decode_entities($text, $exclude = array()) {
  1753.   static $table;
  1754.   // We store named entities in a table for quick processing.
  1755.   if (!isset($table)) {
  1756.     // Get all named HTML entities.
  1757.     $table = array_flip(get_html_translation_table(HTML_ENTITIES));
  1758.     // PHP gives us ISO-8859-1 data, we need UTF-8.
  1759.     $table = array_map('utf8_encode', $table);
  1760.     // Add apostrophe (XML)
  1761.     $table['''] = "'";
  1762.   }
  1763.   $newtable = array_diff($table, $exclude);
  1764.  
  1765.   // Use a regexp to select all entities in one pass, to avoid decoding double-escaped entities twice.
  1766.   return preg_replace('/&(#x?)?([A-Za-z0-9]+);/e', '_decode_entities("$1", "$2", "$0", $newtable, $exclude)', $text);
  1767. }
  1768.  
  1769. /**
  1770.  * Helper function for decode_entities
  1771.  */
  1772. function _decode_entities($prefix, $codepoint, $original, &$table, &$exclude) {
  1773.   // Named entity
  1774.   if (!$prefix) {
  1775.     if (isset($table[$original])) {
  1776.       return $table[$original];
  1777.     }
  1778.     else {
  1779.       return $original;
  1780.     }
  1781.   }
  1782.   // Hexadecimal numerical entity
  1783.   if ($prefix == '#x') {
  1784.     $codepoint = base_convert($codepoint, 16, 10);
  1785.   }
  1786.   // Encode codepoint as UTF-8 bytes
  1787.   if ($codepoint < 0x80) {
  1788.     $str = chr($codepoint);
  1789.   }
  1790.   else if ($codepoint < 0x800) {
  1791.     $str = chr(0xC0 | ($codepoint >> 6))
  1792.          . chr(0x80 | ($codepoint & 0x3F));
  1793.   }
  1794.   else if ($codepoint < 0x10000) {
  1795.     $str = chr(0xE0 | ( $codepoint >> 12))
  1796.          . chr(0x80 | (($codepoint >> 6) & 0x3F))
  1797.          . chr(0x80 | ( $codepoint       & 0x3F));
  1798.   }
  1799.   else if ($codepoint < 0x200000) {
  1800.     $str = chr(0xF0 | ( $codepoint >> 18))
  1801.          . chr(0x80 | (($codepoint >> 12) & 0x3F))
  1802.          . chr(0x80 | (($codepoint >> 6)  & 0x3F))
  1803.          . chr(0x80 | ( $codepoint        & 0x3F));
  1804.   }
  1805.   // Check for excluded characters
  1806.   if (in_array($str, $exclude)) {
  1807.     return $original;
  1808.   }
  1809.   else {
  1810.     return $str;
  1811.   }
  1812. }
  1813.  
  1814. /**
  1815.  * Count the amount of characters in a UTF-8 string. This is less than or
  1816.  * equal to the byte count.
  1817.  */
  1818. function string_length(&$text) {
  1819.   return strlen(preg_replace("/[\x80-\xBF]/", '', $text));
  1820. }
  1821.  
  1822. /**
  1823.  * Evaluate a string of PHP code.
  1824.  *
  1825.  * This is a wrapper around PHP's eval(). It uses output buffering to capture both
  1826.  * returned and printed text. Unlike eval(), we require code to be surrounded by
  1827.  * <?php ?> tags; in other words, we evaluate the code as if it were a stand-alone
  1828.  * PHP file.
  1829.  *
  1830.  * Using this wrapper also ensures that the PHP code which is evaluated can not
  1831.  * overwrite any variables in the calling code, unlike a regular eval() call.
  1832.  *
  1833.  * @param $code
  1834.  *   The code to evaluate.
  1835.  * @return
  1836.  *   A string containing the printed output of the code, followed by the returned
  1837.  *   output of the code.
  1838.  */
  1839. function drupal_eval($code) {
  1840.   ob_start();
  1841.   print eval('?>'. $code);
  1842.   $output = ob_get_contents();
  1843.   ob_end_clean();
  1844.   return $output;
  1845. }
  1846.  
  1847. /**
  1848.  * Returns the path to a system item (module, theme, etc.).
  1849.  *
  1850.  * @param $type
  1851.  *   The type of the item (i.e. theme, theme_engine, module).
  1852.  * @param $name
  1853.  *   The name of the item for which the path is requested.
  1854.  *
  1855.  * @return
  1856.  *   The path to the requested item.
  1857.  */
  1858. function drupal_get_path($type, $name) {
  1859.   return dirname(drupal_get_filename($type, $name));
  1860. }
  1861.  
  1862. /**
  1863.  * Provide a substitute clone() function for PHP4.
  1864.  */
  1865. if (version_compare(phpversion(), '5.0') < 0) {
  1866.   eval('
  1867.     function clone($object) {
  1868.       return $object;
  1869.     }
  1870.   ');
  1871. }
  1872.  
  1873. // Set the Drupal custom error handler.
  1874. set_error_handler('error_handler');
  1875.  
  1876. include_once 'includes/theme.inc';
  1877. include_once 'includes/pager.inc';
  1878. include_once 'includes/menu.inc';
  1879. include_once 'includes/tablesort.inc';
  1880. include_once 'includes/file.inc';
  1881. include_once 'includes/xmlrpc.inc';
  1882. include_once 'includes/image.inc';
  1883.  
  1884. // Emit the correct charset HTTP header.
  1885. drupal_set_header('Content-Type: text/html; charset=utf-8');
  1886.  
  1887. // Initialize $_GET['q'] prior to loading modules and invoking hook_init().
  1888. if (!empty($_GET['q'])) {
  1889.   $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
  1890. }
  1891. else {
  1892.   $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
  1893. }
  1894.  
  1895. // Initialize all enabled modules.
  1896. module_init();
  1897.  
  1898. if (!user_access('bypass input data check')) {
  1899.   // We can't use $_REQUEST because it consists of the contents of $_POST,
  1900.   // $_GET and $_COOKIE: if any of the input arrays share a key, only one
  1901.   // value will be verified.
  1902.   if (!valid_input_data($_GET)
  1903.    || !valid_input_data($_POST)
  1904.    || !valid_input_data($_COOKIE)
  1905.    || !valid_input_data($_FILES)) {
  1906.     die('Terminated request because of suspicious input data.');
  1907.   }
  1908. }
  1909.  
  1910. // Initialize the localization system.
  1911. $locale = locale_initialize();
  1912.  
  1913. ?>
  1914.