Commit 598e7392 authored by Dries's avatar Dries

- Patch #578520 by sun | c960657, mfb, Dries, catch, mattyoung: make in url()...

- Patch #578520 by sun | c960657, mfb, Dries, catch, mattyoung: make  in url() only accept an array. Another nice API clean-up!
parent cef10893
This diff is collapsed.
......@@ -2984,7 +2984,7 @@ function batch_process($redirect = NULL, $url = NULL) {
// Set the batch number in the session to guarantee that it will stay alive.
$_SESSION['batches'][$batch['id']] = TRUE;
drupal_goto($batch['url'], 'op=start&id=' . $batch['id']);
drupal_goto($batch['url'], array('op' => 'start', 'id' => $batch['id']));
}
else {
// Non-progressive execution: bypass the whole progressbar workflow
......
......@@ -171,18 +171,18 @@ public function element($element) {
}
/**
* Compose a query string to append to pager requests.
* Compose a URL query parameter array for pager links.
*
* @return
* A query string that consists of all components of the current page request
* except for those pertaining to paging.
* A URL query parameter array that consists of all components of the current
* page request except for those pertaining to paging.
*/
function pager_get_querystring() {
static $string = NULL;
if (!isset($string)) {
$string = drupal_query_string_encode($_REQUEST, array_merge(array('q', 'page'), array_keys($_COOKIE)));
function pager_get_query_parameters() {
$query = &drupal_static(__FUNCTION__);
if (!isset($query)) {
$query = drupal_get_query_parameters($_REQUEST, array_merge(array('q', 'page'), array_keys($_COOKIE)));
}
return $string;
return $query;
}
/**
......@@ -465,11 +465,10 @@ function theme_pager_link($text, $page_new, $element, $parameters = array(), $at
$query = array();
if (count($parameters)) {
$query[] = drupal_query_string_encode($parameters, array());
$query = drupal_get_query_parameters($parameters, array());
}
$querystring = pager_get_querystring();
if ($querystring != '') {
$query[] = $querystring;
if ($query_pager = pager_get_query_parameters()) {
$query = array_merge($query, $query_pager);
}
// Set each pager link title
......@@ -491,7 +490,7 @@ function theme_pager_link($text, $page_new, $element, $parameters = array(), $at
}
}
return l($text, $_GET['q'], array('attributes' => $attributes, 'query' => count($query) ? implode('&', $query) : NULL));
return l($text, $_GET['q'], array('attributes' => $attributes, 'query' => $query));
}
/**
......
......@@ -59,7 +59,7 @@ public function orderByHeader(Array $header) {
protected function init() {
$ts = $this->order();
$ts['sort'] = $this->getSort();
$ts['query_string'] = $this->getQueryString();
$ts['query'] = $this->getQueryParameters();
return $ts;
}
......@@ -87,14 +87,16 @@ protected function getSort() {
}
/**
* Compose a query string to append to table sorting requests.
* Compose a URL query parameter array to append to table sorting requests.
*
* @return
* A query string that consists of all components of the current page request
* except for those pertaining to table sorting.
* A URL query parameter array that consists of all components of the current
* page request except for those pertaining to table sorting.
*
* @see tablesort_get_query_parameters()
*/
protected function getQueryString() {
return drupal_query_string_encode($_REQUEST, array_merge(array('q', 'sort', 'order'), array_keys($_COOKIE)));
protected function getQueryParameters() {
return tablesort_get_query_parameters();
}
/**
......@@ -141,7 +143,7 @@ protected function order() {
function tablesort_init($header) {
$ts = tablesort_get_order($header);
$ts['sort'] = tablesort_get_sort($header);
$ts['query_string'] = tablesort_get_querystring();
$ts['query'] = tablesort_get_query_parameters();
return $ts;
}
......@@ -174,11 +176,7 @@ function tablesort_header($cell, $header, $ts) {
$ts['sort'] = 'asc';
$image = '';
}
if (!empty($ts['query_string'])) {
$ts['query_string'] = '&' . $ts['query_string'];
}
$cell['data'] = l($cell['data'] . $image, $_GET['q'], array('attributes' => array('title' => $title), 'query' => 'sort=' . $ts['sort'] . '&order=' . urlencode($cell['data']) . $ts['query_string'], 'html' => TRUE));
$cell['data'] = l($cell['data'] . $image, $_GET['q'], array('attributes' => array('title' => $title), 'query' => array_merge($ts['query'], array('sort' => $ts['sort'], 'order' => $cell['data'])), 'html' => TRUE));
unset($cell['field'], $cell['sort']);
}
......@@ -214,14 +212,14 @@ function tablesort_cell($cell, $header, $ts, $i) {
}
/**
* Compose a query string to append to table sorting requests.
* Compose a URL query parameter array for table sorting links.
*
* @return
* A query string that consists of all components of the current page request
* except for those pertaining to table sorting.
* A URL query parameter array that consists of all components of the current
* page request except for those pertaining to table sorting.
*/
function tablesort_get_querystring() {
return drupal_query_string_encode($_REQUEST, array_merge(array('q', 'sort', 'order'), array_keys($_COOKIE)));
function tablesort_get_query_parameters() {
return drupal_get_query_parameters($_REQUEST, array_merge(array('q', 'sort', 'order'), array_keys($_COOKIE)));
}
/**
......
......@@ -639,7 +639,7 @@ function install_tasks_to_display($install_state) {
* @see install_full_redirect_url()
*/
function install_redirect_url($install_state) {
return 'install.php?' . drupal_query_string_encode($install_state['parameters']);
return 'install.php?' . drupal_http_build_query($install_state['parameters']);
}
/**
......
......@@ -56,7 +56,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
$feed_name = $this->randomName(10);
if (!$feed_url) {
$feed_url = url('rss.xml', array(
'query' => 'feed=' . $feed_name,
'query' => array('feed' => $feed_name),
'absolute' => TRUE,
));
}
......
......@@ -73,7 +73,7 @@ function book_node_view_link($node, $build_mode) {
$links['book_add_child'] = array(
'title' => t('Add child page'),
'href' => 'node/add/' . str_replace('_', '-', $child_type),
'query' => 'parent=' . $node->book['mlid'],
'query' => array('parent' => $node->book['mlid']),
);
}
......
......@@ -445,7 +445,7 @@ function comment_new_page_count($num_comments, $new_replies, $node) {
}
if ($pageno >= 1) {
$pagenum = "page=" . intval($pageno);
$pagenum = array('page' => intval($pageno));
}
return $pagenum;
......@@ -2153,10 +2153,10 @@ function theme_comment_post_forbidden($node) {
// We cannot use drupal_get_destination() because these links
// sometimes appear on /node and taxonomy listing pages.
if (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW) == COMMENT_FORM_SEPARATE_PAGE) {
$destination = 'destination=' . rawurlencode("comment/reply/$node->nid#comment-form");
$destination = array('destination' => "comment/reply/$node->nid#comment-form");
}
else {
$destination = 'destination=' . rawurlencode("node/$node->nid#comment-form");
$destination = array('destination' => "node/$node->nid#comment-form");
}
if (variable_get('user_register', 1)) {
......
......@@ -308,7 +308,7 @@ class CommentInterfaceTest extends CommentHelperCase {
$this->setCommentsPerPage(2);
$comment_new_page = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE);
$this->assertTrue($this->commentExists($comment_new_page), t('Page one exists. %s'));
$this->drupalGet('node/' . $this->node->nid, array('query' => 'page=1'));
$this->drupalGet('node/' . $this->node->nid, array('query' => array('page' => 1)));
$this->assertTrue($this->commentExists($reply, TRUE), t('Page two exists. %s'));
$this->setCommentsPerPage(50);
......@@ -588,13 +588,13 @@ class CommentPagerTest extends CommentHelperCase {
$this->assertFalse($this->commentExists($comments[2]), t('Comment 3 does not appear on page 1.'));
// Check the second page.
$this->drupalGet('node/' . $node->nid, array('query' => 'page=1'));
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 1)));
$this->assertTrue($this->commentExists($comments[1]), t('Comment 2 appears on page 2.'));
$this->assertFalse($this->commentExists($comments[0]), t('Comment 1 does not appear on page 2.'));
$this->assertFalse($this->commentExists($comments[2]), t('Comment 3 does not appear on page 2.'));
// Check the third page.
$this->drupalGet('node/' . $node->nid, array('query' => 'page=2'));
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 2)));
$this->assertTrue($this->commentExists($comments[2]), t('Comment 3 appears on page 3.'));
$this->assertFalse($this->commentExists($comments[0]), t('Comment 1 does not appear on page 3.'));
$this->assertFalse($this->commentExists($comments[1]), t('Comment 2 does not appear on page 3.'));
......@@ -608,21 +608,21 @@ class CommentPagerTest extends CommentHelperCase {
$this->setCommentsPerPage(2);
// We are still in flat view - the replies should not be on the first page,
// even though they are replies to the oldest comment.
$this->drupalGet('node/' . $node->nid, array('query' => 'page=0'));
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 0)));
$this->assertFalse($this->commentExists($reply, TRUE), t('In flat mode, reply does not appear on page 1.'));
// If we switch to threaded mode, the replies on the oldest comment
// should be bumped to the first page and comment 6 should be bumped
// to the second page.
$this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED, t('Switched to threaded mode.'));
$this->drupalGet('node/' . $node->nid, array('query' => 'page=0'));
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 0)));
$this->assertTrue($this->commentExists($reply, TRUE), t('In threaded mode, reply appears on page 1.'));
$this->assertFalse($this->commentExists($comments[1]), t('In threaded mode, comment 2 has been bumped off of page 1.'));
// If (# replies > # comments per page) in threaded expanded view,
// the overage should be bumped.
$reply2 = $this->postComment(NULL, $this->randomName(), $this->randomName(), FALSE, TRUE);
$this->drupalGet('node/' . $node->nid, array('query' => 'page=0'));
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 0)));
$this->assertFalse($this->commentExists($reply2, TRUE), t('In threaded mode where # replies > # comments per page, the newest reply does not appear on page 1.'));
$this->drupalLogout();
......
......@@ -155,7 +155,7 @@ function contact_personal_page($account) {
global $user;
if (!valid_email_address($user->mail)) {
$output = t('You need to provide a valid e-mail address to contact other users. Please update your <a href="@url">user information</a> and try again.', array('@url' => url("user/$user->uid/edit", array('query' => 'destination=' . drupal_get_destination()))));
$output = t('You need to provide a valid e-mail address to contact other users. Please update your <a href="@url">user information</a> and try again.', array('@url' => url("user/$user->uid/edit", array('query' => drupal_get_destination()))));
}
elseif (!flood_is_allowed('contact', variable_get('contact_threshold_limit', 5), variable_get('contact_threshold_window', 3600)) && !user_access('administer site-wide contact form')) {
$output = t("You cannot send more than %number messages in @interval. Please try again later.", array('%number' => variable_get('contact_threshold_limit', 3), '@interval' => format_interval(variable_get('contact_threshold_window', 3600))));
......
......@@ -539,7 +539,8 @@ function field_ui_field_overview_form_submit($form, &$form_state) {
}
if ($destinations) {
$destinations[] = urldecode(substr(drupal_get_destination(), 12));
$destination = drupal_get_destination();
$destinations[] = $destination['destination'];
unset($_GET['destination']);
$form_state['redirect'] = field_ui_get_destinations($destinations);
}
......
......@@ -300,7 +300,7 @@ function node_form($form, &$form_state, $node) {
* Button submit function: handle the 'Delete' button on the node form.
*/
function node_form_delete_submit($form, &$form_state) {
$destination = '';
$destination = array();
if (isset($_GET['destination'])) {
$destination = drupal_get_destination();
unset($_GET['destination']);
......
......@@ -229,5 +229,5 @@ function _openid_test_endpoint_authenticate() {
// Put the signed message into the query string of a URL supplied by the
// Relying Party, and redirect the user.
drupal_set_header('Content-Type', 'text/plain');
header('Location: ' . url($_REQUEST['openid_return_to'], array('query' => http_build_query($response, '', '&'), 'external' => TRUE)));
header('Location: ' . url($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE)));
}
......@@ -499,7 +499,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
// Invoke search index update.
$this->drupalLogout();
$this->drupalGet($GLOBALS['base_url'] . '/cron.php', array('external' => TRUE, 'query' => 'cron_key=' . variable_get('cron_key', 'drupal')));
$this->drupalGet($GLOBALS['base_url'] . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => variable_get('cron_key', 'drupal'))));
// Search for $title.
$edit = array(
......@@ -521,7 +521,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
// Invoke search index update.
$this->drupalLogout();
$this->drupalGet($GLOBALS['base_url'] . '/cron.php', array('external' => TRUE, 'query' => 'cron_key=' . variable_get('cron_key', 'drupal')));
$this->drupalGet($GLOBALS['base_url'] . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => variable_get('cron_key', 'drupal'))));
// Search for $title.
$this->drupalPost('', $edit, t('Search'));
......
......@@ -1005,7 +1005,7 @@ protected function drupalLogout() {
// Make a request to the logout page, and redirect to the user page, the
// idea being if you were properly logged out you should be seeing a login
// screen.
$this->drupalGet('user/logout', array('query' => 'destination=user'));
$this->drupalGet('user/logout', array('query' => array('destination' => 'user')));
$pass = $this->assertField('name', t('Username field found.'), t('Logout'));
$pass = $pass && $this->assertField('pass', t('Password field found.'), t('Logout'));
......@@ -1779,7 +1779,7 @@ protected function clickLink($label, $index = 0) {
$this->assertTrue(isset($urls[$index]), t('Clicked link %label (@url_target) from @url_before', array('%label' => $label, '@url_target' => $url_target, '@url_before' => $url_before)), t('Browser'));
if (isset($urls[$index])) {
if (isset($url_target)) {
return $this->drupalGet($url_target);
}
return FALSE;
......@@ -1793,12 +1793,16 @@ protected function clickLink($label, $index = 0) {
* query, too. Can even be an absolute path which is just passed through.
* @return
* An absolute path.
*
* @todo What is the intention of this function? It is only invoked from
* locations, where URLs from the *output* are turned into absolute URLs,
* so why do we pass that through url() again?
*/
protected function getAbsoluteUrl($path) {
$options = array('absolute' => TRUE);
$parts = parse_url($path);
// This is more crude than the menu_is_external but enough here.
// This is more crude than menu_path_is_external() but enough here.
if (empty($parts['host'])) {
$options = array('absolute' => TRUE);
$path = $parts['path'];
$base_path = base_path();
$n = strlen($base_path);
......@@ -1806,7 +1810,19 @@ protected function getAbsoluteUrl($path) {
$path = substr($path, $n);
}
if (isset($parts['query'])) {
$options['query'] = $parts['query'];
parse_str($parts['query'], $options['query']);
// Let's make it a bit more crude. It's not clear why we invoke url() on
// a URL contained in the returned page output again, but since $path is
// FALSE (see $path = $parts['path'] above) with Clean URLs disabled,
// and url() now encodes the passed in query parameter array, we get a
// double-encoded 'q' query string in the resulting absolute URL
// generated by url(). This cannot be avoided in url(). But it could be
// completely avoided if this function wouldn't be calling url().
// @see SimpleTestURLTestCase->testGetAbsoluteUrl()
if (isset($options['query']['q'])) {
$path = $options['query']['q'];
unset($options['query']['q']);
}
}
$path = url($path, $options);
}
......@@ -2499,7 +2515,8 @@ protected function assertMail($name, $value = '', $message = '') {
*/
protected function verbose($message) {
if ($id = simpletest_verbose($message)) {
$this->pass(l(t('Verbose message'), $this->originalFileDirectory . '/simpletest/verbose/' . get_class($this) . '-' . $id . '.html', array('attributes' => array('target' => '_blank'))), 'Debug');
$url = file_create_url($this->originalFileDirectory . '/simpletest/verbose/' . get_class($this) . '-' . $id . '.html');
$this->pass(l(t('Verbose message'), $url, array('attributes' => array('target' => '_blank'))), 'Debug');
}
}
......
......@@ -270,6 +270,43 @@ class SimpleTestFunctionalTest extends DrupalWebTestCase {
}
}
/**
* Test internal testing framework URL handling.
*/
class SimpleTestURLTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'SimpleTest URL handling',
'description' => 'Test the URL handling in the testing framework.',
'group' => 'SimpleTest',
);
}
/**
* Test DrupalWebTestCase::getAbsoluteUrl().
*/
function testGetAbsoluteUrl() {
// Testbed runs with Clean URLs disabled, so disable it here.
$GLOBALS['conf']['clean_url'] = 0;
$url = 'user/login';
$this->drupalGet($url);
$absolute = url($url, array('absolute' => TRUE));
$this->assertEqual($absolute, $this->url, t('Passed and requested URL are equal.'));
$this->assertEqual($this->url, $this->getAbsoluteUrl($url), t('Requested and returned absolute URL are equal.'));
$this->drupalPost(NULL, array(), t('Log in'));
$this->assertEqual($absolute, $this->url, t('Passed and requested URL are equal.'));
$this->assertEqual($this->url, $this->getAbsoluteUrl($url), t('Requested and returned absolute URL are equal.'));
$this->clickLink('Create new account');
$url = 'user/register';
$absolute = url($url, array('absolute' => TRUE));
$this->assertEqual($absolute, $this->url, t('Passed and requested URL are equal.'));
$this->assertEqual($this->url, $this->getAbsoluteUrl($url), t('Requested and returned absolute URL are equal.'));
}
}
class SimpleTestMailCaptureTestCase extends DrupalWebTestCase {
/**
* Implement getInfo().
......
......@@ -58,7 +58,7 @@ function browser_test_print_post_form_submit($form, &$form_state) {
function browser_test_refresh_meta() {
if (!isset($_GET['refresh'])) {
$url = url('browser_test/refresh/meta', array('absolute' => TRUE, 'query' => 'refresh=true'));
$url = url('browser_test/refresh/meta', array('absolute' => TRUE, 'query' => array('refresh' => 'true')));
drupal_add_html_head('<meta http-equiv="Refresh" content="0; URL=' . $url . '">');
return '';
}
......@@ -68,7 +68,7 @@ function browser_test_refresh_meta() {
function browser_test_refresh_header() {
if (!isset($_GET['refresh'])) {
$url = url('browser_test/refresh/header', array('absolute' => TRUE, 'query' => 'refresh=true'));
$url = url('browser_test/refresh/header', array('absolute' => TRUE, 'query' => array('refresh' => 'true')));
drupal_set_header('Location', $url);
return '';
}
......
This diff is collapsed.
......@@ -447,10 +447,10 @@ class FormsFormStorageTestCase extends DrupalWebTestCase {
$user = $this->drupalCreateUser(array('access content'));
$this->drupalLogin($user);
$this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue', array('query' => 'cache=1'));
$this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue', array('query' => array('cache' => 1)));
$this->assertText('Form constructions: 1', t('The form has been constructed one time till now.'));
$this->drupalPost(NULL, array(), 'Save', array('query' => 'cache=1'));
$this->drupalPost(NULL, array(), 'Save', array('query' => array('cache' => 1)));
$this->assertText('Form constructions: 2', t('The form has been constructed two times till now.'));
$this->assertText('Title: new', t('The form storage has stored the values.'));
}
......
......@@ -116,7 +116,8 @@ function system_test_redirect_invalid_scheme() {
}
function system_test_destination() {
return 'The destination: ' . drupal_get_destination();
$destination = drupal_get_destination();
return 'The destination: ' . $destination['destination'];
}
/**
......
......@@ -130,9 +130,9 @@ function statistics_top_visitors() {
$result = $query->execute();
$rows = array();
$destination = drupal_get_destination();
foreach ($result as $account) {
$qs = drupal_get_destination();
$ban_link = $account->iid ? l(t('unblock IP address'), "admin/config/people/ip-blocking/delete/$account->iid", array('query' => $qs)) : l(t('block IP address'), "admin/config/people/ip-blocking/$account->hostname", array('query' => $qs));
$ban_link = $account->iid ? l(t('unblock IP address'), "admin/config/people/ip-blocking/delete/$account->iid", array('query' => $destination)) : l(t('block IP address'), "admin/config/people/ip-blocking/$account->hostname", array('query' => $destination));
$rows[] = array($account->hits, ($account->uid ? theme('username', $account) : $account->hostname), format_interval(round($account->total / 1000)), (user_access('block IP addresses') && !$account->uid) ? $ban_link : '');
}
......
......@@ -172,7 +172,7 @@ function system_requirements($phase) {
}
$description .= ' ' . $t('You can <a href="@cron">run cron manually</a>.', array('@cron' => url('admin/reports/status/run-cron')));
$description .= '<br />' . $t('To run cron from outside the site, go to <a href="!cron">!cron</a>', array('!cron' => url($base_url . '/cron.php', array('external' => TRUE, 'query' => 'cron_key=' . variable_get('cron_key', 'drupal')))));
$description .= '<br />' . $t('To run cron from outside the site, go to <a href="!cron">!cron</a>', array('!cron' => url($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => variable_get('cron_key', 'drupal'))))));
$requirements['cron'] = array(
'title' => $t('Cron maintenance tasks'),
......
......@@ -2336,7 +2336,7 @@ function system_admin_compact_mode() {
function system_admin_compact_page($mode = 'off') {
global $user;
user_save($user, array('admin_compact_mode' => ($mode == 'on')));
drupal_goto(drupal_get_destination());
drupal_goto();
}
/**
......
......@@ -379,12 +379,12 @@ class CronRunTestCase extends DrupalWebTestCase {
// Run cron anonymously with a random cron key.
$key = $this->randomName(16);
$this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => 'cron_key=' . $key));
$this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => $key)));
$this->assertResponse(403);
// Run cron anonymously with the valid cron key.
$key = variable_get('cron_key', 'drupal');
$this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => 'cron_key=' . $key));
$this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => $key)));
$this->assertResponse(200);
// Execute cron directly.
......
......@@ -47,7 +47,7 @@ function translation_node_overview($node) {
// No such translation in the set yet: help user to create it.
$title = t('n/a');
if (node_access('create', $node)) {
$options[] = l(t('add translation'), 'node/add/' . str_replace('_', '-', $node->type), array('query' => "translation=$node->nid&language=$language->language"));
$options[] = l(t('add translation'), 'node/add/' . str_replace('_', '-', $node->type), array('query' => array('translation' => $node->nid, 'language' => $language->language)));
}
$status = t('Not translated');
}
......
......@@ -3139,9 +3139,16 @@ function user_modules_uninstalled($modules) {
}
/**
* Rewrite the destination to prevent redirecting to login page after login.
* Helper function to rewrite the destination to avoid redirecting to login page after login.
*
* Third-party authentication modules may use this function to determine the
* proper destination after a user has been properly logged in.
*/
function user_login_destination() {
$destination = drupal_get_destination();
return $destination == 'destination=user%2Flogin' ? 'destination=user' : $destination;
if ($destination['destination'] == 'user/login') {
$destination['destination'] = 'user';
}
return $destination;
}
......@@ -292,7 +292,7 @@ function user_profile_form_submit($form, &$form_state) {
* Submit function for the 'Cancel account' button on the user edit form.
*/
function user_edit_cancel_submit($form, &$form_state) {
$destination = '';
$destination = array();
if (isset($_GET['destination'])) {
$destination = drupal_get_destination();
unset($_GET['destination']);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment