CRM-20776 - Navigation - Fix menu items with mix of #, ?, &
authorTim Otten <totten@civicrm.org>
Wed, 28 Jun 2017 06:47:19 +0000 (23:47 -0700)
committerTim Otten <totten@civicrm.org>
Wed, 28 Jun 2017 07:02:05 +0000 (00:02 -0700)
== Use case

 * Use an extension to implement `hook_civicrm_navigationMenu`.
 * Add or edit the URL of a menu item to use a mix of URL control chars -- eg `civicrm/case/a/#/case?dtab=0&dme=0`
 * Look in the CiviCRM navigation bar and see the final URL of the link.

== Before

 * The URL is munged (eg `http://dcase.l/civicrm/case/a/?dtab=0&dme=0#/case`)

== After

 * The URL appears consistent (eg `http://dcase.l/civicrm/case/a/#/case?dtab=0&dme=0`)

== Testing

 * On Drupal 7, I activated all components (CiviContribute, CiviMail, etal) to build a large pool of menu items.
   Then I grabbed the menu content (eg `http://dcase.l/civicrm/ajax/menujs/202/en_US/1/abcd1234`) -- both with and
   without the patch. The content was the same, except for the intended items.
 * Repeated above on WordPress (which does not use clean URLs).

CRM/Core/BAO/Navigation.php

index 32f18b86806eda92f96f34604dc3ae5f3786e81d..f450ef8d9b3d3735c6a17aaa2e0bc0e0c07020ca 100644 (file)
@@ -487,11 +487,14 @@ ORDER BY parent_id, weight";
       if (substr($url, 0, 4) !== 'http') {
         //CRM-7656 --make sure to separate out url path from url params,
         //as we'r going to validate url path across cross-site scripting.
-        $urlParam = explode('?', $url);
-        if (empty($urlParam[1])) {
-          $urlParam[1] = NULL;
+        $parsedUrl = parse_url($url);
+        if (empty($parsedUrl['query'])) {
+          $parsedUrl['query'] = NULL;
         }
-        $url = CRM_Utils_System::url($urlParam[0], $urlParam[1], FALSE, NULL, TRUE);
+        if (empty($parsedUrl['fragment'])) {
+          $parsedUrl['fragment'] = NULL;
+        }
+        $url = CRM_Utils_System::url($parsedUrl['path'], $parsedUrl['query'], FALSE, $parsedUrl['fragment'], TRUE);
       }
       elseif (strpos($url, '&amp;') === FALSE) {
         $url = htmlspecialchars($url);