When clean URLs are switched off, one cannot create new menu items or list existing ones.

To reproduce:

  1. Switch off clean URLs
  2. Visit Administer > Structure > Menus
  3. Click "add link" for any of the menu items and create an item pointing to node#fragment?query=foo

Trying to save the menu item from step 3 will break with the following fatal error:

PHP Fatal error:  Unsupported operand types in \d7-patch\includes\common.inc on line 2601

Afterwards, attempts to "list items" for the same menu will result in the same error (so there is no easy way to remove the problematic menu item again).

Caused by the fact that $options['query'] is a string while $query is an array in the following piece of code (which is only run when clean URLs are disabled):

    if ($options['query']) {
      // We do not use array_merge() here to prevent overriding $path via query
      // parameters.
      $query += $options['query'];
    }

Not sure if the problem is specific to Clean URLs being switched off. When, after doing the above, I enable Clean URLs and try to add a similar menu item, I run into:

Recoverable fatal error: Argument 1 passed to drupal_http_build_query() must be an array, string given, called in \d7-patch\includes\common.inc on line 2585 and defined in drupal_http_build_query() (line 488 of \d7-patch\includes\common.inc).
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mr.baileys’s picture

Looks like this might be less related to the Clean URLs being switched off, and more to parse_url() being used on relative paths when saving a menu item containing a fragment/query.

From menu.admin.inc:

/**
 * Validate form values for a menu link being added or edited.
 */
function menu_edit_item_validate($form, &$form_state) {
  $item = &$form_state['values'];
  $normal_path = drupal_get_normal_path($item['link_path']);
  if ($item['link_path'] != $normal_path) {
    drupal_set_message(t('The menu system stores system paths only, but will use the URL alias for display. %link_path has been stored as %normal_path', array('%link_path' => $item['link_path'], '%normal_path' => $normal_path)));
    $item['link_path'] = $normal_path;
  }
  if (!url_is_external($item['link_path'])) {
    $parsed_link = parse_url(url($item['link_path']));

From the php docs for parse_url():

Note: This function doesn't work with relative URLs.

Running parse_url on "node#fragment?query=q" results in

array(2) { ["path"]=>  string(4) "node" ["query"]=>  string(16) "fragment?query=q" } 
mr.baileys’s picture

Hm, too early for me I guess: fragments go at the end, so "node?query=q#fragment"

Initial report is still valid: I cannot create menu items to "node?query=q#fragment" when clean URLs are disabled. Additionally, even though it seems to work since it was added to the menu validation handler, should we use parse_url on relative URLs even though the manual says it does not work?

mr.baileys’s picture

Status: Active » Needs review
FileSize
805 bytes

Patch for review.

mr.baileys’s picture

FileSize
753 bytes

Less whitespace.

catch’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Quick fix

RTBC when the bot comes back green.

Would be good to have tests for this, but would be better to have a test bot that runs everything without clean URLs IMO, so I think this can go in as a quick fix.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Good catch. Committed to CVS HEAD.

Status: Fixed » Closed (fixed)
Issue tags: -Quick fix

Automatically closed -- issue fixed for 2 weeks with no activity.