path_redirect.module

Tracking 5.x-1.x branch
  1. drupal
    1. 5 contributions/path_redirect/path_redirect.module
    2. 6 contributions/path_redirect/path_redirect.module
    3. 7 contributions/path_redirect/path_redirect.module

Functions & methods

NameDescription
path_redirect_adminRender a list of redirects for the main admin page.
path_redirect_checkIf a redirect is found for the current path, perform the redirect.
path_redirect_deleteDelete the specified path redirect. This will delete as specifically as possible, in order: by $rid, by ($from, $to), by $from, or by $to. Multiple redirects may be deleted if the $to parameter matches more than one entry.
path_redirect_delete_confirm
path_redirect_delete_confirm_submit
path_redirect_editCallback for add and edit pages.
path_redirect_edit_form
path_redirect_edit_submit
path_redirect_edit_validate
path_redirect_form_alter
path_redirect_gotoThis is a copy of drupal_goto() redesigned for use during the bootstrap
path_redirect_helpImplementation of hook_help
path_redirect_loadRetrieve the specified URL redirect
path_redirect_menuImplementation of hook_menu
path_redirect_nodeapi
path_redirect_node_redirects
path_redirect_permImplementation of hook_perm
path_redirect_save
path_redirect_settings
path_redirect_status_codesReturn an array of 300-range status codes placed here for clarity
theme_path_redirect_node_form_list
_path_redirect_node_form_list

Constants

NameDescription
PATH_REDIRECT_DEFAULT_TYPE

File

