Problem/Motivation
In function _menu_check_access()
of includes/menu.inc
, the documentation asserts:
$item['access'] becomes TRUE if the item is accessible, FALSE otherwise.
However, if the $item['access_callback']
function does not exist, the 'access'
property will not be set as advertised. This results in subtle and hard-to-troubleshoot bugs in apparently unrelated areas of code.
Proposed resolution
The patch in #45 logs a warning and sets $item['access']
to FALSE
when the callback function does not exist.
The proposed patch is a D7-only solution. In D8, the function_exists()
check was eliminated by #1059884-22: Drop function_exists for 'callback' functions.
Remaining tasks
The patch in #45 needs to be reviewed.
User interface changes
None.
API changes
None.
Original report by pillarsdotnet
Got some "undefined index" errors on a fresh install, and fixed them as follows:
diff --git includes/menu.inc includes/menu.inc
index 47d4941..c9fd51e 100644
--- includes/menu.inc
+++ includes/menu.inc
@@ -891,7 +891,7 @@ function _menu_link_translate(&$item, $translate = FALSE) {
_menu_check_access($item, $map);
}
// For performance, don't localize a link the user can't access.
- if ($item['access']) {
+ if (!empty($item['access'])) {
_menu_item_localize($item, $map, TRUE);
}
}
@@ -1424,7 +1424,7 @@ function _menu_tree_check_access(&$tree) {
foreach ($tree as $key => $v) {
$item = &$tree[$key]['link'];
_menu_link_translate($item);
- if ($item['access'] || ($item['in_active_trail'] && strpos($item['href'], '%') !== FALSE)) {
+ if (!empty($item['access']) || ($item['in_active_trail'] && strpos($item['href'], '%') !== FALSE)) {
if ($tree[$key]['below']) {
_menu_tree_check_access($tree[$key]['below']);
}
Comment | File | Size | Author |
---|---|---|---|
#59 | drupal.menu-check-access.59.patch | 594 bytes | jpstrikesback |
#54 | drupal.menu-check-access.54.patch | 566 bytes | sun |
#53 | menu_check_access-994992-53.patch | 1.04 KB | pillarsdotnet |
#45 | menu_check_access-994992-45.patch | 1.03 KB | pillarsdotnet |
#37 | includes_menu.inc_.patch | 575 bytes | pillarsdotnet |
Comments
Comment #1
Damien Tournoud CreditAttribution: Damien Tournoud commentedWe need more information here. At this point 'access' must be defined. The fact that it is not defined is a bug that needs investigating, not hiding under the carpet :)
Can you come up with reproduction steps that are as detailled as possible?
Comment #2
pillarsdotnet CreditAttribution: pillarsdotnet commented@Damien -- Thanks. I never know whether these variable keys are supposed to be defined, or whether the original programmer had E_NOTICE turned off.
Working on reproducing the issue, starting over with a blank database and reinstalling module-by-module, with the following code inserted:
It's entirely possible that the original error happened during my abortive attempt to do a D6--D7 upgrade. If I can't reproduce on a clean install I'll close this issue, and thanks again for your input.
Comment #3
pillarsdotnet CreditAttribution: pillarsdotnet commentedOkay, the error is definitely triggered by the installation of admin_menu. Moving to that project.
Comment #4
pillarsdotnet CreditAttribution: pillarsdotnet commentedUnfortunately, starting from a clean install and then adding admin_menu and admin_menu_toolbar, the problem doesn't trigger. So it's a combination of two or more modules that don't work together (sigh).
Still narrowing it down...
Comment #5
pillarsdotnet CreditAttribution: pillarsdotnet commentedOkay, here's the minimal steps to reproduce:
Attached:
Comment #6
pillarsdotnet CreditAttribution: pillarsdotnet commentedWeird. Now I can't duplicate...
Wonder if the problem was due to Google Chrome's "autocomplete prediction service" which I have subsequently turned off.
EDIT: Nope. Happened again as soon as I enabled some more modules... (sigh) Still debugging...
Comment #7
pillarsdotnet CreditAttribution: pillarsdotnet commentedOkay, I'm moving this back to Drupal core because the error seems to be in the field_ui module.
Here's the sequence of events:
near the end of the function.
with $callback = '_field_ui_view_mode_menu_access' and $arguments=array('user', 'user', 'full', 'user_access', 'administer users')
results in $visibility being FALSE, so the entire body of the function is skipped and no value is returned at all.
I believe that this is either a bug in _menu_translate (for relying on access callbacks to fulfill its contract) or in field_ui (for failing to set access in _field_ui_view_mode_menu_access).
Comment #8
pillarsdotnet CreditAttribution: pillarsdotnet commentedOne-line patch.
Comment #9
pillarsdotnet CreditAttribution: pillarsdotnet commentedBetter title.
Comment #10
geekgirlweb CreditAttribution: geekgirlweb commentedEven after patching I am still having the same error message displayed.
Correction, even after applying both patches:
http://drupal.org/files/issues/modules-field_ui.module.patch
http://drupal.org/files/issues/menu.inc-Undefined-index--access--in--ite...
Comment #11
pillarsdotnet CreditAttribution: pillarsdotnet commented@gamerxgirl -- probably there is another helper function being called that also fails to return a value. IMHO, _menu_translate should issue a warning when its helper function fails to return a value.
patch attached.
EDIT: Ignore http://drupal.org/files/issues/menu.inc-Undefined-index--access--in--ite...
It was checking in the wrong place.
Comment #12
pillarsdotnet CreditAttribution: pillarsdotnet commentedFresh title
Comment #13
geekgirlweb CreditAttribution: geekgirlweb commentedI undid the http://drupal.org/files/issues/menu.inc-Undefined-index--access--in--ite... patch and used the one you supplied. I haven't spotted the error messages yet, so I think that might have done the trick. If they do pop-up again I will let you know. Thanks!
Comment #15
pillarsdotnet CreditAttribution: pillarsdotnet commentedNeed to read the api docs for watchdog() more carefully...
Comment #16
pillarsdotnet CreditAttribution: pillarsdotnet commentedtestbot
Comment #17
pillarsdotnet CreditAttribution: pillarsdotnet commentedComment #19
pillarsdotnet CreditAttribution: pillarsdotnet commentedTrying again...
Comment #20
pillarsdotnet CreditAttribution: pillarsdotnet commentedComment #21
pillarsdotnet CreditAttribution: pillarsdotnet commentedbetter title
Comment #23
Damien Tournoud CreditAttribution: Damien Tournoud commentedThat makes no sense. A NULL value is a set value anyway. If the menu router passed through _menu_translate(), there can be no notice.
Comment #24
pillarsdotnet CreditAttribution: pillarsdotnet commented@Damien -- Try running the following code:
PHP 5.3 prints "The function did not return a value." Perhaps your PHP behaves differently.
Comment #25
Damien Tournoud CreditAttribution: Damien Tournoud commentedPlease re-read #23. What I said is that:
... doesn't trigger any notice.
Yet it happens that you are trying to fix a
Notice: Undefined index
, right?You still haven't described how to reliably reproduce the problem, as a consequence I'm confused about what problem you are actually trying to fix. What I do know is that what you describe in #7 (and the subsequent patches you posted) cannot possibly explain the notice.
Comment #26
pillarsdotnet CreditAttribution: pillarsdotnet commentedThe router item with its NULL value gets serialized and stored in the database, then unserialized and used later.
Try this:
Comment #27
Damien Tournoud CreditAttribution: Damien Tournoud commentedPlease re-read your code. You are setting 'bar' and reading 'access'.
Comment #28
pillarsdotnet CreditAttribution: pillarsdotnet commentedBah. You're right. But doggone it, SOMEWHERE it was producing errors the other day. Will keep trying. Meanwhile I still assert that the function fails to fulfill its contract, because it promises either TRUE or FALSE and delivers NULL, which is neither.
Comment #29
Damien Tournoud CreditAttribution: Damien Tournoud commentedI still don't understand what you are up to.
Comment #30
pillarsdotnet CreditAttribution: pillarsdotnet commentedI'm trying to avoid another six hours sifting through megabytes of debug output trying to nail down why it is that when $item['access'] is set to NULL rather than TRUE or FALSE, a notice later occurs.
Comment #31
Damien Tournoud CreditAttribution: Damien Tournoud commentedWell, we can definitely fix this menu access callback, but I really doubt it will fix the problem you have been having, which I feel is unrelated.
Comment #32
Damien Tournoud CreditAttribution: Damien Tournoud commentedActually, this can only happen in one case: when the 'access callback' function does not exist.
I suggest we just add a error trigger in _menu_check_access() in that case.
Comment #33
pillarsdotnet CreditAttribution: pillarsdotnet commentedGood catch.
Comment #34
bohatt CreditAttribution: bohatt commentedmenu.inc-Undefined-index--access--in--item--array.patch queued for re-testing.
Comment #35
pillarsdotnet CreditAttribution: pillarsdotnet commentedRe-rolled for fuzz.
Comment #36
pillarsdotnet CreditAttribution: pillarsdotnet commentedRemoved what I now understand to be a superfluous watchdog call and re-rolled.
Comment #37
pillarsdotnet CreditAttribution: pillarsdotnet commentedPatch.
Comment #38
pillarsdotnet CreditAttribution: pillarsdotnet commentedBetter title.
Comment #39
pillarsdotnet CreditAttribution: pillarsdotnet commentedBrowsing the issue queue, I like the approach in #1059884: Drop function_exists for 'callback' functions better. Marking this issue as duplicate.
Comment #40
andreak CreditAttribution: andreak commentedMany many thanks to whomever posted the following code! You saved me hours of frustration. I had just installed a brand new drupal 7 with the newest ubercart and got the dreaded "undefined index: _menu_check_access() in includes/menu.inc line 776" issue every time I clicked on one of my products grrr. but This fixed it!!!
Now I can sleep....zzz...zzz
-Andrea
diff --git includes/menu.inc includes/menu.inc
index a3121c7..246d076 100644
--- includes/menu.inc
+++ includes/menu.inc
@@ -618,6 +618,13 @@ function _menu_check_access(&$item, $map) {
elseif (function_exists($callback)) {
$item['access'] = call_user_func_array($callback, $arguments);
}
+ else {
+ watchdog('menu.inc',
+ 'Undefined access callback function :callback in router_item :item',
+ array(':callback' => $callback, ':item' => var_export($item,1)),
+ WATCHDOG_WARNING);
+ $item['access'] = FALSE;
+ }
}
}
Comment #41
shanarigelhaupt CreditAttribution: shanarigelhaupt commentedHello,
I received these errors :
Notice: Undefined index: access in _menu_link_translate() (line 913 of /home/content/22/5654522/html/includes/menu.inc).
Notice: Undefined index: access in _menu_tree_check_access() (line 1488 of /home/content/22/5654522/html/includes/menu.inc).
I see from this thread that there is a patch? How do I install the patch?
Any help would be appreciated.
Thank you!
Comment #42
pillarsdotnet CreditAttribution: pillarsdotnet commentedRe-opening for 7.x since the 8.x fix will not be backported.
Comment #43
pillarsdotnet CreditAttribution: pillarsdotnet commented#37: includes_menu.inc_.patch queued for re-testing.
Comment #45
pillarsdotnet CreditAttribution: pillarsdotnet commentedRe-rolled.
Comment #46
Summit CreditAttribution: Summit commentedHi, This patch #45 is working for me. Will this be committed soon?
EDIT: sorry, still
With this patch..
Greetings, Martijn
Comment #47
pillarsdotnet CreditAttribution: pillarsdotnet commented@#46 I don't think your error is related to this issue. If you disagree, please walk the rest of us through the code path you think is occurring.
Comment #48
rashvin CreditAttribution: rashvin commentedi installed admin_menu again
and deactivated. also cleared all caches
its gone. . .
thank you all
Comment #49
pillarsdotnet CreditAttribution: pillarsdotnet commented#45: menu_check_access-994992-45.patch queued for re-testing.
Comment #50
pillarsdotnet CreditAttribution: pillarsdotnet commentedUpdated issue summary. Either this patch or a backport of #1059884: Drop function_exists for 'callback' functions should be reviewed and committed.
Comment #51
itz_andr3 CreditAttribution: itz_andr3 commentedI got this issue on localhost, while on live hosting not.Step:Install clean drupal 7.12Restore database from live hosting.Error happened.Maybe can give an insight, of what might be the problemIgnore this, i finds out, my module not completely copied
Comment #52
sun1) All on one line, please.
2) Must use t() placeholders instead of db_query() placeholders.
3) Let's use this text: "Undefined access callback %function() for router path @path"
4) WATCHDOG_ERROR is more appropriate.
5) Type/category should be just "menu".
Comment #53
pillarsdotnet CreditAttribution: pillarsdotnet commentedRe-rolled as requested.
Comment #54
sunThe message needs to be within the watchdog() call to be compatible with the potx extractor.
Fixed patch attached.
Comment #55
jpstrikesback CreditAttribution: jpstrikesback commentedAfter Applying #54 and upon clearing caches I get:
Notice: Undefined index: _number_parts in _menu_router_build() (line 3624 of /includes/menu.inc) on the Performance page and:Notice: Undefined index: path in _menu_check_access() (line 641 of /includes/menu.inc)
on a node page
Comment #56
jpstrikesback CreditAttribution: jpstrikesback commentedPutting a little isset in there fixes it...does this need tests? (unfortunately I wouldn't know what to test for)
Comment #57
jpstrikesback CreditAttribution: jpstrikesback commentedComment #58
pillarsdotnet CreditAttribution: pillarsdotnet commentedPatch?
Comment #59
jpstrikesback CreditAttribution: jpstrikesback commentedfor sure
Comment #60
barraponto CreditAttribution: barraponto commentedSeems to have fixed the issue.
Comment #61
sunA router $item without 'path'? Eh?
No, either there's more debugging info for #55, or that case is bogus in itself. In turn, the added isset() hides a deeper error, which is not what we want.
It's late here, so it's possible that I overlook something obvious.
Comment #62
fietserwinI got this message on an item in the default navigation menu after the search module was disabled. Clearing the cache solved the problem. But if the menu cache is not cleared automatically, this is a situation that may arise. Thus I guess the patch is correct in solving the problem "by hiding it"., but the addition in #59 (w,r,t, #54) seems to be adding a hiding of a case that should not be hidden. So IMO #54 is correct, while #59 is too forgiving.
Comment #63
a.ross CreditAttribution: a.ross commentedAgreed. The case in #55 seems to have more issues unrelated to this. Patch in #54 looks good to me. Tentatively marking this RTBC...
Comment #64
webchickI can replicate the issue in #55 with the following:
"Notice: Undefined index: path in _menu_check_access() (line 641 of /Users/abyron/Sites/7.x/includes/menu.inc)."
Needs work, and also needs tests, because that should've been caught.
I wonder if while we're at it we want to include a check for no access callback. This will give you a 403 but it won't tell you why.
Comment #65
webchickAnd also, I would consider this a new feature, not a bug. The bug is in your code. You're asking for additional babysitting, which is something new core wasn't doing for you before.
Comment #66
jpstrikesback CreditAttribution: jpstrikesback commentedI haven't been able to replicate the notice anymore, it must have been in a module I updated or stopped using. (also using 7.15 now and iirc it wasn't out at time of posting 55)
Comment #67
pillarsdotnet CreditAttribution: pillarsdotnet commentedIf this is a feature request, then it should be marked "wontfix" because the "feature" of checking for function existence was removed in 8.x.
Comment #67.0
pillarsdotnet CreditAttribution: pillarsdotnet commentedBetter issue summary.