'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) { if (!variable_get('securepages_enable', 0)) { return; } foreach ($links as $module => $link) { if ($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() { $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) { $_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', "*/autocomplete/*\n*/ajax/*"); 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, '/')) .')$/'; return !($secure xor preg_match($regexp, $path)) ? 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() { return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? TRUE : 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 (!isset($options['external'])) { // Return an external link if $path contains an allowed absolute URL. // Only call the slow filter_xss_bad_protocol if $path contains a ':' before // any / ? or #. $colonpos = strpos($path, ':'); $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path)); } if ($options['fragment']) { $options['fragment'] = '#'. $options['fragment']; } if (is_array($options['query'])) { $options['query'] = drupal_query_string_encode($options['query']); } if ($options['external']) { // Split off the fragment. if (strpos($path, '#') !== FALSE) { list($path, $old_fragment) = explode('#', $path, 2); if (isset($old_fragment) && !$options['fragment']) { $options['fragment'] = '#'. $old_fragment; } } // Append the query. if ($options['query']) { $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . $options['query']; } // Reassemble. return $path . $options['fragment']; } 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) { unset($query['q']); $q = array(); foreach ($query as $key => $value) { if (is_array($value)) { $value = http_build_query(array($key => $value)); } $q[] = securepages_urlencode($key) .'='. securepages_urlencode($value); } return implode('&', $q); } /** * 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'), urlencode($text)); } else { return str_replace('%2F', '/', urlencode($text)); } } /** * 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; 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 (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; }