extreme-bg / borica-emv-3ds Goto Github PK
View Code? Open in Web Editor NEWClient library for Borica EMV 3DS
License: MIT License
Client library for Borica EMV 3DS
License: MIT License
Remove all usages of openssl_free_key()
as it is now deprecated, and the code produces warnings/errors in the future. More info at https://www.php.net/manual/en/function.openssl-free-key.php
Its about new version 1.0.1...
When try to create a form, that messages appear:
Warning: Undefined array key "RFU" in ...\common\composer\extreme-bg\borica-emv-3ds\src\Borica.php on line 139
Deprecated: mb_strlen(): Passing null to parameter #1 ($string) of type string is deprecated in ...\common\composer\extreme-bg\borica-emv-3ds\src\Borica.php on line 142
Its because RFU is not set and there is no check for null or missing value.
:) I will create a fix for me but... its good to be updated.
Greetings
This is up-to-date list with response status codes (translated both in Bulgarian and English):
/**
* Response codes
*/
const RESPONSE_CODES = [
'bg' => [
'-1' => 'В заявката не е попълнено задължително поле',
'-2' => 'Заявката съдържа поле с некоректно име',
'-3' => 'Aвторизационният хост не отговаря или форматът на отговора е неправилен',
'-4' => 'Няма връзка с авторизационния хост',
'-5' => 'Грешка във връзката с авторизационния хост',
'-6' => 'Грешка в конфигурацията на APGW',
'-7' => 'Форматът на отговора от авторизационният хост е неправилен',
'-10' => 'Грешка в поле "Сума" в заявката',
'-11' => 'Грешка в поле "Валута" в заявката',
'-12' => 'Грешка в поле "Идентификатор на търговеца" в заявката',
'-13' => 'Неправилен IP адрес на търговеца',
'-15' => 'Грешка в поле "RRN" в заявката',
'-16' => 'В момента се изпълнява друга трансакция на терминала',
'-17' => 'Отказан достъп до платежния сървър (напр. грешка при проверка на P_SIGN)',
'-19' => 'Грешка в искането за аутентикация или неуспешна аутентикация',
'-20' => 'Разрешената разлика между времето на сървъра на търговеца и e-Gateway сървъра е надвишена',
'-21' => 'Трансакцията вече е била изпълнена',
'-22' => 'Трансакцията съдържа невалидни данни за аутентикация',
'-23' => 'Невалиден контекст на транзацията',
'-24' => 'Заявката съдържа стойности за полета, които не могат да бъдат обработени. Например валутата е различна от тази на терминала или трансакцията е по-стара от 24 часа.',
'-25' => 'Допълнителното потвърждение на трансакцията е отказано от картодържателя',
'-26' => 'Невалиден BIN на картата',
'-27' => 'Невалидно име на търговеца',
'-28' => 'Невалидно допълнително поле (например AD.CUST_BOR_ORDER_ID)',
'-29' => 'Невалиден отговор от ACS на издателя на картата',
'-30' => 'Трансакцията е отказана',
'-31' => 'Трансакцията е в процес на обработка',
'-32' => 'Дублирана отказана трансакция',
'-33' => 'Трансакцията е в процес на аутентикация на картодържателя',
'-40' => 'Трансакцията е в процес на обработка',
'00' => 'Трансакцията е завършена успешно',
'01' => 'Обърнете се към издателя на картата',
'04' => 'Задържане на картата',
'05' => 'Не зачитайте картата',
'06' => 'Грешка',
'12' => 'Невалидна трансакция',
'13' => 'Невалидна сума',
'14' => 'Няма такава карта',
'15' => 'Няма такъв издател',
'17' => 'Анулиране от клиента',
'30' => 'Грешка на форматирането',
'35' => 'Задържане на картата, приобретател на контакт с акцептор на карта',
'36' => 'Задържане на картата, карта ограничена',
'37' => 'Задържане на картата, повикване сигурност на получателя',
'38' => 'Задържане на картата, допустимите опити за ПИН са надвишени',
'39' => 'Няма кредитна сметка',
'40' => 'Заявената функция не се поддържа',
'41' => 'Задържане на картата, загубена карта',
'42' => 'Няма универсален акаунт',
'43' => 'Задържане на картата, открадната карта',
'54' => 'Изтекла карта / цел',
'55' => 'Неправилен ПИН',
'56' => 'Няма запис за картата',
'57' => 'Трансакцията не е разрешена на картодържателя',
'58' => 'Трансакцията не е разрешена до терминал',
'59' => 'Подозирана измама',
'82' => 'Време за изчакване',
'85' => 'Няма причина за отказ',
'88' => 'Криптографска грешка',
'89' => 'Неуспешно удостоверяване',
'91' => 'Издателят или суичът не работи',
'95' => 'Съгласуваща грешка / Удостоверяването не е намерено',
'96' => 'Неизправност на системата',
'1A' => 'Свържете се с Вашата банка',
'B1' => 'Допълнителната сума не е разрешена за карти Visa (само за купувачи в САЩ)',
'N0' => 'Принудително STIP',
'N3' => 'Касовата услуга не е налична',
'N4' => 'Искането за кешбек надвишава лимита на издателя',
'N7' => 'Отказ поради грешка в CVV2',
'P2' => 'Невалидна информация за фактуращия',
'P5' => 'Искането за промяна / деблокиране на ПИН е отхвърлено',
'P6' => 'Несигурен ПИН',
'Q1' => 'Удостоверяването на картата не бе успешно',
'R0' => 'Стоп-платежно нареждане',
'R1' => 'Отмяна на нареждане за упълномощаване',
'R3' => 'Отмяна на всички нареждания за авторизация',
'FAR' => 'Препращане към емитента',
'XD' => 'Препращане към емитента',
'Z3' => 'Не може да се влезе онлайн'
],
'en' => [
'-1' => 'A mandatory request field is not filled in',
'-2' => 'CGI request validation failed',
'-3' => 'Acquirer host (TS) does not respond or wrong format of e-gateway response template file',
'-4' => 'No connection to the acquirer host (TS)',
'-5' => 'The acquirer host (TS) connection failed during transaction processing',
'-6' => 'e-Gateway configuration error',
'-7' => 'The acquirer host (TS) response is invalid, e.g. mandatory fields missing',
'-10' => 'Error in the "Amount" request field',
'-11' => 'Error in the "Currency" request field',
'-12' => 'Error in the "Merchant ID" request field',
'-13' => 'The referrer IP address (usually the merchant\'s IP) is not the one expected',
'-15' => 'Error in the "RRN" request field',
'-16' => 'Another transaction is being performed on the terminal',
'-17' => 'The terminal is denied access to e-Gateway',
'-19' => 'Error in the authentication information request or authentication failed.',
'-20' => 'The permitted time interval (1 hour by default) between the transaction timestamp request field and the e-Gateway time was exceeded',
'-21' => 'The transaction has already been executed',
'-22' => 'Transaction contains invalid authentication information',
'-23' => 'Invalid transaction context',
'-24' => 'Transaction context data mismatch',
'-25' => 'Transaction confirmation state was canceled by user',
'-26' => 'Invalid action BIN',
'-27' => 'Invalid merchant name',
'-28' => 'Invalid incoming addendum(s)',
'-29' => 'Invalid/duplicate authentication reference',
'-30' => 'Transaction was declined as fraud',
'-31' => 'Transaction already in progress',
'-32' => 'Duplicate declined transaction',
'-33' => 'Customer authentication by random amount or verify one-time code in progress',
'-40' => 'Client side transaction form in progress',
'00' => 'Transaction completed successfully',
'01' => 'Refer to card issuer',
'04' => 'Pick Up',
'05' => 'Do not Honour',
'06' => 'Error',
'12' => 'Invalid transaction',
'13' => 'Invalid amount',
'14' => 'No such card',
'15' => 'No such issuer',
'17' => 'Customer cancellation',
'30' => 'Format error',
'35' => 'Pick-up, card acceptor contact acquirer',
'36' => 'Pick up, card restricted',
'37' => 'Pick up, call acquirer security',
'38' => 'Pick up, Allowable PIN tries exceeded',
'39' => 'No credit account',
'40' => 'Requested function not supported',
'41' => 'Pick up, lost card',
'42' => 'No universal account',
'43' => 'Pick up, stolen card',
'54' => 'Expired card / target',
'55' => 'Incorrect PIN',
'56' => 'No card record',
'57' => 'Transaction not permitted to cardholder',
'58' => 'Transaction not permitted to terminal',
'59' => 'Suspected fraud',
'82' => 'Timeout',
'85' => 'No reason to decline',
'88' => 'Cryptographic failure',
'89' => 'Authentication failure',
'91' => 'Issuer or switch is inoperative',
'95' => 'Reconcile error / Auth Not found',
'96' => 'System Malfunction',
'1A' => 'Call your bank',
'B1' => 'Surcharge amount not permitted on Visa cards (U.S. acquirers only)',
'N0' => 'Force STIP',
'N3' => 'Cash service not available',
'N4' => 'Cashback request exceeds issuer limit',
'N7' => 'Decline for CVV2 failure',
'P2' => 'Invalid biller information',
'P5' => 'PIN change/unblock request declined',
'P6' => 'Unsafe PIN',
'Q1' => 'Card authentication failed',
'R0' => 'Stop payment order',
'R1' => 'Revocation of authorization order',
'R3' => 'Revocation of all authorizations order',
'FAR' => 'Forward to issuer',
'XD' => 'Forward to issuer',
'Z3' => 'Unable to go online'
]
];
A simple new class method should be implemented inside Request
which handles sanitization, example:
/*
* Function to sanitize string - Strip tags, optionally strip or encode special characters.
* @Params: $string = the string, $mode = encode or strip special characters
*/
private static function sanitize_string ($string, $mode = "strip"): string {
if(!is_string($string))
return;
switch ($mode) {
default:
case "strip":
$filter = array("flags"=> FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_BACKTICK); //Keep characters like é and д
break;
case "encode":
$filter = array("flags"=> FILTER_FLAG_ENCODE_LOW|FILTER_FLAG_ENCODE_AMP); //Keep characters like é and д
break;
}
//Prevent Unicode and XSS attacks
//https://stackoverflow.com/questions/8491431/how-to-replace-remove-4-byte-characters-from-a-utf-8-string-in-php
return preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", filter_var(trim($string), FILTER_SANITIZE_STRING, $filter));
}
}
And then, the renderForm()
method should be updated:
public function renderForm($borica) : string {
$html = '<form action="' . self::sanitize_string ($borica->getApiUrl()) . '" method="POST" id="boricaForm">';
foreach ($this->toPostData() as $key => $value) {
$html .= '<input name="' . self::sanitize_string ($key) . '" value="' . self::sanitize_string ($value) . '" style="width: 100%;"><br>';
}
$html .= '<button type="submut">Send to Borica</button></form>';
return $html;
}
Class method verifySignature()
always returns false
even if response's isSuccessful()
is true
when checking APGW response.
From last Borica documentation MAC fields (Signature) are changed and this library will not work after 21 july 2023 until MAC_GENERAL is provided.
The method withPost()
inside class Response
should be changed as follows as it can return null values (PHP 7.1+):
public static function withPost(array $postData) : ?Response {
// The rest of code
}
This change is mandatory since post data, returned from Borica can be corrupted and produces fatal error Return value must be an instance of Response, null returned...
Also a very good programming practice is to wrap in try-catch
such scenarios.
There a few useful (and important by my opinion) properties, which are not added inside Response
class, those are according the new documentation v.3.0 of APGW and those properties are used to verify by external entity (i.e. accountant) that the card belongs to given user. See below, all the properties are conditional:
AUTH_STEP_RES
=> Status of the authentication, used in scheme 3-D Secure
CARDHOLDERINFO
=> Information regarding the cardholder, provided by ACS issuer. Note: the e-commerce system must visualize this field to customer
CARD_BRAND
=> The brand of the card (i.e. Visa, MasterCard, etc.)
Adding new public method in class Response
which displays exact response from Borica could benefit debugging:
/**
* Response codes in human-friendly format
*
* @return string
*/
public function responseDescription() : string {
$description = '';
//Maybe all codes could be combined in one array?
if(isset($this->responseCode) && (array_key_exists($this->responseCode, $this::RESPONSE_CODES) || array_key_exists($this->responseCode, $this::RESPONSE_ERROR_CODES))) {
//Negative response codes
if(intval($this->responseCode) < 0) {
$description = $this::RESPONSE_ERROR_CODES[$this->responseCode];
}
//Non-negative response codes, including mixed(letters/numbers)
else {
$description = $this::RESPONSE_CODES[$this->responseCode];
}
}
return $description;
}
In Request.php
file, the method renderForm()
has a form with one "submit" button with misspelled attribute, it should be type="submit"
instead of type="submut"
.
Inside class Response
the property originalTranscationType
is misspelled, also the TRAN_TRTYPE
which is assigned to this property is not returned with the response anymore, so maybe this property can be deleted.
Autoload rules are not included
Error response codes in class Response
are incomplete. Here is the up-to-date list (Bulgarian):
const RESPONSE_ERROR_CODES = [
-1 => 'В заявката не е попълнено задължително поле',
-2 => 'Заявката съдържа поле с некоректно име',
-3 => 'Aвторизационният хост не отговаря или форматът на отговора е неправилен',
-4 => 'Няма връзка с авторизационния хост',
-5 => 'Грешка във връзката с авторизационния хост',
-6 => 'Грешка в конфигурацията на APGW',
-7 => 'Форматът на отговора от авторизационният хост е неправилен',
-9 => 'Грешна дата на валидност на картата',
-10 => 'Грешка в поле "Сума" в заявката',
-11 => 'Грешка в поле "Валута" в заявката',
-12 => 'Грешка в поле "Идентификатор на търговец" в заявката',
-13 => 'Неправилен IP адрес на търговеца',
-15 => 'Грешка в поле "RRN" в заявката',
-16 => 'В момента се изпълнява друга трансакция на терминала',
-17 => 'Отказан достъп до платежния сървър (напр. грешка при проверка на P_SIGN)',
-19 => 'Грешка в искането за автентикация или неуспешна автентикация',
-20 => 'Разрешената разлика между времето на сървъра на търговеца и e-Gateway сървъра е надвишена',
-21 => 'Трансакцията вече е била изпълнена',
-22 => 'Трансакцията съдържа невалидни данни за аутентикация',
-23 => 'Невалиден контекст на трансакция',
-24 => 'Заявката съдържа стойности за полета, които не могат да бъдат обработени. Например валутата е различна от валутата на терминала.',
-25 => 'Допълнителното потвърждение на трансакцията е отказано от картодържателя',
-26 => 'Невалиден BIN на картата',
-27 => 'Неправилно име на търговеца',
-28 => 'Невалидно допълнително поле (например AD.CUST_BOR_ORDER_ID)',
-29 => 'Невалиден отговор от ACS на издателя на картата',
-30 => 'Трансакцията е отказана като измамна',
-31 => 'Трансакцията е в процес на обрбаотка',
-32 => 'Дублирана отказана трансакция',
-33 => 'Трансакцията е в процес на аутентикация на картодържателя',
-40 => 'Трансакцията е в процес на обработка',
];
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.