diff --git a/vendor/magento/module-paypal/Model/Payflow/Service/Gateway.php b/vendor/magento/module-paypal/Model/Payflow/Service/Gateway.php index 6a2229c3d55..bd9bd21d57d 100644 --- a/vendor/magento/module-paypal/Model/Payflow/Service/Gateway.php +++ b/vendor/magento/module-paypal/Model/Payflow/Service/Gateway.php @@ -85,7 +85,8 @@ class Gateway implements GatewayInterface ); $client->setConfig($clientConfig); $client->setMethod(\Zend_Http_Client::POST); - $client->setParameterPost($request->getData()); + $requestData = $this->prepareRequestData($request->getData()); + $client->setParameterPost($requestData); $client->setHeaders( [ 'X-VPS-VIT-CLIENT-CERTIFICATION-ID' => '33baf5893fc2123d8b191d2d011b7fdc', @@ -97,9 +98,7 @@ class Gateway implements GatewayInterface try { $response = $client->request(); - - $responseArray = []; - parse_str(strstr($response->getBody(), 'RESULT'), $responseArray); + $responseArray = $this->parseNVP(strstr($response->getBody(), 'RESULT')); $result->setData(array_change_key_case($responseArray, CASE_LOWER)); $result->setData('result_code', $result->getData('result')); @@ -115,7 +114,7 @@ class Gateway implements GatewayInterface } finally { $this->logger->debug( [ - 'request' => $request->getData(), + 'request' => $requestData, 'result' => $result->getData() ], (array)$config->getValue('getDebugReplacePrivateDataKeys'), @@ -125,4 +124,62 @@ class Gateway implements GatewayInterface return $result; } + + /** + * Add length tag to parameters name which contains special characters: =, & + * + * The length tag specifies the exact number of characters and spaces (number of bytes) that appear in the value + * eg ['COMPANYNAME[14]' => 'Ruff & Johnson')] + * + * @param array $data + * @return array + */ + private function prepareRequestData(array $data): array + { + $requestData = []; + foreach ($data as $k => $v) { + if (strpos($v, '&') !== false || strpos($v, '=') !== false) { + $requestData[$k . '[' . strlen($v) . ']'] = $v; + } else { + $requestData[$k] = $v; + } + } + return $requestData; + } + + /** + * Parse NVP string into array + * + * Use length tag (if present) to parse the key value. + * + * The length tag specifies the exact number of characters and spaces (number of bytes) that appear in the value + * e.g COMPANYNAME[14]=Ruff & Johnson + * e.g COMMENT1[7]=Level=5 + * @param string $nvp + * @return array + */ + private function parseNVP(string $nvp): array + { + $result = []; + while (strlen($nvp) > 0) { + $keyPos = strpos($nvp, '='); + if ($keyPos !== false) { + $key = substr($nvp, 0, $keyPos); + if (preg_match('/\[(\d+)]$/', $key, $keyParts)) { + $valueLength = (int)$keyParts[1]; + $key = substr($key, 0, strpos($key, '[')); + $result[$key] = substr($nvp, $keyPos + 1, $valueLength); + $valuePos = $keyPos + 1 + $valueLength; + } else { + $valuePos = strpos($nvp, '&') ? strpos($nvp, '&') : strlen($nvp); + $value = substr($nvp, $keyPos + 1, $valuePos - $keyPos - 1); + $result[$key] = $value; + } + $nvp = substr($nvp, $valuePos + 1); + } else { + $nvp = ''; + } + } + return $result; + } }