View source
<?php
define('PATH_REDIRECT_DEFAULT_TYPE', 301);
if (module_exists('workflow_ng')) {
include_once drupal_get_path('module', 'path_redirect') . '/path_redirect_workflow.inc';
}
function path_redirect_help($path) {
switch ($path) {
case 'admin/build/path-redirect':
return '<p>' . t('Here you can set up URL redirecting for this site. Any existing or non-existing path within this site can redirect to any internal or external URL.') . '</p>';
case 'admin/build/path-redirect/' . arg(2):
case 'admin/build/path-redirect/edit/' . arg(3):
return '<p>' . t("The <strong>from</strong> path must be an internal Drupal path in the form of 'node/123', 'admin/logs', or 'taxonomy/term/123'. The <strong>to</strong> path can be either an internal Drupal path as above or a complete external URL such as http://www.example.com/. Furthermore, the <strong>to</strong> path may contain query arguments (such as 'page=2') and fragment anchors, to make it possible to redirect to 'admin/user?page=1#help'. Most redirects will not contain queries or anchors.") . '</p>';
}
}
function path_redirect_check() {
$path = drupal_substr(urldecode(request_uri()), drupal_strlen($GLOBALS['base_path']));
if (preg_match('/^\\?q=/', $path)) {
$path = preg_replace(array(
'/^\\?q=/',
'/&/',
), array(
'',
'?',
), $path, 1);
}
$path = preg_replace('/\\/\\?|\\/$/', '', $path);
$r = db_fetch_object(db_query("SELECT rid, redirect, query, fragment, type FROM {path_redirect} WHERE path = '%s' OR path = '%s'", $path, urlencode(utf8_encode($path))));
if (!$r) {
$path = preg_replace('/\\?.*/', '', $path);
$r = db_fetch_object(db_query("SELECT rid, redirect, query, fragment, type FROM {path_redirect} WHERE path = '%s' OR path = '%s'", $path, urlencode(utf8_encode($path))));
}
if ($r) {
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$r->query = strlen($r->query) ? $r->query : NULL;
$r->fragment = strlen($r->fragment) ? $r->fragment : NULL;
$redirect = url($r->redirect, $r->query, $r->fragment, TRUE);
if (url($r->redirect) == url($path)) {
watchdog('path_redirect', t('Redirect to <code>%redirect</code> is causing an infinite loop; redirect cancelled.', array(
'%redirect' => $r->redirect,
)), WATCHDOG_WARNING, l(t('edit'), 'admin/build/path-redirect/edit/' . $r->rid));
}
elseif (variable_get('path_redirect_allow_bypass', 0) && isset($_GET['redirect']) && $_GET['redirect'] === 'no') {
drupal_set_message(t('This page has been redirected to <a href="@redirect">@redirect</a>.', array(
'@redirect' => $redirect,
)));
}
elseif (variable_get('path_redirect_redirect_warning', 0)) {
drupal_set_message(t('This page has been moved to <a href="@redirect">@redirect</a> and will redirect in 5 seconds. You may want to update your bookmarks.', array(
'@redirect' => $redirect,
)), 'error');
drupal_set_html_head("<meta http-equiv=\"refresh\" content=\"5;url={$redirect}\" />");
}
else {
unset($_REQUEST['destination']);
drupal_goto($r->redirect, $r->query, $r->fragment, $r->type);
}
}
}
function path_redirect_menu($may_cache) {
$access = user_access('administer redirects');
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/build/path-redirect',
'title' => t('URL redirects'),
'description' => t('Redirect users from one URL to another'),
'callback' => 'path_redirect_admin',
'access' => $access,
);
$items[] = array(
'path' => 'admin/build/path-redirect/list',
'title' => t('List'),
'description' => t('List all URL redirects'),
'access' => $access,
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -3,
);
$items[] = array(
'path' => 'admin/build/path-redirect/add',
'title' => t('Add redirect'),
'description' => t('Add a new URL redirect'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'path_redirect_edit',
),
'access' => $access,
'type' => MENU_LOCAL_TASK,
);
$items[] = array(
'path' => 'admin/build/path-redirect/edit',
'title' => t('Edit'),
'description' => t('Edit an existing URL redirect'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'path_redirect_edit',
),
'access' => $access,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'admin/build/path-redirect/delete',
'title' => t('Delete'),
'description' => t('Delete an existing URL redirect'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'path_redirect_delete_confirm',
),
'access' => $access,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'admin/build/path-redirect/settings',
'title' => t('Settings'),
'description' => t('Configure behavior for URL redirects'),
'callback' => 'drupal_get_form',
'callback arguments' => 'path_redirect_settings',
'access' => $access,
'type' => MENU_LOCAL_TASK,
);
}
else {
path_redirect_check();
}
return $items;
}
function path_redirect_perm() {
return array(
'administer redirects',
);
}
function path_redirect_admin() {
$header = array(
array(
'data' => t('From'),
'field' => 'path',
'sort' => 'asc',
),
array(
'data' => t('To'),
'field' => 'redirect',
),
array(
'data' => t('Type'),
'field' => 'type',
),
array(
'data' => t('Operations'),
'colspan' => '2',
),
);
$result = pager_query('SELECT rid, path, redirect, query, fragment, type FROM {path_redirect}' . tablesort_sql($header), 50);
$rows = array();
while ($r = db_fetch_object($result)) {
$redirect = url($r->redirect, $r->query ? $r->query : NULL, $r->fragment ? $r->fragment : NULL, TRUE);
$rows[] = array(
l($r->path, preg_replace('/\\?.*/', '', $r->path), array(), strstr($r->path, '?') ? preg_replace('/.*\\?/', '', $r->path) : NULL),
l($redirect, $redirect),
$r->type,
l(t('edit'), 'admin/build/path-redirect/edit/' . $r->rid),
l(t('delete'), 'admin/build/path-redirect/delete/' . $r->rid),
);
}
if (empty($rows)) {
$rows[] = array(
array(
'data' => t('No redirects have been added.'),
'colspan' => '5',
),
);
}
$output = theme('table', $header, $rows, array(
'class' => 'path-redirects',
));
$output .= '<p>' . l(t('Add redirect'), 'admin/build/path-redirect/add') . '</p>';
$output .= theme('pager');
return $output;
}
function path_redirect_edit($rid = FALSE) {
if ($rid) {
$redirect = path_redirect_load($rid);
drupal_set_title(check_plain($redirect['path']));
$output = path_redirect_edit_form($redirect);
}
else {
$breadcrumbs = drupal_get_breadcrumb();
array_push($breadcrumbs, l(t('URL redirects'), 'admin/build/path-redirect'));
drupal_set_breadcrumb($breadcrumbs);
drupal_set_title(t('Add redirect'));
$output = path_redirect_edit_form();
}
return $output;
}
function path_redirect_edit_form($edit = array(
'path' => '',
'redirect' => '',
'query' => '',
'fragment' => '',
'type' => PATH_REDIRECT_DEFAULT_TYPE,
'rid' => NULL,
)) {
$form['path'] = array(
'#type' => 'textfield',
'#title' => t('From'),
'#description' => t('Enter a Drupal path or path alias to redirect. Fragment anchors <em>#foo</em> are <strong>not</strong> allowed.'),
'#size' => 42,
'#maxlength' => 255,
'#default_value' => $edit['path'],
'#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q='),
);
$form['redirect'] = array(
'#type' => 'item',
'#prefix' => '<div class="container-inline">',
'#suffix' => '</div>',
'#title' => t('To'),
'#description' => '<div style="display:block">' . t('Enter a Drupal path, path alias, or external URL to redirect to. Use %front to redirect to the front page. Enter (optional) queries after "?" and (optional) anchor after "#". Most redirects will not contain queries or fragment anchors.', array(
'%front' => '<front>',
)) . '</div>',
);
$form['redirect']['redirect'] = array(
'#type' => 'textfield',
'#size' => 30,
'#maxlength' => 255,
'#default_value' => $edit['redirect'],
);
$form['redirect'][] = array(
'#value' => '?',
);
$form['redirect']['query'] = array(
'#type' => 'textfield',
'#size' => 12,
'#maxlength' => 255,
'#default_value' => $edit['query'],
);
$form['redirect'][] = array(
'#value' => '#',
);
$form['redirect']['fragment'] = array(
'#type' => 'textfield',
'#size' => 12,
'#maxlength' => 50,
'#default_value' => $edit['fragment'],
);
$form[] = array(
'#value' => "<p> </p>",
);
$form['type'] = array(
'#type' => 'fieldset',
'#title' => t('Redirect Type'),
'#collapsible' => TRUE,
'#collapsed' => $edit['type'] == PATH_REDIRECT_DEFAULT_TYPE,
);
foreach (path_redirect_status_codes() as $key => $info) {
$form['type'][]['type'] = array(
'#type' => 'radio',
'#title' => $info['title'],
'#description' => $info['description'],
'#return_value' => $key,
'#default_value' => $edit['type'],
);
}
$form['type']['link'] = array(
'#type' => 'markup',
'#value' => t('<p>Find more information about http redirect codes <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3">here</a>.</p>'),
);
$form['rid'] = array(
'#type' => 'hidden',
'#value' => $edit['rid'],
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => $edit['rid'] ? t('Update redirect') : t('Create new redirect'),
);
return $form;
}
function path_redirect_edit_validate($form_id, &$form_values, $form) {
$form_values['path'] = urlencode(preg_replace('/\\?.*/', '', $form_values['path'])) . (strstr($form_values['path'], '?') ? preg_replace('/.*(\\?)/', '$1', $form_values['path']) : '');
form_set_value($form['path'], $form_values['path']);
if (trim($form_values['path']) == '') {
form_set_error('path', t('You must enter a <strong>from</strong> path.'));
}
else {
$path_error = '';
$result = path_redirect_load(NULL, $form_values['path']);
if ($result && (!$form_values['rid'] || $form_values['rid'] !== $result['rid'])) {
$path_error .= ' ' . t('The <strong>from</strong> path you entered is already redirected. You can <a href="@edit-page">edit this redirect</a> instead.', array(
'@edit-page' => url('admin/build/path-redirect/edit/' . $result['rid']),
));
}
if (strpos($form_values['path'], '#') !== FALSE) {
$path_error .= ' ' . t('You cannot redirect from a fragment anchor.');
}
if (!valid_url($form_values['path'])) {
$path_error .= ' ' . t('The redirect <strong>from</strong> path does not appear valid. This must be a local Drupal path.');
}
if (!empty($path_error)) {
form_set_error('path', $path_error);
}
}
if (!valid_url($form_values['redirect']) && !valid_url($form_values['redirect'], TRUE) && $form_values['redirect'] != '<front>') {
form_set_error('redirect', t('The redirect <strong>to</strong> path does not appear valid.'));
}
if ($form_values['redirect'] == '<front>') {
$form_values['redirect'] = variable_get('site_frontpage', 'node');
}
if ($form_values['path'] === $form_values['redirect']) {
form_set_error('redirect', t('You are attempting to redirect the page to itself. This will result in an infinite loop.'));
}
}
function path_redirect_edit_submit($form_id, &$form_values) {
path_redirect_save($form_values);
drupal_set_message(t('Redirect has been saved.'));
drupal_goto('admin/build/path-redirect');
}
function path_redirect_save($edit) {
if (empty($edit['rid'])) {
$edit['rid'] = db_next_id('{path_redirect}_rid');
}
else {
path_redirect_delete(NULL, NULL, $edit['rid']);
}
if (empty($edit['type'])) {
$edit['type'] = PATH_REDIRECT_DEFAULT_TYPE;
}
if (empty($edit['query'])) {
$edit['query'] = '';
}
if (empty($edit['fragment'])) {
$edit['fragment'] = '';
}
db_query("DELETE FROM {path_redirect} WHERE path = '%s'", $edit['path']);
return db_query("INSERT INTO {path_redirect} (rid, path, redirect, query, fragment, type) VALUES (%d, '%s', '%s', '%s', '%s', '%s')", $edit['rid'], $edit['path'], $edit['redirect'], $edit['query'], $edit['fragment'], $edit['type']);
}
function path_redirect_load($rid = NULL, $from = NULL) {
if (!empty($rid)) {
$result = db_fetch_array(db_query("SELECT rid, path, redirect, query, fragment, type FROM {path_redirect} WHERE rid = %d", $rid));
}
else {
if (!empty($from)) {
$result = db_fetch_array(db_query("SELECT rid, path, redirect, query, fragment, type FROM {path_redirect} WHERE path = '%s'", $from));
}
}
if ($result) {
$result['path'] = urldecode($result['path']);
}
return $result;
}
function path_redirect_delete($from = NULL, $to = NULL, $rid = NULL) {
if (!empty($rid)) {
$result = db_query("DELETE FROM {path_redirect} WHERE rid = %d", $rid);
}
else {
if (!empty($from)) {
if (!empty($to)) {
$result = db_query("DELETE FROM {path_redirect} WHERE path = '%s' AND redirect = '%s'", $from, $to);
}
else {
$result = db_query("DELETE FROM {path_redirect} WHERE path = '%s'", $from);
}
}
else {
if (!empty($to)) {
$result = db_query("DELETE FROM {path_redirect} WHERE redirect = '%s'", $to);
}
}
}
return $result;
}
function path_redirect_delete_confirm($rid) {
$form['rid'] = array(
'#type' => 'value',
'#value' => $rid,
);
$redirect = path_redirect_load($rid);
return confirm_form($form, t('Are you sure you want to delete the redirect from %path to %redirect?', array(
'%path' => $redirect['path'],
'%redirect' => $redirect['redirect'],
)), isset($_GET['destination']) ? $_GET['destination'] : 'admin/build/path-redirect');
}
function path_redirect_delete_confirm_submit($form_id, $form_values) {
if ($form_values['confirm']) {
path_redirect_delete(NULL, NULL, $form_values['rid']);
drupal_set_message(t('The redirect has been deleted.'));
return 'admin/build/path-redirect';
}
}
function path_redirect_settings() {
$form['path_redirect_nodeapi_enabled'] = array(
'#type' => 'radios',
'#title' => t('Enable on edit pages'),
'#default_value' => variable_get('path_redirect_nodeapi_enabled', 0),
'#options' => array(
t('Disabled'),
t('Enabled'),
),
'#description' => t('Enable management of URL redirects directly on content editing pages.'),
);
$form['path_redirect_redirect_warning'] = array(
'#type' => 'radios',
'#title' => t('Warn on redirect'),
'#default_value' => variable_get('path_redirect_redirect_warning', 0),
'#options' => array(
t('Disabled'),
t('Enabled'),
),
'#description' => t('Display a warning message to users when a redirect takes place.'),
);
$form['path_redirect_allow_bypass'] = array(
'#type' => 'radios',
'#title' => t('Allow bypassing'),
'#default_value' => variable_get('path_redirect_allow_bypass', 0),
'#options' => array(
t('Disabled'),
t('Enabled'),
),
'#description' => t('Allow users to bypass redirects by appending <code>?redirect=no</code> to the URL.'),
);
return system_settings_form($form);
}
function path_redirect_form_alter($form_id, &$form) {
if (variable_get('path_redirect_nodeapi_enabled', 0) && isset($form['#id']) && $form['#id'] == 'node-form' && user_access('administer redirects')) {
$form['redirects'] = array(
'#type' => 'fieldset',
'#access' => user_access('administer redirects'),
'#title' => t('URL redirects'),
'#collapsible' => TRUE,
'#collapsed' => !db_num_rows(path_redirect_node_redirects($form['#node']->nid)),
'#prefix' => '<div class="path-redirects">',
'#suffix' => '</div>',
'#weight' => 31,
);
$form['redirects']['list'] = _path_redirect_node_form_list($form['#node']);
$form['redirects']['path_redirect_add'] = array(
'#type' => 'textfield',
'#title' => t('Add a redirect from'),
'#description' => t('Path from which to redirect to this node. Do not include the leading slash.'),
'#maxlength' => 255,
'#size' => 42,
);
}
}
function path_redirect_node_redirects($nid) {
return db_query("\n SELECT rid, path, redirect, type\n FROM {path_redirect} pr LEFT JOIN {url_alias} ua ON pr.redirect = ua.dst\n WHERE pr.redirect = 'node/%d' OR ua.src = 'node/%d'\n ORDER BY pr.path", $nid, $nid);
}
function _path_redirect_node_form_list($node) {
$form['#theme'] = 'path_redirect_node_form_list';
if (!empty($node->nid)) {
$result = path_redirect_node_redirects($node->nid);
if ($result) {
$destination = drupal_get_destination();
$types = path_redirect_status_codes();
while ($redirect = db_fetch_object($result)) {
$form['redirects'][$redirect->rid]['path'] = array(
'#value' => htmlspecialchars(urldecode($redirect->path)),
);
$form['redirects'][$redirect->rid]['redirect'] = array(
'#value' => $redirect->redirect,
);
$form['redirects'][$redirect->rid]['type'] = array(
'#value' => '<span title="' . $types[$redirect->type]['title'] . '">' . $redirect->type . '</span>',
);
$form['redirects'][$redirect->rid]['test'] = array(
'#value' => l(t('test'), preg_replace('/\\?.*/', '', urldecode($redirect->path)), NULL, strstr($redirect->path, '?') ? preg_replace('/.*\\?/', '', $redirect->path) : NULL),
);
$form['redirects'][$redirect->rid]['edit'] = array(
'#value' => l(t('edit'), 'admin/build/path-redirect/edit/' . $redirect->rid, array(), $destination),
);
$form['redirects'][$redirect->rid]['delete'] = array(
'#value' => l(t('delete'), 'admin/build/path-redirect/delete/' . $redirect->rid, array(), $destination),
);
}
}
}
return $form;
}
function theme_path_redirect_node_form_list(&$form) {
if (count(element_children($form['redirects']))) {
$header = array(
t('From'),
t('To'),
t('Type'),
array(
'data' => t('Operations'),
'colspan' => 3,
),
);
foreach (element_children($form['redirects']) as $key) {
$rows[] = array(
drupal_render($form['redirects'][$key]['path']),
drupal_render($form['redirects'][$key]['redirect']),
drupal_render($form['redirects'][$key]['type']),
drupal_render($form['redirects'][$key]['test']),
drupal_render($form['redirects'][$key]['edit']),
drupal_render($form['redirects'][$key]['delete']),
);
}
return theme('table', $header, $rows);
}
}
function path_redirect_nodeapi(&$node, $op, $arg) {
if (user_access('administer redirects')) {
switch ($op) {
case 'validate':
if (db_result(db_query("SELECT COUNT(rid) FROM {path_redirect} WHERE path = '%s' AND redirect != '%s' AND redirect != '%s'", $node->path_redirect_add, "node/{$node->nid}", $node->path))) {
form_set_error('path_redirect_add', t('The path is already redirected elsewhere.'));
}
break;
case 'load':
break;
case 'update':
case 'insert':
if ($node->path_redirect_add) {
path_redirect_save(array(
'path' => $node->path_redirect_add,
'redirect' => 'node/' . $node->nid,
'type' => 301,
));
}
break;
case 'delete':
break;
}
}
}
function path_redirect_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) {
$url = $path;
if (!preg_match('/^[a-z]+:\\/\\//', $url)) {
global $base_url;
$url = $base_url . '/' . $url;
}
$url .= empty($query) ? '' : '?' . $query;
$url .= empty($fragment) ? '' : '#' . $fragment;
$url = str_replace(array(
"\n",
"\r",
), '', $url);
bootstrap_invoke_all('exit');
session_write_close();
header('Location: ' . $url, TRUE, $http_response_code);
exit;
}
function path_redirect_status_codes() {
$codes = array(
300 => array(
'title' => t('300 Multiple Choices'),
'description' => t('The request is ambiguous and needs clarification as to which resource was requested.'),
),
301 => array(
'title' => t('301 Moved Permanently'),
'description' => t('Moved Permanently. The resource has permanently moved elsewhere, the response indicates where it has gone to. <strong>Recommended.</strong>'),
),
302 => array(
'title' => t('302 Found'),
'description' => t('The resource has temporarily moved elsewhere, the response indicates where it is at present. <strong>This is Drupal\'s default redirect type.</strong>'),
),
303 => array(
'title' => t('303 See Other'),
'description' => t('See Other/Redirect. A preferred alternative source should be used at present.'),
),
304 => array(
'title' => t('304 Not Modified'),
'description' => t('The server has identified from the request information that the client\'s copy of the information is up-to-date and the requested information does not need to be sent again.'),
),
305 => array(
'title' => t('305 Use Proxy'),
'description' => t('The request must be sent through the indicated proxy server.'),
),
307 => array(
'title' => t('307 Temporary Redirect'),
'description' => t('The resource has temporarily moved elsewhere, the response indicates where it is at present. Client should still use this URL.'),
),
);
return $codes;
}