'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,
);
return $items;
}
/**
* Implementation of hook_settings().
*/
function securepages_settings() {
$form = array();
$form['securepages_enable'] = array(
'#type' => 'radios',
'#title' => t('Enable Secure Pages'),
'#default_value' => variable_get('securepages_enable', 0),
'#options' => array(t('Disabled'), t('Enabled')),
'#disabled' => !securepages_test(),
'#description' => t('To start using secure pages this setting must be enabled. This setting will only be able to changed when the web server has been configured for SSL.
If this test has failed then go here', array('!url' => preg_replace(';^http://;i', 'https://', url($_GET['q'], array('absolute' => TRUE))))),
);
$form['securepages_switch'] = array(
'#type' => 'checkbox',
'#title' => t('Switch back to http pages when there are no matches'),
'#return_value' => TRUE,
'#default_value' => variable_get('securepages_switch', FALSE),
);
$form['securepages_basepath'] = array(
'#type' => 'textfield',
'#title' => t('Non-secure Base URL'),
'#default_value' => variable_get('securepages_basepath', ''),
);
$form['securepages_basepath_ssl'] = array(
'#type' => 'textfield',
'#title' => t('Secure Base URL'),
'#default_value' => variable_get('securepages_basepath_ssl', ''),
);
$form['securepages_secure'] = array(
'#type' => 'radios',
'#title' => t('Pages which will be be secure'),
'#default_value' => variable_get('securepages_secure', 1),
'#options' => array(t('Make secure every page except the listed pages.'), t('Make secure only the listed pages.')),
);
$form['securepages_pages'] = array(
'#type' => 'textarea',
'#title' => t('Pages'),
'#default_value' => variable_get('securepages_pages', "node/add*\nnode/*/edit\nuser/*\nadmin*"),
'#cols' => 40,
'#rows' => 5,
'#description' => t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are 'blog' for the blog page and 'blog/*' for every personal blog. '<front>' is the front page."),
);
$form['securepages_ignore'] = array(
'#type' => 'textarea',
'#title' => t('Ignore pages'),
'#default_value' => variable_get('securepages_ignore', "*/autocomplete/*\n*/ajax/*"),
'#cols' => 40,
'#rows' => 5,
'#description' => t("The pages listed here will be ignored and be either returned in http or https. Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are 'blog' for the blog page and 'blog/*' for every personal blog. '<front>' is the front page."),
);
return system_settings_form($form);
}
/**
* Implementation of hook_form_alter().
*/
function securepages_form_alter(&$form, &$form_state, $form_id) {
if (!variable_get('securepages_enable', 0)) {
return;
}
if ($form['#action']) {
extract(parse_url($form['#action']));
parse_str($query, $query);
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']) {
$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);
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 current menu item has a preference and ignore the
* secure pages settings
*/
if (function_exists('menu_get_item')) {
$item = menu_get_item($path);
if (isset($item['secure'])) {
return $item['secure'];
}
}
/**
* 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/settings/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));
}
// May need language dependent rewriting if language.inc is present.
if (function_exists('language_url_rewrite')) {
language_url_rewrite($path, $options);
}
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 : '');
}
if (function_exists('custom_url_rewrite_outbound')) {
// Modules may alter outbound links by reference.
custom_url_rewrite_outbound($path, $options, $original_path);
}
$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) {
$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));
}
}