--- common.coder.inc 2008-01-17 01:07:11.952020200 +0100 +++ common.inc 2008-01-17 01:05:11.895163800 +0100 +/** + * Add a feed URL for the current page. + * + * @param $url + * A url for the feed. + * @param $title + * The title of the feed. + */ function drupal_add_feed($url = NULL, $title = '') { static $stored_feed_links = array(); + if (!is_null($url) && !isset($stored_feed_links[$url])) { $stored_feed_links[$url] = theme('feed_icon', $url, $title); - drupal_add_link(array('rel' => 'alternate', 'type' => 'application/rss+xml', 'title' => $title, 'href' => $url)); + + drupal_add_link(array('rel' => 'alternate', + 'type' => 'application/rss+xml', + 'title' => $title, + 'href' => $url)); } return $stored_feed_links; } +/** + * Get the feed URLs for the current page. + * + * @param $delimiter + * A delimiter to split feeds by. + */ function drupal_get_feeds($delimiter = "\n") { $feeds = drupal_add_feed(); return implode($feeds, $delimiter); } +/** + * @name HTTP handling + * @{ + * Functions to properly handle HTTP responses. + */ + +/** + * Parse an array into a valid urlencoded query string. + * + * @param $query + * The array to be processed e.g. $_GET. + * @param $exclude + * The array filled with keys to be excluded. Use parent[child] to exclude + * nested items. + * @param $parent + * Should not be passed, only used in recursive calls. + * @return + * An urlencoded string which can be appended to/as the URL query string. + */ function drupal_query_string_encode($query, $exclude = array(), $parent = '') { $params = array(); + foreach ($query as $key => $value) { $key = drupal_urlencode($key); if ($parent) { $key = $parent .'['. $key .']'; } + if (in_array($key, $exclude)) { continue; } + if (is_array($value)) { $params[] = drupal_query_string_encode($value, $exclude, $key); } @@ -106,14 +223,26 @@ function drupal_query_string_encode($que $params[] = $key .'='. drupal_urlencode($value); } } + return implode('&', $params); } +/** + * Prepare a destination query string for use in combination with drupal_goto(). + * + * Used to direct the user back to the referring page after completing a form. + * By default the current URL is returned. If a destination exists in the + * previous request, that destination is returned. As such, a destination can + * persist across multiple pages. + * + * @see drupal_goto() + */ function drupal_get_destination() { if (isset($_REQUEST['destination'])) { return 'destination='. urlencode($_REQUEST['destination']); } else { + // Use $_GET here to retrieve the original path in source form. $path = isset($_GET['q']) ? $_GET['q'] : ''; $query = drupal_query_string_encode($_GET, array('q')); if ($query != '') { @@ -123,59 +252,139 @@ function drupal_get_destination() { } } +/** + * Send the user to a different Drupal page. + * + * This issues an on-site HTTP redirect. The function makes sure the redirected + * URL is formatted correctly. + * + * Usually the redirected URL is constructed from this function's input + * parameters. However you may override that behavior by setting a + * destination in either the $_REQUEST-array (i.e. by using + * the query string of an URI) or the $_REQUEST['edit']-array (i.e. by + * using a hidden form field). This is used to direct the user back to + * the proper page after completing a form. For example, after editing + * a post on the 'admin/content/node'-page or after having logged on using the + * 'user login'-block in a sidebar. The function drupal_get_destination() + * can be used to help set the destination URL. + * + * Drupal will ensure that messages set by drupal_set_message() and other + * session data are written to the database before the user is redirected. + * + * This function ends the request; use it rather than a print theme('page') + * statement in your menu callback. + * + * @param $path + * A Drupal path or a full URL. + * @param $query + * A query string component, if any. + * @param $fragment + * A destination fragment identifier (named anchor). + * @param $http_response_code + * Valid values for an actual "goto" as per RFC 2616 section 10.3 are: + * - 301 Moved Permanently (the recommended value for most redirects) + * - 302 Found (default in Drupal and PHP, sometimes used for spamming search + * engines) + * - 303 See Other + * - 304 Not Modified + * - 305 Use Proxy + * - 307 Temporary Redirect (alternative to "503 Site Down for Maintenance") + * Note: Other values are defined by RFC 2616, but are rarely used and poorly + * supported. + * @see drupal_get_destination() + */ function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) { + if (isset($_REQUEST['destination'])) { extract(parse_url(urldecode($_REQUEST['destination']))); } else if (isset($_REQUEST['edit']['destination'])) { extract(parse_url(urldecode($_REQUEST['edit']['destination']))); } + $url = url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE)); + // Remove newlines from the URL to avoid header injection attacks. $url = str_replace(array("\n", "\r"), '', $url); + + // Allow modules to react to the end of the page request before redirecting. + // We do not want this while running update.php. if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') { module_invoke_all('exit', $url); } + + // Even though session_write_close() is registered as a shutdown function, we + // need all session data written to the database before redirecting. session_write_close(); + header('Location: '. $url, TRUE, $http_response_code); + + // The "Location" header sends a redirect status code to the HTTP daemon. In + // some cases this can be wrong, so we make sure none of the code below the + // drupal_goto() call gets executed upon redirection. exit(); } +/** + * Generates a site off-line message. + */ function drupal_site_offline() { drupal_maintenance_theme(); drupal_set_header('HTTP/1.1 503 Service unavailable'); drupal_set_title(t('Site off-line')); - print theme('maintenance_page', filter_xss_admin(variable_get('site_offline_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))))); + print theme('maintenance_page', filter_xss_admin(variable_get('site_offline_message', + t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))))); } +/** + * Generates a 404 error if the request can not be handled. + */ function drupal_not_found() { drupal_set_header('HTTP/1.1 404 Not Found'); + watchdog('page not found', check_plain($_GET['q']), NULL, WATCHDOG_WARNING); + + // Keep old path for reference. if (!isset($_REQUEST['destination'])) { $_REQUEST['destination'] = $_GET['q']; } + $path = drupal_get_normal_path(variable_get('site_404', '')); if ($path && $path != $_GET['q']) { + // Set the active item in case there are tabs to display, or other + // dependencies on the path. menu_set_active_item($path); $return = menu_execute_active_handler($path); } + if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) { drupal_set_title(t('Page not found')); $return = t('The requested page could not be found.'); } + + // To conserve CPU and bandwidth, omit the blocks. print theme('page', $return, FALSE); }