·
Added a discussion

I’m running UNA 14.0.0 with the latest Payments module. Analysis of a bug I've identified (with some formatting and research help from ChatGPT) is listed below. This bug existed all the way back to the Dolphin days - and still exists in Una today.

PayPal successfully processes a payment and sends back an IPN with:

payment_status=Completed

But UNA sometimes logs:

_bx_payment_pp_err_wrong_transaction

and PayPal returns:

INVALID

during the IPN verification step.

After reviewing the UNA debug logs and the provider code, the cause can be reproduced and confirmed.

🔍 What the UNA logs show

  • UNA sends a "custom" value like:
custom = NHw4MQ%3D%3D
  • PayPal returns the IPN with the exact same value:
custom = NHw4MQ%3D%3D
  • But UNA’s validation request (cmd=_notify-validate) shows:
custom = NHw4MQ%253D%253D

The %3D  inside the custom value has been encoded twice.

PayPal requires the validation payload to match the original IPN exactly, so it responds:

INVALID

and UNA rejects an otherwise successful payment.

📘 PayPal IPN Specification Requirement

Direct quote from PayPal’s IPN documentation:

“You must send back the entire messageexactly as PayPal sent it, in your (cmd=_notify-validate) message.
The message must match byte-for-byte, otherwise PayPal will return INVALID .”

UNA’s current PayPal provider violates this requirement by re-encoding POST values.

🎯 Root Cause

The issue is in:

modules/boonex/payment/classes/BxPaymentProviderPayPal.php

Inside:

protected function _validateCheckout(&$aData, &$aPending)

UNA builds the validation request like this:

$sRequest .= '&' . urlencode($sKey) . '=' . urlencode(bx_process_pass($sValue));

This always encodes the value again, even if PayPal already encoded it.

Example:

NHw4MQ%3D%3D → NHw4MQ%253D%253D

As soon as this happens, PayPal will always return INVALID .

This is not environment-related — the behavior is in the provider code.

🛠 Fix / Patch

Modify the loop in _validateCheckout()  so that the original POST data

is passed back to PayPal without re-encoding the value.

Replace this:

$sRequest .= '&' . urlencode($sKey) . '=' . urlencode(bx_process_pass($sValue));

With this:

// Do not double-encode values — PayPal requires exact original values
$sRequest .= '&' . $sKey . '=' . $sValue;

This ensures:

  • UNA sends PayPal the exact original value
  • PayPal returns VERIFIED
  • Checkout completes successfully

🧪 Why this works

PayPal sends:

custom = NHw4MQ%3D%3D

If UNA returns:

custom = NHw4MQ%3D%3D

→ PayPal: VERIFIED

If UNA returns:

custom = NHw4MQ%253D%253D

→ PayPal: INVALID

The fix restores the required byte-for-byte match.

📝 Environment context

  • UNA 14.0.0
  • Payments module fully up to date
  • Apache + PHP-FPM 8.2.x
  • 57
  • 1