View source
  1. <?php
  2. // The default HTTP status code for redirects is "moved permanently"
  3. define('PATH_REDIRECT_DEFAULT_TYPE', 301);
  4. if (module_exists('workflow_ng')) {
  5. include_once(drupal_get_path('module', 'path_redirect') .'/path_redirect_workflow.inc');
  6. }
  7. /**
  8. * Implementation of hook_help
  9. */
  10. function path_redirect_help($path) {
  11. switch ($path) {
  12. case 'admin/build/path-redirect':
  13. 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>';
  14. case 'admin/build/path-redirect/'. arg(2):
  15. case 'admin/build/path-redirect/edit/'. arg(3):
  16. 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>';
  17. }
  18. }
  19. /**
  20. * If a redirect is found for the current path, perform the redirect.
  21. */
  22. function path_redirect_check() {
  23. // Extract the Drupal path and query string from the request URI.
  24. $path = drupal_substr(urldecode(request_uri()), drupal_strlen($GLOBALS['base_path']));
  25. if (preg_match('/^\?q=/', $path)) {
  26. $path = preg_replace(array('/^\?q=/', '/&/'), array('', '?'), $path, 1);
  27. }
  28. // Remove trailing slash from path.
  29. $path = preg_replace('/\/\?|\/$/', '', $path);
  30. $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))));
  31. if (!$r) {
  32. // If there is no match against path and query string, check just the path
  33. $path = preg_replace('/\?.*/', '', $path);
  34. $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))));
  35. }
  36. if ($r) {
  37. drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
  38. $r->query = strlen($r->query) ? $r->query : NULL;
  39. $r->fragment = strlen($r->fragment) ? $r->fragment : NULL;
  40. $redirect = url($r->redirect, $r->query, $r->fragment, TRUE);
  41. if (url($r->redirect) == url($path)) {
  42. // Prevent infinite loop redirection.
  43. 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));
  44. }
  45. elseif (variable_get('path_redirect_allow_bypass', 0) && isset($_GET['redirect']) && $_GET['redirect'] === 'no') {
  46. // If the user has requested not to be redirected, show a message.
  47. drupal_set_message(t('This page has been redirected to <a href="@redirect">@redirect</a>.', array('@redirect' => $redirect)));
  48. }
  49. elseif (variable_get('path_redirect_redirect_warning', 0)) {
  50. // Show a message and automatically redirect after 5 seconds.
  51. 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');
  52. drupal_set_html_head("<meta http-equiv=\"refresh\" content=\"5;url=$redirect\" />");
  53. }
  54. else {
  55. // Perform the redirect directly.
  56. unset($_REQUEST['destination']);
  57. drupal_goto($r->redirect, $r->query, $r->fragment, $r->type);
  58. }
  59. }
  60. }
  61. /**
  62. * Implementation of hook_menu
  63. */
  64. function path_redirect_menu($may_cache) {
  65. $access = user_access('administer redirects');
  66. $items = array();
  67. if ($may_cache) {
  68. $items[] = array(
  69. 'path' => 'admin/build/path-redirect',
  70. 'title' => t('URL redirects'),
  71. 'description' => t('Redirect users from one URL to another'),
  72. 'callback' => 'path_redirect_admin',
  73. 'access' => $access,
  74. );
  75. $items[] = array(
  76. 'path' => 'admin/build/path-redirect/list',
  77. 'title' => t('List'),
  78. 'description' => t('List all URL redirects'),
  79. 'access' => $access,
  80. 'type' => MENU_DEFAULT_LOCAL_TASK,
  81. 'weight' => -3,
  82. );
  83. $items[] = array(
  84. 'path' => 'admin/build/path-redirect/add',
  85. 'title' => t('Add redirect'),
  86. 'description' => t('Add a new URL redirect'),
  87. 'callback' => 'drupal_get_form',
  88. 'callback arguments' => array('path_redirect_edit'),
  89. 'access' => $access,
  90. 'type' => MENU_LOCAL_TASK,
  91. );
  92. $items[] = array(
  93. 'path' => 'admin/build/path-redirect/edit',
  94. 'title' => t('Edit'),
  95. 'description' => t('Edit an existing URL redirect'),
  96. 'callback' => 'drupal_get_form',
  97. 'callback arguments' => array('path_redirect_edit'),
  98. 'access' => $access,
  99. 'type' => MENU_CALLBACK,
  100. );
  101. $items[] = array(
  102. 'path' => 'admin/build/path-redirect/delete',
  103. 'title' => t('Delete'),
  104. 'description' => t('Delete an existing URL redirect'),
  105. 'callback' => 'drupal_get_form',
  106. 'callback arguments' => array('path_redirect_delete_confirm'),
  107. 'access' => $access,
  108. 'type' => MENU_CALLBACK,
  109. );
  110. $items[] = array(
  111. 'path' => 'admin/build/path-redirect/settings',
  112. 'title' => t('Settings'),
  113. 'description' => t('Configure behavior for URL redirects'),
  114. 'callback' => 'drupal_get_form',
  115. 'callback arguments' => 'path_redirect_settings',
  116. 'access' => $access,
  117. 'type' => MENU_LOCAL_TASK,
  118. );
  119. }
  120. else {
  121. path_redirect_check();
  122. }
  123. return $items;
  124. }
  125. /**
  126. * Implementation of hook_perm
  127. */
  128. function path_redirect_perm() {
  129. return array('administer redirects');
  130. }
  131. /**
  132. * Render a list of redirects for the main admin page.
  133. */
  134. function path_redirect_admin() {
  135. $header = array(
  136. array('data' => t('From'), 'field' => 'path', 'sort' => 'asc'),
  137. array('data' => t('To'), 'field' => 'redirect'),
  138. array('data' => t('Type'), 'field' => 'type'),
  139. array('data' => t('Operations'), 'colspan' => '2'),
  140. );
  141. $result = pager_query('SELECT rid, path, redirect, query, fragment, type FROM {path_redirect}'. tablesort_sql($header), 50);
  142. $rows = array();
  143. while ($r = db_fetch_object($result)) {
  144. $redirect = url($r->redirect, ($r->query ? $r->query : NULL), ($r->fragment? $r->fragment : NULL), TRUE);
  145. $rows[] = array(
  146. // @todo: Revise the following messy, confusing line.
  147. l($r->path, preg_replace('/\?.*/', '', $r->path), array(), strstr($r->path, '?') ? preg_replace('/.*\?/', '', $r->path) : NULL),
  148. l($redirect, $redirect),
  149. $r->type,
  150. l(t('edit'), 'admin/build/path-redirect/edit/'. $r->rid),
  151. l(t('delete'), 'admin/build/path-redirect/delete/'. $r->rid),
  152. );
  153. }
  154. if (empty($rows)) {
  155. $rows[] = array(array('data' => t('No redirects have been added.'), 'colspan' => '5'));
  156. }
  157. $output = theme('table', $header, $rows, array('class' => 'path-redirects'));
  158. $output .= '<p>'. l(t('Add redirect'), 'admin/build/path-redirect/add') .'</p>';
  159. $output .= theme('pager');
  160. return $output;
  161. }
  162. /**
  163. * Callback for add and edit pages.
  164. *
  165. * @return
  166. * A form for drupal_get_form.
  167. */
  168. function path_redirect_edit($rid = FALSE) {
  169. if ($rid) {
  170. $redirect = path_redirect_load($rid);
  171. drupal_set_title(check_plain($redirect['path']));
  172. $output = path_redirect_edit_form($redirect);
  173. }
  174. else {
  175. $breadcrumbs = drupal_get_breadcrumb();
  176. array_push($breadcrumbs, l(t('URL redirects'), 'admin/build/path-redirect'));
  177. drupal_set_breadcrumb($breadcrumbs);
  178. drupal_set_title(t('Add redirect'));
  179. $output = path_redirect_edit_form();
  180. }
  181. return $output;
  182. }
  183. function path_redirect_edit_form($edit = array('path' => '', 'redirect' => '', 'query' => '', 'fragment' => '', 'type' => PATH_REDIRECT_DEFAULT_TYPE, 'rid' => NULL)) {
  184. $form['path'] = array(
  185. '#type' => 'textfield',
  186. '#title' => t('From'),
  187. '#description' => t('Enter a Drupal path or path alias to redirect. Fragment anchors <em>#foo</em> are <strong>not</strong> allowed.'),
  188. '#size' => 42,
  189. '#maxlength' => 255,
  190. '#default_value' => $edit['path'],
  191. '#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q='),
  192. );
  193. $form['redirect'] = array(
  194. '#type' => 'item',
  195. '#prefix' => '<div class="container-inline">',
  196. '#suffix' => '</div>',
  197. '#title' => t('To'),
  198. '#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>',
  199. );
  200. $form['redirect']['redirect'] = array(
  201. '#type' => 'textfield',
  202. '#size' => 30,
  203. '#maxlength' => 255,
  204. '#default_value' => $edit['redirect'],
  205. );
  206. $form['redirect'][] = array(
  207. '#value' => '?',
  208. );
  209. $form['redirect']['query'] = array(
  210. '#type' => 'textfield',
  211. '#size' => 12,
  212. '#maxlength' => 255,
  213. '#default_value' => $edit['query'],
  214. );
  215. $form['redirect'][] = array(
  216. '#value' => '#',
  217. );
  218. $form['redirect']['fragment'] = array(
  219. '#type' => 'textfield',
  220. '#size' => 12,
  221. '#maxlength' => 50,
  222. '#default_value' => $edit['fragment'],
  223. );
  224. $form[] = array(
  225. '#value' => "<p> </p>", // little bit of extra space
  226. );
  227. $form['type'] = array(
  228. '#type' => 'fieldset',
  229. '#title' => t('Redirect Type'),
  230. '#collapsible' => TRUE,
  231. '#collapsed' => ($edit['type'] == PATH_REDIRECT_DEFAULT_TYPE),
  232. );
  233. foreach (path_redirect_status_codes() as $key => $info) {
  234. $form['type'][]['type'] = array(
  235. '#type' => 'radio',
  236. '#title' => $info['title'],
  237. '#description' => $info['description'],
  238. '#return_value' => $key,
  239. '#default_value' => $edit['type'],
  240. );
  241. }
  242. $form['type']['link'] = array(
  243. '#type' => 'markup',
  244. '#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>'),
  245. );
  246. $form['rid'] = array(
  247. '#type' => 'hidden',
  248. '#value' => $edit['rid'],
  249. );
  250. $form['submit'] = array(
  251. '#type' => 'submit',
  252. '#value' => $edit['rid'] ? t('Update redirect') : t('Create new redirect'),
  253. );
  254. return $form;
  255. }
  256. function path_redirect_edit_validate($form_id, &$form_values, $form) {
  257. // Allow spaces in "from" path; encode everything but the query string
  258. $form_values['path'] = urlencode(preg_replace('/\?.*/', '', $form_values['path']))
  259. . (strstr($form_values['path'], '?') ? preg_replace('/.*(\?)/', '$1', $form_values['path']) : '');
  260. form_set_value($form['path'], $form_values['path']);
  261. if (trim($form_values['path']) == '') {
  262. form_set_error('path', t('You must enter a <strong>from</strong> path.'));
  263. }
  264. else {
  265. $path_error = '';
  266. // The "from" path should not conflict with another redirect
  267. $result = path_redirect_load(NULL, $form_values['path']);
  268. if ($result && (!$form_values['rid'] || ($form_values['rid'] !== $result['rid']))) {
  269. $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'])));
  270. }
  271. // Check that the "from" path is valid and contains no # fragment
  272. if (strpos($form_values['path'], '#') !== FALSE) {
  273. $path_error .= ' '. t('You cannot redirect from a fragment anchor.');
  274. }
  275. // Make sure "from" has the form of a local Drupal path
  276. if (!valid_url($form_values['path'])) {
  277. $path_error .= ' '. t('The redirect <strong>from</strong> path does not appear valid. This must be a local Drupal path.');
  278. }
  279. if (!empty($path_error)) {
  280. form_set_error('path', $path_error);
  281. }
  282. }
  283. if (!valid_url($form_values['redirect']) && !valid_url($form_values['redirect'], TRUE) && $form_values['redirect'] != '<front>') {
  284. form_set_error('redirect', t('The redirect <strong>to</strong> path does not appear valid.'));
  285. }
  286. if ($form_values['redirect'] == '<front>') {
  287. $form_values['redirect'] = variable_get('site_frontpage', 'node');
  288. }
  289. // check that there there are no redirect loops
  290. if ($form_values['path'] === $form_values['redirect']) {
  291. form_set_error('redirect', t('You are attempting to redirect the page to itself. This will result in an infinite loop.'));
  292. }
  293. }
  294. function path_redirect_edit_submit($form_id, &$form_values) {
  295. path_redirect_save($form_values);
  296. drupal_set_message(t('Redirect has been saved.'));
  297. drupal_goto('admin/build/path-redirect');
  298. }
  299. function path_redirect_save($edit) {
  300. if (empty($edit['rid'])) {
  301. $edit['rid'] = db_next_id('{path_redirect}_rid');
  302. }
  303. else {
  304. path_redirect_delete(NULL, NULL, $edit['rid']);
  305. }
  306. if (empty($edit['type'])) {
  307. $edit['type'] = PATH_REDIRECT_DEFAULT_TYPE;
  308. }
  309. if (empty($edit['query'])) {
  310. $edit['query'] = '';
  311. }
  312. if (empty($edit['fragment'])) {
  313. $edit['fragment'] = '';
  314. }
  315. // Remove any other redirects from the same path
  316. db_query("DELETE FROM {path_redirect} WHERE path = '%s'", $edit['path']);
  317. 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']);
  318. }
  319. /**
  320. * Retrieve the specified URL redirect
  321. */
  322. function path_redirect_load($rid = NULL, $from = NULL) {
  323. if (!empty($rid)) {
  324. $result = db_fetch_array(db_query("SELECT rid, path, redirect, query, fragment, type FROM {path_redirect} WHERE rid = %d", $rid));
  325. }
  326. else if (!empty($from)) {
  327. $result = db_fetch_array(db_query("SELECT rid, path, redirect, query, fragment, type FROM {path_redirect} WHERE path = '%s'", $from));
  328. }
  329. if ($result) {
  330. $result['path'] = urldecode($result['path']);
  331. }
  332. return $result;
  333. }
  334. /**
  335. * Delete the specified path redirect. This will delete as specifically as
  336. * possible, in order: by $rid, by ($from, $to), by $from, or by $to.
  337. * Multiple redirects may be deleted if the $to parameter matches more than
  338. * one entry.
  339. *
  340. * This function is part of an API available for external code to use.
  341. *
  342. * @param $from
  343. * Source path of redirect to delete.
  344. * @param $to
  345. * Destination path or URL of redirect to delete.
  346. * @param $rid
  347. * Unique ID of redirect to delete.
  348. * @return
  349. * The result of the deletion query.
  350. */
  351. function path_redirect_delete($from = NULL, $to = NULL, $rid = NULL) {
  352. if (!empty($rid)) {
  353. $result = db_query("DELETE FROM {path_redirect} WHERE rid = %d", $rid);
  354. }
  355. else if (!empty($from)) {
  356. if (!empty($to)) {
  357. $result = db_query("DELETE FROM {path_redirect} WHERE path = '%s' AND redirect = '%s'", $from, $to);
  358. }
  359. else {
  360. $result = db_query("DELETE FROM {path_redirect} WHERE path = '%s'", $from);
  361. }
  362. }
  363. else if (!empty($to)) {
  364. $result = db_query("DELETE FROM {path_redirect} WHERE redirect = '%s'", $to);
  365. }
  366. return $result;
  367. }
  368. function path_redirect_delete_confirm($rid) {
  369. $form['rid'] = array(
  370. '#type' => 'value',
  371. '#value' => $rid,
  372. );
  373. $redirect = path_redirect_load($rid);
  374. return confirm_form($form,
  375. t('Are you sure you want to delete the redirect from %path to %redirect?', array('%path' => $redirect['path'], '%redirect' => $redirect['redirect'])),
  376. isset($_GET['destination']) ? $_GET['destination'] : 'admin/build/path-redirect');
  377. }
  378. function path_redirect_delete_confirm_submit($form_id, $form_values) {
  379. if ($form_values['confirm']) {
  380. path_redirect_delete(NULL, NULL, $form_values['rid']);
  381. drupal_set_message(t('The redirect has been deleted.'));
  382. return 'admin/build/path-redirect';
  383. }
  384. }
  385. function path_redirect_settings() {
  386. $form['path_redirect_nodeapi_enabled'] = array(
  387. '#type' => 'radios',
  388. '#title' => t('Enable on edit pages'),
  389. '#default_value' => variable_get('path_redirect_nodeapi_enabled', 0),
  390. '#options' => array(t('Disabled'), t('Enabled')),
  391. '#description' => t('Enable management of URL redirects directly on content editing pages.'),
  392. );
  393. $form['path_redirect_redirect_warning'] = array(
  394. '#type' => 'radios',
  395. '#title' => t('Warn on redirect'),
  396. '#default_value' => variable_get('path_redirect_redirect_warning', 0),
  397. '#options' => array(t('Disabled'), t('Enabled')),
  398. '#description' => t('Display a warning message to users when a redirect takes place.'),
  399. );
  400. $form['path_redirect_allow_bypass'] = array(
  401. '#type' => 'radios',
  402. '#title' => t('Allow bypassing'),
  403. '#default_value' => variable_get('path_redirect_allow_bypass', 0),
  404. '#options' => array(t('Disabled'), t('Enabled')),
  405. '#description' => t('Allow users to bypass redirects by appending <code>?redirect=no</code> to the URL.'),
  406. );
  407. return system_settings_form($form);
  408. }
  409. function path_redirect_form_alter($form_id, &$form) {
  410. if (variable_get('path_redirect_nodeapi_enabled', 0) && isset($form['#id']) && $form['#id'] == 'node-form' && user_access('administer redirects')) {
  411. $form['redirects'] = array(
  412. '#type' => 'fieldset',
  413. '#access' => user_access('administer redirects'),
  414. '#title' => t('URL redirects'),
  415. '#collapsible' => TRUE,
  416. '#collapsed' => !db_num_rows(path_redirect_node_redirects($form['#node']->nid)),
  417. '#prefix' => '<div class="path-redirects">',
  418. '#suffix' => '</div>',
  419. '#weight' => 31,
  420. );
  421. $form['redirects']['list'] = _path_redirect_node_form_list($form['#node']);
  422. $form['redirects']['path_redirect_add'] = array(
  423. '#type' => 'textfield',
  424. '#title' => t('Add a redirect from'),
  425. '#description' => t('Path from which to redirect to this node. Do not include the leading slash.'),
  426. '#maxlength' => 255,
  427. '#size' => 42,
  428. );
  429. }
  430. }
  431. function path_redirect_node_redirects($nid) {
  432. return db_query("
  433. SELECT rid, path, redirect, type
  434. FROM {path_redirect} pr LEFT JOIN {url_alias} ua ON pr.redirect = ua.dst
  435. WHERE pr.redirect = 'node/%d' OR ua.src = 'node/%d'
  436. ORDER BY pr.path", $nid, $nid);
  437. }
  438. function _path_redirect_node_form_list($node) {
  439. $form['#theme'] = 'path_redirect_node_form_list';
  440. if (!empty($node->nid)) {
  441. $result = path_redirect_node_redirects($node->nid);
  442. if ($result) {
  443. $destination = drupal_get_destination();
  444. $types = path_redirect_status_codes();
  445. while ($redirect = db_fetch_object($result)) {
  446. $form['redirects'][$redirect->rid]['path'] = array(
  447. '#value' => htmlspecialchars(urldecode($redirect->path)),
  448. );
  449. $form['redirects'][$redirect->rid]['redirect'] = array(
  450. '#value' => $redirect->redirect,
  451. );
  452. $form['redirects'][$redirect->rid]['type'] = array(
  453. '#value' => '<span title="'. $types[$redirect->type]['title'] .'">'. $redirect->type .'</span>',
  454. );
  455. $form['redirects'][$redirect->rid]['test'] = array(
  456. '#value' => l(t('test'), preg_replace('/\?.*/', '', urldecode($redirect->path)), NULL, strstr($redirect->path, '?') ? preg_replace('/.*\?/', '', $redirect->path) : NULL),
  457. );
  458. $form['redirects'][$redirect->rid]['edit'] = array(
  459. '#value' => l(t('edit'), 'admin/build/path-redirect/edit/'. $redirect->rid, array(), $destination),
  460. );
  461. $form['redirects'][$redirect->rid]['delete'] = array(
  462. '#value' => l(t('delete'), 'admin/build/path-redirect/delete/'. $redirect->rid, array(), $destination),
  463. );
  464. }
  465. }
  466. }
  467. return $form;
  468. }
  469. function theme_path_redirect_node_form_list(&$form) {
  470. if (count(element_children($form['redirects']))) {
  471. $header = array(
  472. t('From'),
  473. t('To'),
  474. t('Type'),
  475. array('data' => t('Operations'), 'colspan' => 3),
  476. );
  477. foreach (element_children($form['redirects']) as $key) {
  478. $rows[] = array(
  479. drupal_render($form['redirects'][$key]['path']),
  480. drupal_render($form['redirects'][$key]['redirect']),
  481. drupal_render($form['redirects'][$key]['type']),
  482. drupal_render($form['redirects'][$key]['test']),
  483. drupal_render($form['redirects'][$key]['edit']),
  484. drupal_render($form['redirects'][$key]['delete']),
  485. );
  486. }
  487. return theme('table', $header, $rows);
  488. }
  489. }
  490. function path_redirect_nodeapi(&$node, $op, $arg) {
  491. if (user_access('administer redirects')) {
  492. switch ($op) {
  493. case 'validate':
  494. 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))) {
  495. form_set_error('path_redirect_add', t('The path is already redirected elsewhere.'));
  496. }
  497. break;
  498. case 'load':
  499. break;
  500. case 'update':
  501. case 'insert':
  502. if ($node->path_redirect_add) {
  503. path_redirect_save(array(
  504. 'path' => $node->path_redirect_add,
  505. 'redirect' => 'node/'. $node->nid,
  506. 'type' => 301,
  507. ));
  508. }
  509. break;
  510. case 'delete':
  511. break;
  512. }
  513. }
  514. }
  515. /**
  516. * This is a copy of drupal_goto() redesigned for use during the bootstrap
  517. */
  518. function path_redirect_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) {
  519. $url = $path;
  520. // Make the given path or URL absolute
  521. if (!preg_match('/^[a-z]+:\/\//', $url)) {
  522. global $base_url;
  523. $url = $base_url .'/'. $url;
  524. }
  525. $url .= (empty($query) ? '' : '?'. $query);
  526. $url .= (empty($fragment) ? '' : '#'. $fragment);
  527. // Remove newlines from the URL to avoid header injection attacks.
  528. $url = str_replace(array("\n", "\r"), '', $url);
  529. // Before the redirect, allow modules to react to the end of the page request.
  530. bootstrap_invoke_all('exit');
  531. // Even though session_write_close() is registered as a shutdown function, we
  532. // need all session data written to the database before redirecting.
  533. session_write_close();
  534. header('Location: '. $url, TRUE, $http_response_code);
  535. // The "Location" header sends a REDIRECT status code to the http
  536. // daemon. In some cases this can go wrong, so we make sure none
  537. // of the code below the drupal_goto() call gets executed when we redirect.
  538. exit();
  539. }
  540. /**
  541. * Return an array of 300-range status codes
  542. * placed here for clarity
  543. */
  544. function path_redirect_status_codes() {
  545. $codes = array(
  546. 300 => array('title' => t('300 Multiple Choices'), 'description' => t('The request is ambiguous and needs clarification as to which resource was requested.')),
  547. 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>')),
  548. 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>')),
  549. 303 => array('title' => t('303 See Other'), 'description' => t('See Other/Redirect. A preferred alternative source should be used at present.')),
  550. 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.')),
  551. 305 => array('title' => t('305 Use Proxy'), 'description' => t('The request must be sent through the indicated proxy server.')),
  552. 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.')),
  553. );
  554. return $codes;
  555. }