I tried to find and only was able to find the following issue, where it seems the involved code was reworked during D5: #84250: Allow usage of query string on confirm forms

There's something that confirm_form doesn't cover well, yet.

I noticed this with a Delete node link in Views. Tried to debug the issue and found that the problem seems to live in confirm_form().

Explanation:

In Views, it's easy to see query strings in the view URL. If you have one of these, Node Delete links have a destination argument that contains all the arguments in the current URL of the view. It's a path and query string.

When you click on one of those Delete links, you see a confirmation form. This confirmation form uses the destination argument of set, to build the returning path of the form. But in this case, destionation contains a path and a query string! The confirm_form() function is invoked like this:

  return confirm_form($form,
    t('Are you sure you want to delete %title?', array('%title' => $node->title)),
    isset($_GET['destination']) ? $_GET['destination'] : 'node/' . $node->nid,
    t('This action cannot be undone.'),
    t('Delete'),
    t('Cancel')
  );

Note that $_GET['destination'] is taken if set.

Then, in system.module, function confirm_form, we can see this:

  // Prepare cancel link
  $query = $fragment = NULL;
  if (is_array($path)) {
    $query = isset($path['query']) ? $path['query'] : NULL;
    $fragment = isset($path['fragment']) ? $path['fragment'] : NULL;
    $path = isset($path['path']) ? $path['path'] : NULL;
  }
  $cancel = l($no ? $no : t('Cancel'), $path, array('query' => $query, 'fragment' => $fragment));

Note that $path here would be $_GET['destination']. It's not an array, so is_array($path) is NOT true. Then, function l() is used with a $path that contains a path and a query string. But this does not work well in function url(), and it also gets drupal_urlencode'd, so we end up with a broken URL for the cancel link of confirm_form().

I fixed this on our D6 site, like the following, but I'm not sure if this is the best way to do it.

This is a mini-patch for function confirm_form() in modules/system/system.module.

   $query = $fragment = NULL;
   if (is_array($path)) {
     $query = isset($path['query']) ? $path['query'] : NULL;
     $fragment = isset($path['fragment']) ? $path['fragment'] : NULL;
     $path = isset($path['path']) ? $path['path'] : NULL;
   }
+  elseif (strpos($path, '?') !== FALSE) {
+    list($path, $query) = explode('?', $path);
+    if (strpos($query, '#') !== FALSE) {
+      list($query, $fragment) = explode('#', $query);
+    }
+  }
   $cancel = l($no ? $no : t('Cancel'), $path, array('query' => $query, 'fragment' => $fragment));

I haven't tested in D7, but the code looks the same as in D6, so I guess this issue affects both versions.

Please, consider backporting the resulting fix to D6.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

markus_petrux’s picture

Status: Active » Needs review
FileSize
848 bytes

Patch against HEAD attached.

Status: Needs review » Needs work

The last submitted patch failed testing.

markus_petrux’s picture

Status: Needs work » Needs review
FileSize
906 bytes

hmm... now fixing the paths to be relative to Drupal root. Sorry.

markus_petrux’s picture

Oops

markus_petrux’s picture

If this patch is applied to D7, then please consider a back port to D6. I'll happily provide the patch if needed. Thank you.

j.somers’s picture

Status: Needs review » Reviewed & tested by the community

Looks OK, applied fine, works for me.

webchick’s picture

Status: Reviewed & tested by the community » Needs work

Sorry, but this definitely sounds like something tweaky that is not going to get tested through regular use of Drupal and is going to break again someday. That means we need a test.

There are a cabal of folks in #drupal-dev right now who would love to help anyone write their first test on this. :)

markus_petrux’s picture

I have never written a simpletest, so I would appreciate if someone else can do it. I can show you the steps to reproduce the problem in Drupal core. For example, with the path module:

1) Goto admin/build/path and create 51 aliases.
2) Now you can go to page 2 (50 aliases per page).
3) Click the delete link on any alias.
4) Now, click the "Cancel" link next to the "Confirm" button. Bang!

Then, apply the patch in #4 and repeat. The "Cancel" link now works.

Now, the confirm_form() function is provided by system module, but there's any place in the system module where to reproduce the problem, so we need to find something else, for example, the path module as described above. The question is, the test should be implemented in system.test or path.test ? Also, I would appreciate if someone else could write it. I hope the description above helps.

peti2006@googlemail.com’s picture

It worked for Drupal 6.12. Thanks!

testertesters’s picture

I'm on 6.16, and this is still a problem.. I manually applied the code in the patch and got i working.

sun’s picture

Status: Needs work » Postponed (maintainer needs more info)

http://api.drupal.org/api/function/confirm_form/7 did get some, in the meantime. Please confirm that this issue actually still exists in D7.

HardikBadani’s picture

Status: Postponed (maintainer needs more info) » Needs review

#4: system.module-383748-4-D7.patch queued for re-testing.

sun’s picture

Status: Needs review » Postponed (maintainer needs more info)
marthinal’s picture

@markus_petrus your patch for D6 http://drupal.org/node/383760 works fine form me also... the problem is $path isnt an array in this case your elseif works.

Thanks for your time !

bleuscyther’s picture

the issue is solved for Drupal 7 : http://drupal.org/node/64975

webchick’s picture

Version: 7.x-dev » 6.x-dev
Status: Postponed (maintainer needs more info) » Needs review
Anonymous’s picture

Version: 6.x-dev » 7.2
Status: Needs review » Active

This remains as an issue in D7.

To recreate:

1) Create a custom menu called custom menu.
2) Navigate to admin/structure/menu/manage/menu-custom-menu/edit?destination=fail
3) Click Delete

You'll be redirected to the fail page instead of the confirmation page.

I discovered this because I have contextual links enabled and after clicking edit menu I am directed to admin/structure/menu/manage/menu-custom-menu/edit?destination=node which results in the same behavior.

sun’s picture

Version: 7.2 » 6.x-dev
Status: Active » Needs review

@darthclue: What you describe is the expected behavior of form redirects for the special destination query parameter. See http://api.drupal.org/api/drupal/includes--common.inc/function/drupal_go...

pacufist’s picture

When I go to delete node form, from views field "delete link" I have same problem.
In hook_form_alter wrote some check.

It`s works fine for me:
// Fix destination bug
if($form_id == 'node_delete_confirm'){
if($_GET['destination'] && isset($form['actions']['cancel'])){
$parts = parse_url($_GET['destination']);
$form['actions']['cancel']['#value'] = l(t('Cancel'),$parts['path'],array('query' => $parts['query']));
}
}

yannickoo’s picture

Just got that bug when I tried to edit a menu via a contextual link and then tried to delete that menu but I have been redirected to /node (where the actual link was), that was in 7.x.

Status: Needs review » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.