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 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 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 commentedOkay, the error is definitely triggered by the installation of admin_menu. Moving to that project.
Comment #4
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 commentedOkay, here's the minimal steps to reproduce:
Attached:
Comment #6
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 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 commentedOne-line patch.
Comment #9
pillarsdotnet commentedBetter title.
Comment #10
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 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 commentedFresh title
Comment #13
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 commentedNeed to read the api docs for watchdog() more carefully...
Comment #16
pillarsdotnet commentedtestbot
Comment #17
pillarsdotnet commentedComment #19
pillarsdotnet commentedTrying again...
Comment #20
pillarsdotnet commentedComment #21
pillarsdotnet commentedbetter title
Comment #23
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 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 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 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 commentedPlease re-read your code. You are setting 'bar' and reading 'access'.
Comment #28
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 commentedI still don't understand what you are up to.
Comment #30
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 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 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 commentedGood catch.
Comment #34
bohatt commentedmenu.inc-Undefined-index--access--in--item--array.patch queued for re-testing.
Comment #35
pillarsdotnet commentedRe-rolled for fuzz.
Comment #36
pillarsdotnet commentedRemoved what I now understand to be a superfluous watchdog call and re-rolled.
Comment #37
pillarsdotnet commentedPatch.
Comment #38
pillarsdotnet commentedBetter title.
Comment #39
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 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 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 commentedRe-opening for 7.x since the 8.x fix will not be backported.
Comment #43
pillarsdotnet commented#37: includes_menu.inc_.patch queued for re-testing.
Comment #45
pillarsdotnet commentedRe-rolled.
Comment #46
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 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 commentedi installed admin_menu again
and deactivated. also cleared all caches
its gone. . .
thank you all
Comment #49
pillarsdotnet commented#45: menu_check_access-994992-45.patch queued for re-testing.
Comment #50
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 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 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 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 commentedPutting a little isset in there fixes it...does this need tests? (unfortunately I wouldn't know what to test for)
Comment #57
jpstrikesback commentedComment #58
pillarsdotnet commentedPatch?
Comment #59
jpstrikesback commentedfor sure
Comment #60
barrapontoSeems 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 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 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 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 commentedBetter issue summary.