com.drastikbydesign.stripe icon indicating copy to clipboard operation
com.drastikbydesign.stripe copied to clipboard

Wrong URL redirect when error + language prefix in URL

Open rthouvenin opened this issue 7 years ago • 5 comments

We are using the extension on a Drupal install, with language negotation by path prefix. So for example, a page in English will have a URL www.domain.org/civicrm/contribute/transact, and page in German will have a URL www.domain.org/de/civicrm/contribute/transact.

When a error occurs during the processing of a donation, the user is redirected to the URL where they came from, with a different query. The redirect URL is computed in CRM_Core_Payment_Stripe#doDirectPayment, by giving the path and query to CRM_Utils_System::url(). I am not sure why it is done that way rather than just appending the parameters to the entry URL, but the problem is that the url function prepends the language prefix again, and so the user is redirected to e.g. www.domain.org/de/de/civicrm/contribute/transact.

The solutions I can see to this are:

  • Don't call the url function, just append the parameters to the query
  • If above is not possible, instead of:
$parsed_url = parse_url($params['entryURL']);

do:

$entryURL = CRM_Utils_System::languageNegotiationURL($params['entryURL'], FALSE, TRUE);
$parsed_url = parse_url($entryURL); 

I have tested the second solution, but I don't know enough about other CMS and their language negotiation to be sure that it works in all use cases.

rthouvenin avatar Apr 14 '17 12:04 rthouvenin

@rthouvenin, you made the change here: https://github.com/drastik/com.drastikbydesign.stripe/blob/4.7-dev/CRM/Core/Payment/Stripe.php#L353:L359

changing from this:

...
    else {
      $qfKey = $params['qfKey'];
      $parsed_url = parse_url($params['entryURL']);
      $url_path = substr($parsed_url['path'], 1);
      $params['stripe_error_url'] = $error_url = CRM_Utils_System::url($url_path,
      $parsed_url['query'] . "&_qf_Main_display=1&qfKey={$qfKey}", FALSE, NULL, FALSE);
    }
...

to this:

...
    else {
      $qfKey = $params['qfKey'];
      $entryURL = CRM_Utils_System::languageNegotiationURL($params['entryURL'], FALSE, TRUE);
      $parsed_url = parse_url($entryURL);
      $url_path = substr($parsed_url['path'], 1);
      $params['stripe_error_url'] = $error_url = CRM_Utils_System::url($url_path,
      $parsed_url['query'] . "&_qf_Main_display=1&qfKey={$qfKey}", FALSE, NULL, FALSE);
    }
...

DaveBagler avatar Apr 19 '17 01:04 DaveBagler

@DaveBagler yes exactly

rthouvenin avatar Apr 25 '17 12:04 rthouvenin

This issue also occurs for environments with path-element in their base-url: https://example.com/mycivicrm/

My approach was to replace:

  $parsed_url = parse_url($params['entryURL']);
  $url_path = substr($parsed_url['path'], 1);

with

 $url_path = CRM_Utils_System::currentPath();

This also works with language-switches in the url.

thomst avatar May 24 '17 13:05 thomst

I would like to clarify my point: I think the logic of DaveBaglers solution is still not consistent. parse_url($params['entryURL']) will always give the whole path of the URL and strip only the domain. While CRM_Utils_System::url($url_path, ...); will use CIVICRM_UF_BASEURL and add the $url_path. But CIVICRM_UF_BASEURL might already consists of a domain plus additional path-element.

In the first place parsing the entryURL we use a generic logic, while in the second place composing the error-url we use a CiviCRM-logic. It might be more stable to use CiviCRM-logic in both cases. Therefore I suggest using CRM_Utils_System::currentPath(); to get the $url_path.

thomst avatar May 29 '17 07:05 thomst

@thomst, yeah I think it would be good to use CiviCRM's API, but in the meantime, @rthouvenin's solution works for my clients.

DaveBagler avatar May 30 '17 12:05 DaveBagler