'Secure Pages', 'description' => 'Configure which pages are and are not to be viewed in SSL', 'page callback' => 'drupal_get_form', 'page arguments' => array('securepages_settings'), 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, 'secure' => 1, 'file' => 'securepages.admin.inc' ); return $items; } /** * Implementation of hook_form_alter(). */ function securepages_form_alter(&$form, &$form_state, $form_id) { if (!variable_get('securepages_enable', 0)) { return; } if (isset($form['#action']) && securepages_can_alter_url($form['#action'])) { @extract(@parse_url($form['#action'])); if (isset($query)) { parse_str($query, $query); } else { $query = array(); } if (isset($query['q'])) { $path = $query['q']; } else { $base_path = base_path(); $path = (!strncmp($path, $base_path, drupal_strlen($base_path)) ? drupal_substr($path, drupal_strlen($base_path)) : $path); } $path = drupal_get_normal_path($path); $query = drupal_query_string_encode($query); $page_match = securepages_match($path); if ($page_match && !securepages_is_secure()) { $form['#action'] = securepages_url($path, array('query' => $query, 'secure' => TRUE)); } elseif ($page_match === 0 && securepages_is_secure() && variable_get('securepages_switch', FALSE)) { $form['#action'] = securepages_url($path, array('query' => $query, 'secure' => FALSE)); } } } /** * Implementation of hook_link_alter(). */ function securepages_link_alter(&$links, $node, $comment = NULL) { if (!variable_get('securepages_enable', 0)) { return; } foreach ($links as $module => $link) { if (isset($link['href']) && $link['href'] && securepages_can_alter_url($link['href'])) { $page_match = securepages_match($link['href']); if ($page_match && !securepages_is_secure()) { $links[$module]['href'] = securepages_url($link['href'], array('secure' => TRUE)); } elseif ($page_match === 0 && securepages_is_secure() && variable_get('securepages_switch', FALSE)) { $links[$module]['href'] = securepages_url($link['href'], array('secure' => FALSE)); } } } } /** * Check the current page and see if we need to redirect to the secure or * insecure version of the page. */ function securepages_redirect() { global $base_url; $path = isset($_GET['q']) ? $_GET['q'] : ''; $page_match = securepages_match($path); if ($_POST) { // If something has been posted to here then ignore the rules. } elseif ($page_match && !securepages_is_secure()) { securepages_goto(TRUE); } elseif ($page_match === 0 && securepages_is_secure() && variable_get('securepages_switch', FALSE)) { securepages_goto(FALSE); } // Correct the base_url so that everything comes from https. if (securepages_is_secure()) { $base_url = securepages_baseurl(); } } /** * securepage_goto() * * Redirects the current page to the secure or insecure version. * * @param $secure * Determine which version of the set to move to. */ function securepages_goto($secure) { global $base_root; $_SESSION['securepages_redirect'] = TRUE; $path = !empty($_REQUEST['q']) ? $_REQUEST['q'] : ''; $query = count($_GET) > 1 ? securepages_get_query($_GET) : NULL; $url = securepages_url($path, array('query' => $query, 'secure' => $secure)); if (function_exists('module_invoke_all')) { foreach (module_implements('exit') as $module) { if ($module != 'devel') { module_invoke($module, 'exit'); } } } else { bootstrap_invoke_all('exit'); } header('Location: '. $url); // Make sure the cache is clear so that the next page will not pick up a cached version. cache_clear_all($base_root . request_uri(), 'cache_page'); exit(); } /** * securepages_match() * * check the page past and see if it should be secure or insecure. * * @param $path * the page of the page to check. * * @return * 0 - page should be insecure. * 1 - page should be secure. * NULL - do not change page. */ function securepages_match($path) { /** * Check to see if the page matches the current settings */ $secure = variable_get('securepages_secure', 1); $pages = variable_get('securepages_pages', "node/add*\nnode/*/edit\nuser/*\nadmin*"); $ignore = variable_get('securepages_ignore', ''); $path = securepages_strtolower(trim($path, '/')); if ($ignore) { $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($ignore, '/')) .')$/'; if (preg_match($regexp, $path)) { return securepages_is_secure() ? 1 : 0; } } if ($pages) { $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($pages, '/')) .')$/'; $result = preg_match($regexp, $path); if (function_exists('drupal_get_path_alias')) { $path_alias = drupal_get_path_alias($path); $result |= preg_match($regexp, $path_alias); } return !($secure xor $result) ? 1 : 0; } else { return; } } /** * Secure Pages SSL Test */ function securepages_test() { // If we are in an SSL page then assume that SSL is configured correctly. if (securepages_is_secure()) { return TRUE; } $url = 'https://'. preg_replace(';^http[s]?://;s', '', url('admin/build/securepages/test', array('absolute' => TRUE))); $response = drupal_http_request($url); return $response->code == 200 ? TRUE : FALSE; } /** * Check if the current page is SSL */ function securepages_is_secure() { foreach (variable_get('securepages_ssl_checks', array('HTTPS' => array('on', '1'), 'HTTP_X_FORWARDED_PROTO' => 'https')) as $key => $value) { if (isset($_SERVER[$key]) && is_array($value) && in_array($_SERVER[$key], $value)) { return TRUE; } elseif (isset($_SERVER[$key]) && $_SERVER[$key] == $value) { return TRUE; } } return FALSE; } /** * Generate a URL from a Drupal menu path. Will also pass-through existing URLs. * * @param $path * The Drupal path being linked to, such as "admin/content/node", or an * existing URL like "http://drupal.org/". The special path * '' may also be given and will generate the site's base URL. * @param $options * An associative array of additional options, with the following keys: * - 'query' * A query string to append to the link, or an array of query key/value * properties. * - 'fragment' * A fragment identifier (or named anchor) to append to the link. * Do not include the '#' character. * - 'alias' (default FALSE) * Whether the given path is an alias already. * - 'external' * Whether the given path is an external URL. * - 'language' * An optional language object. Used to build the URL to link to and * look up the proper alias for the link. * - 'base_url' * Only used internally, to modify the base URL when a language dependent * URL requires so. * - 'prefix' * Only used internally, to modify the path when a language dependent URL * requires so. * - 'secure' * Specifies if the secure or insecure url should be returned. * @return * A string containing a URL to the given path. * * When creating links in modules, consider whether l() could be a better * alternative than url(). */ function securepages_url($path = NULL, $options = array()) { // Merge in defaults. $options += array( 'fragment' => '', 'query' => '', 'alias' => FALSE, 'prefix' => '', 'secure' => TRUE, ); if ($options['fragment']) { $options['fragment'] = '#'. $options['fragment']; } if (is_array($options['query'])) { $options['query'] = drupal_query_string_encode($options['query']); } global $base_url; static $script; static $clean_url; if (!isset($script)) { // On some web servers, such as IIS, we can't omit "index.php". So, we // generate "index.php?q=foo" instead of "?q=foo" on anything that is not // Apache. $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE) ? 'index.php' : ''; } // Cache the clean_url variable to improve performance. if (!isset($clean_url)) { $clean_url = (bool)variable_get('clean_url', '0'); } if (!isset($options['base_url'])) { // The base_url might be rewritten from the language rewrite in domain mode. $options['base_url'] = securepages_baseurl($options['secure']); } // Preserve the original path before aliasing. $original_path = $path; // The special path '' links to the default front page. if ($path == '') { $path = ''; } elseif (!empty($path) && !$options['alias'] && function_exists('drupal_get_path_alias')) { $path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : ''); } $base = $options['base_url'] .'/'; $prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix']; $path = securepages_urlencode($prefix . $path); if ($clean_url) { // With Clean URLs. if ($options['query']) { return $base . $path .'?'. $options['query'] . $options['fragment']; } else { return $base . $path . $options['fragment']; } } else { // Without Clean URLs. $variables = array(); if (!empty($path)) { $variables[] = 'q='. $path; } if (!empty($options['query'])) { $variables[] = $options['query']; } if ($query = join('&', $variables)) { return $base . $script .'?'. $query . $options['fragment']; } else { return $base . $options['fragment']; } } } /** * Return the secure base path */ function securepages_baseurl($secure = TRUE) { global $base_url; if ($secure) { $url = variable_get('securepages_basepath_ssl', NULL); } else { $url = variable_get('securepages_basepath', NULL); } if (!empty($url)) { return $url; } // No url has been set, so convert the base_url from 1 to the other return preg_replace('/http[s]?:\/\//i', ($secure ? 'https://' : 'http://'), $base_url, 1); } /** * Return a querystring without the q paramter */ function securepages_get_query($query) { return trim(str_replace('q='.$query['q'], '', $_SERVER['QUERY_STRING']),'&'); } /** * Copy of Drupals so we can redirect correctly */ function securepages_urlencode($text) { if (variable_get('clean_url', '0')) { return str_replace(array('%2F', '%26', '%23', '//'), array('/', '%2526', '%2523', '/%252F'), rawurlencode($text)); } else { return str_replace('%2F', '/', rawurlencode($text)); } } /** * Lowercase a UTF-8 string. * * @param $text * The string to run the operation on. * * @return string * The string in lowercase. * * @ingroup php_wrappers */ function securepages_strtolower($text) { global $multibyte; if ($multibyte == 1) { return mb_strtolower($text); } else { // Use C-locale for ASCII-only lowercase $text = strtolower($text); // Case flip Latin-1 accented letters $text = preg_replace_callback('/\xC3[\x80-\x96\x98-\x9E]/', '_securepages_unicode_caseflip', $text); return $text; } } /** * Helper function for case conversion of Latin-1. * Used for flipping U+C0-U+DE to U+E0-U+FD and back. */ function _securepages_unicode_caseflip($matches) { return $matches[0][0] . chr(ord($matches[0][1]) ^ 32); } /** * Check the url and make sure that it is a url that you can alter this url. */ function securepages_can_alter_url($url) { global $base_path, $base_url; $path = ''; @extract(@parse_url($url)); // If there is no scheme then it is a relative url and can be altered if (!isset($scheme) && $base_path == '/') { return TRUE; } // If the host names are not the same then don't allow altering of the path. if (isset($host) && strtolower($host) != strtolower($_SERVER['HTTP_HOST'])) { return FALSE; } if (strlen($base_path) > 1 && substr($base_url, -1) != substr($path, 1, strlen($base_path))) { return FALSE; } return TRUE; }