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.
Comment | File | Size | Author |
---|---|---|---|
#4 | system.module-383748-4-D7.patch | 878 bytes | markus_petrux |
#3 | system.module-383748-3-D7.patch | 906 bytes | markus_petrux |
#1 | system.module-383748-D7.patch | 848 bytes | markus_petrux |
Comments
Comment #1
markus_petrux CreditAttribution: markus_petrux commentedPatch against HEAD attached.
Comment #3
markus_petrux CreditAttribution: markus_petrux commentedhmm... now fixing the paths to be relative to Drupal root. Sorry.
Comment #4
markus_petrux CreditAttribution: markus_petrux commentedOops
Comment #5
markus_petrux CreditAttribution: markus_petrux commentedIf this patch is applied to D7, then please consider a back port to D6. I'll happily provide the patch if needed. Thank you.
Comment #6
j.somers CreditAttribution: j.somers commentedLooks OK, applied fine, works for me.
Comment #7
webchickSorry, 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. :)
Comment #8
markus_petrux CreditAttribution: markus_petrux commentedI 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.
Comment #9
peti2006@googlemail.com CreditAttribution: peti2006@googlemail.com commentedIt worked for Drupal 6.12. Thanks!
Comment #10
testertesters CreditAttribution: testertesters commentedI'm on 6.16, and this is still a problem.. I manually applied the code in the patch and got i working.
Comment #11
sunhttp://api.drupal.org/api/function/confirm_form/7 did get some, in the meantime. Please confirm that this issue actually still exists in D7.
Comment #12
HardikBadani CreditAttribution: HardikBadani commented#4: system.module-383748-4-D7.patch queued for re-testing.
Comment #13
sunComment #14
marthinal CreditAttribution: marthinal commented@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 !
Comment #15
bleuscyther CreditAttribution: bleuscyther commentedthe issue is solved for Drupal 7 : http://drupal.org/node/64975
Comment #16
webchickComment #17
Anonymous (not verified) CreditAttribution: Anonymous commentedThis 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.
Comment #18
sun@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...Comment #19
pacufist CreditAttribution: pacufist commentedWhen 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']));
}
}
Comment #20
yannickooJust 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.