├── .gitignore ├── LICENSE.md ├── README.md ├── composer.json ├── docs └── payment-form.png └── src └── Faxi ├── Sisp.php └── samples ├── buy.php ├── callback-buy.php ├── callback-refund.php ├── phone-recharge.php ├── refund.php └── services-payment.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Assis Ferreira 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SISP php 2 | This is implementation of a library to process 3 | SISP [https://www.sisp.cv/](https://www.sisp.cv/) 4 | vinti4 [https://www.vinti4.cv/](https://www.vinti4.cv/) payment in a easy way. 5 | 6 | ## Install 7 | Download the project folder on your project. 8 | Or install it using composer: 9 | ``` 10 | composer require faxi-online/sisp-php:dev-main 11 | ``` 12 | 13 | ## Include in your project 14 | Import the library file; 15 | 16 | ```php 17 | include "../Sisp.php"; 18 | ``` 19 | 20 | Or include the composer autoload 21 | ```php 22 | include "vendor/autoload.php"; 23 | ``` 24 | 25 | ## Create Transaction Object 26 | Create the transaction object from the **Sisp** class. 27 | You can pass three parameters: 28 | - Your POS Id/Identifier 29 | - The respective POS authentication code 30 | - The VBV api URL, and it is set by default as "https://mc.vinti4net.cv/BizMPIOnUsSisp", 31 | remember to define it value in production, without the path "/CardPayment" because 32 | it will be added automatically according the transaction code 33 | 34 | ```php 35 | use Faxi\Sisp; 36 | 37 | $payment = new Sisp( 38 | "90000045", 39 | "kfyhhKJH875ndu44" 40 | ); 41 | 42 | ``` 43 | 44 | ## Generate Transaction id 45 | Generate your transaction id, it can be max of 15 characters, 46 | after a successful payment you should not reuse that id for new transaction. 47 | ```php 48 | // sample to generate id from timestamp 49 | $transaction_id = "T" . date('YmdHms'); 50 | ``` 51 | 52 | ## Generate the HTML buy form 53 | You can generate the HTML form 54 | by calling the **buyForm** method. 55 | It receives three parameters: 56 | - The transaction Id, you will receive it in the transaction callback 57 | - The amount of the transaction 58 | - The callback url, the transaction result will be sent to here 59 | 60 | ```php 61 | $buyForm = $payment->buyForm( 62 | $transaction_id, 63 | 1000, 64 | "http://localhost/sisp-php/src/Faxi/samples/callback-buy.php" 65 | ); 66 | ``` 67 | 68 | ## Put the form on your HTML page 69 | Just put that form in your HTML page 70 | and submit it by calling **document.forms[0].submit();** 71 | 72 | ```html 73 | 74 |
75 |Payment sucessfully for $transaction_id
"; 126 | 127 | // save clearingPeriod and sisp_transaction_id 128 | // you will need them to do refund later 129 | echo "merchantRespCP: " . $clearingPeriod. "
"; 130 | echo "merchantRespTid: " . $sisp_transaction_id . "
"; 131 | 132 | }, 133 | 134 | // error callback 135 | function ($transaction_id, $errorDescription, $errorDetail, $errorAdditionalMessage){ 136 | 137 | echo "Error on transaction $transaction_id
"; 138 | echo "Error: description $errorDescription
"; 139 | echo "Error: detail $errorDetail
"; 140 | echo "Error: additional $errorAdditionalMessage
"; 141 | 142 | }, 143 | 144 | // cancellation callback 145 | function (){ 146 | 147 | echo "Transaction cancelled
"; 148 | 149 | } 150 | 151 | ); 152 | ``` 153 | ## Generate phone recharge HTML form 154 | You can generate the HTML form 155 | by calling the **phoneRechargeForm** method. 156 | It receives five parameters: 157 | - The transaction Id, you will receive it in the transaction callback, it can be max of 15 characters 158 | - The amount of the transaction 159 | - The phone number you want to recharge 160 | - The operator id (it will be provided by SISP) 161 | - The callback url, the transaction result will be sent to here 162 | 163 | ```php 164 | $buyForm = $payment->phoneRechargeForm( 165 | $transaction_id, 166 | 1000, 167 | 9112233, 168 | 2, 169 | "http://localhost/sisp-php/src/Faxi/samples/callback-buy.php" 170 | ); 171 | ``` 172 | 173 | ## Generate service payment HTML form 174 | You can generate the HTML form 175 | by calling the **servicePaymentForm** method. 176 | It receives five parameters: 177 | - The transaction Id, you will receive it in the transaction callback, it can be max of 15 characters 178 | - The amount of the transaction 179 | - The reference number of the bill you want to pay 180 | - The enity id (it will be provided by SISP) 181 | - The callback url, the transaction result will be sent to here 182 | 183 | ```php 184 | $buyForm = $payment->servicePaymentForm( 185 | $transaction_id, 186 | 1000, 187 | "123456789", 188 | "6", 189 | "http://localhost/sisp-php/src/Faxi/samples/callback-buy.php" 190 | ); 191 | ``` 192 | 193 | ## Generate refund HTML form 194 | Call the **refundForm** method. 195 | It receives five parameters: 196 | - The transaction Id, you will receive it in the transaction callback, it can be max of 15 characters, (It must not be the same as the transaction to be refunded) 197 | - The amount to be refunded 198 | - The clearing period number of transaction that is being refunded, it is received in transaction result 199 | - The SISP transaction id received in transaction result 200 | - The callback url, the refund result will be sent to here 201 | ```php 202 | $transaction_id = "T" . date('YmdHms'); 203 | 204 | $refundForm = $payment->refundForm( 205 | $transaction_id, 206 | 1000, 207 | 1765, 208 | 76133, 209 | "http://localhost/sisp-php/src/Faxi/samples/callback-refund.php" 210 | ); 211 | ``` 212 | To handle the refund result you must do the following code. 213 | ```php 214 | $payment->onRefundResult( 215 | 216 | // success callback 217 | function ($transaction_id){ 218 | 219 | echo "Refunded done for $transaction_id
"; 220 | 221 | }, 222 | 223 | // error callback 224 | function ($transaction_id, $errorDescription, $errorDetail, $errorAdditionalMessage){ 225 | 226 | echo "Error on refund for $transaction_id
"; 227 | echo "Error: description $errorDescription
"; 228 | echo "Error: detail $errorDetail
"; 229 | echo "Error: additional $errorAdditionalMessage
"; 230 | 231 | }, 232 | 233 | // cancellation callback 234 | function (){ 235 | 236 | echo "Refund cancelled
"; 237 | 238 | } 239 | 240 | ); 241 | ``` 242 | 243 | ## Internationalization 244 | If you want you can change the language of payment form presented to user, 245 | it supports en and pt. 246 | 247 | ```php 248 | $payment->lang = "pt"; 249 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "faxi-online/sisp-php", 3 | "description": "Implementation of a library to process SISP vinti4 payment in a easy way.", 4 | "authors": [ 5 | { 6 | "name": "Assis Ferreira", 7 | "email": "ferreira.assisruny@gmail.com" 8 | } 9 | ], 10 | "require": {}, 11 | "minimum-stability": "dev", 12 | "autoload": { 13 | "psr-0": { 14 | "Faxi": "src/Faxi" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/payment-form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faxi-online/sisp-php/d01bcb76ea0bb50ff2ecf751e748b71bdcd276a6/docs/payment-form.png -------------------------------------------------------------------------------- /src/Faxi/Sisp.php: -------------------------------------------------------------------------------- 1 | posId = $posId; 26 | $this->posAuthCode = $posAuthCode; 27 | 28 | if(!empty($apiUrl)) 29 | $this->apiBaseUrl = $apiUrl; 30 | } 31 | 32 | function buyForm($transaction_id, $amount, $callbackUrl) 33 | { 34 | $fields = [ 35 | 'transactionCode' => 1, 36 | 'posID' => $this->posId, 37 | 'merchantRef' => $transaction_id, 38 | 'merchantSession' => "S" . date('YmdHms'), 39 | 'amount' => $amount, 40 | 'currency' => 132, 41 | 'is3DSec' => 1, 42 | 'urlMerchantResponse' => $callbackUrl, 43 | 'languageMessages' => $this->lang, 44 | 'timeStamp' => date('Y-m-d H:m:s'), 45 | 'fingerprintversion' => '1', 46 | 'entityCode' => '', 47 | 'referenceNumber' => '' 48 | ]; 49 | 50 | $fields['fingerprint'] = self::GerarFingerPrintEnvio( 51 | $this->posAuthCode, $fields['timeStamp'], $amount, 52 | $fields['merchantRef'], $fields['merchantSession'], $fields['posID'], 53 | $fields['currency'], $fields['transactionCode'], '', '' 54 | ); 55 | 56 | $postUrl = $this->apiBaseUrl . $this->transactionPath . "?FingerPrint=" . urlencode($fields["fingerprint"]) . "&TimeStamp=" . urlencode($fields["timeStamp"]) . "&FingerPrintVersion=" . urlencode($fields["fingerprintversion"]); 57 | 58 | return self::generateHtmlForm($postUrl, $fields); 59 | } 60 | 61 | function phoneRechargeForm($transaction_id, $amount, $phoneNumber, $operatorId, $callbackUrl) 62 | { 63 | $fields = [ 64 | 'transactionCode' => 3, 65 | 'posID' => $this->posId, 66 | 'merchantRef' => $transaction_id, 67 | 'merchantSession' => "S" . date('YmdHms'), 68 | 'amount' => $amount, 69 | 'currency' => 132, 70 | 'is3DSec' => 1, 71 | 'urlMerchantResponse' => $callbackUrl, 72 | 'languageMessages' => $this->lang, 73 | 'timeStamp' => date('Y-m-d H:m:s'), 74 | 'fingerprintversion' => '1', 75 | 'entityCode' => $operatorId, 76 | 'referenceNumber' => $phoneNumber 77 | ]; 78 | 79 | $fields['fingerprint'] = self::GerarFingerPrintEnvio( 80 | $this->posAuthCode, $fields['timeStamp'], $amount, 81 | $fields['merchantRef'], $fields['merchantSession'], $fields['posID'], 82 | $fields['currency'], $fields['transactionCode'], $fields['entityCode'], $fields['referenceNumber'] 83 | ); 84 | 85 | $postUrl = $this->apiBaseUrl . $this->transactionPath . "?FingerPrint=" . urlencode($fields["fingerprint"]) . "&TimeStamp=" . urlencode($fields["timeStamp"]) . "&FingerPrintVersion=" . urlencode($fields["fingerprintversion"]); 86 | 87 | return self::generateHtmlForm($postUrl, $fields); 88 | } 89 | 90 | function servicePaymentForm($transaction_id, $amount, $reference, $entity, $callbackUrl) 91 | { 92 | $fields = [ 93 | 'transactionCode' => 2, 94 | 'posID' => $this->posId, 95 | 'merchantRef' => $transaction_id, 96 | 'merchantSession' => "S" . date('YmdHms'), 97 | 'amount' => $amount, 98 | 'currency' => 132, 99 | 'is3DSec' => 1, 100 | 'urlMerchantResponse' => $callbackUrl, 101 | 'languageMessages' => $this->lang, 102 | 'timeStamp' => date('Y-m-d H:m:s'), 103 | 'fingerprintversion' => '1', 104 | 'entityCode' => $entity, 105 | 'referenceNumber' => $reference 106 | ]; 107 | 108 | $fields['fingerprint'] = self::GerarFingerPrintEnvio( 109 | $this->posAuthCode, $fields['timeStamp'], $amount, 110 | $fields['merchantRef'], $fields['merchantSession'], $fields['posID'], 111 | $fields['currency'], $fields['transactionCode'], $fields['entityCode'], $fields['referenceNumber'] 112 | ); 113 | 114 | $postUrl = $this->apiBaseUrl . $this->transactionPath . "?FingerPrint=" . urlencode($fields["fingerprint"]) . "&TimeStamp=" . urlencode($fields["timeStamp"]) . "&FingerPrintVersion=" . urlencode($fields["fingerprintversion"]); 115 | 116 | return self::generateHtmlForm($postUrl, $fields); 117 | } 118 | 119 | function refundForm($transaction_id, $amount, $clearingPeriod, $sisp_transaction_id, $callbackUrl) 120 | { 121 | $fields = [ 122 | 'transactionCode' => 4, 123 | 'posID' => $this->posId, 124 | 'merchantRef' => $transaction_id, 125 | 'merchantSession' => "S" . date('YmdHms'), 126 | 'amount' => $amount, 127 | 'currency' => 132, 128 | 'is3DSec' => 1, 129 | 'urlMerchantResponse' => $callbackUrl, 130 | 'languageMessages' => $this->lang, 131 | 'timeStamp' => date('Y-m-d H:m:s'), 132 | 'fingerprintversion' => '1', 133 | 'entityCode' => '', 134 | 'referenceNumber' => '', 135 | 'reversal' => 'R', 136 | 'clearingPeriod' => $clearingPeriod, 137 | 'transactionID' => $sisp_transaction_id, 138 | ]; 139 | 140 | $fields['fingerprint'] = self::GerarFingerPrintEnvio( 141 | $this->posAuthCode, $fields['timeStamp'], $amount, 142 | $fields['merchantRef'], $fields['merchantSession'], $fields['posID'], 143 | $fields['currency'], $fields['transactionCode'], '', '' 144 | ); 145 | 146 | $postUrl = $this->apiBaseUrl . $this->transactionPath . "?FingerPrint=" . urlencode($fields["fingerprint"]) . "&TimeStamp=" . urlencode($fields["timeStamp"]) . "&FingerPrintVersion=" . urlencode($fields["fingerprintversion"]); 147 | 148 | return self::generateHtmlForm($postUrl, $fields); 149 | } 150 | 151 | function onTransactionResult($successCallback, $errorCallback = null, $cancelledCallback = null) 152 | { 153 | $successMessageType = array('8', 'P', 'M'); 154 | 155 | /* 156 | 8 - buy 157 | P - payment service 158 | M - phone recharge 159 | */ 160 | 161 | if(isset($_POST)) 162 | { 163 | if(isset($_POST["messageType"]) && in_array($_POST["messageType"], $successMessageType)) 164 | { 165 | $fingerPrintCalculado = self::GerarFingerPrintRespostaBemSucedida( 166 | $this->posAuthCode, $_POST["messageType"] , $_POST["merchantRespCP"], 167 | $_POST["merchantRespTid"] , $_POST["merchantRespMerchantRef"] , $_POST["merchantRespMerchantSession"] , 168 | $_POST["merchantRespPurchaseAmount"] , $_POST["merchantRespMessageID"] , $_POST["merchantRespPan"] , 169 | $_POST["merchantResp"] , $_POST["merchantRespTimeStamp"] , $_POST["merchantRespReferenceNumber"] , 170 | $_POST["merchantRespEntityCode"] , $_POST["merchantRespClientReceipt"] , trim($_POST["merchantRespAdditionalErrorMessage"]) , 171 | $_POST["merchantRespReloadCode"] 172 | ); 173 | 174 | if($_POST["resultFingerPrint"] == $fingerPrintCalculado) 175 | { 176 | $successCallback($_POST["merchantRespMerchantRef"], $_POST["merchantRespCP"], $_POST["merchantRespTid"]); 177 | } 178 | else 179 | { 180 | $errorCallback($_POST["merchantRespMerchantRef"], "resultFingerPrint dont match", "", ""); 181 | } 182 | 183 | } 184 | else if(isset($_POST["messageType"]) && $_POST["messageType"] == "6") 185 | { 186 | $errorCallback($_POST["merchantRespMerchantRef"], $_POST["merchantRespErrorDescription"], $_POST["merchantRespErrorDetail"], $_POST["merchantRespAdditionalErrorMessage"]); 187 | } 188 | else if(isset($_POST["UserCancelled"]) && $_POST["UserCancelled"] == "true") 189 | { 190 | $cancelledCallback(); 191 | } 192 | } 193 | 194 | } 195 | 196 | function onRefundResult($successCallback, $errorCallback = null, $cancelledCallback = null) 197 | { 198 | $successMessageType = array('10'); 199 | 200 | /* 201 | 10 - refund 202 | */ 203 | 204 | if(isset($_POST)) 205 | { 206 | if(isset($_POST["messageType"]) && in_array($_POST["messageType"], $successMessageType)) 207 | { 208 | $fingerPrintCalculado = self::GerarFingerPrintRespostaBemSucedida( 209 | $this->posAuthCode, $_POST["messageType"] , $_POST["merchantRespCP"], 210 | $_POST["merchantRespTid"] , $_POST["merchantRespMerchantRef"] , $_POST["merchantRespMerchantSession"] , 211 | $_POST["merchantRespPurchaseAmount"] , $_POST["merchantRespMessageID"] , $_POST["merchantRespPan"] , 212 | $_POST["merchantResp"] , $_POST["merchantRespTimeStamp"] , $_POST["merchantRespReferenceNumber"] , 213 | $_POST["merchantRespEntityCode"] , $_POST["merchantRespClientReceipt"] , trim($_POST["merchantRespAdditionalErrorMessage"]) , 214 | $_POST["merchantRespReloadCode"] 215 | ); 216 | 217 | if($_POST["resultFingerPrint"] == $fingerPrintCalculado) 218 | { 219 | $successCallback($_POST["merchantRespMerchantRef"], $_POST["merchantRespCP"], $_POST["merchantRespTid"]); 220 | } 221 | else 222 | { 223 | $errorCallback($_POST["merchantRespMerchantRef"], "resultFingerPrint dont match", "", ""); 224 | } 225 | 226 | } 227 | else if(isset($_POST["messageType"]) && $_POST["messageType"] == "6") 228 | { 229 | $errorCallback($_POST["merchantRespMerchantRef"], $_POST["merchantRespErrorDescription"], $_POST["merchantRespErrorDetail"], $_POST["merchantRespAdditionalErrorMessage"]); 230 | } 231 | else if(isset($_POST["UserCancelled"]) && $_POST["UserCancelled"] == "true") 232 | { 233 | $cancelledCallback(); 234 | } 235 | } 236 | 237 | } 238 | 239 | static function generateHtmlForm($action_url, $fields) 240 | { 241 | $form = ""; 248 | 249 | return $form; 250 | } 251 | 252 | static function GerarFingerPrintEnvio 253 | ( 254 | $posAutCode, $timestamp, $amount, 255 | $merchantRef, $merchantSession, $posID, 256 | $currency, $transactionCode, $entityCode, 257 | $referenceNumber 258 | ) 259 | { 260 | // REMOVER POSSIVEIS ZEROS A ESQUERDA 261 | if(!empty($entityCode)) 262 | $entityCode = (int)$entityCode; 263 | 264 | if(!empty($referenceNumber)) 265 | $referenceNumber = (int)$referenceNumber; 266 | 267 | // CONCATENAR OS DADOS PARA O HASH FINAL 268 | $toHash = base64_encode(hash('sha512', $posAutCode, true)) . $timestamp . ((int)((float)$amount * 1000)) 269 | . $merchantRef . $merchantSession . $posID 270 | . $currency . $transactionCode . $entityCode . $referenceNumber 271 | ; 272 | 273 | return base64_encode(hash('sha512', $toHash, true)); 274 | } 275 | 276 | static function GerarFingerPrintRespostaBemSucedida 277 | ( 278 | $posAutCode, $messageType, $clearingPeriod, 279 | $transactionID, $merchantReference, $merchantSession, 280 | $amount, $messageID, $pan, 281 | $merchantResponse, $timestamp, $reference, 282 | $entity, $clientReceipt, $additionalErrorMessage, 283 | $reloadCode 284 | ) 285 | { 286 | // REMOVER POSSIVEIS ZEROS A ESQUERDA 287 | if(!empty($reference)) 288 | $reference = (int)$reference; 289 | 290 | if(!empty($entity)) 291 | $entity = (int)$entity; 292 | 293 | // EFETUAR O CALCULO CONFORME A DOCUMENTACAO 294 | $toHash = base64_encode(hash('sha512', $posAutCode, true)) . $messageType . $clearingPeriod . $transactionID 295 | . $merchantReference . $merchantSession . 296 | ((int)((float)$amount * 1000)) . $messageID . $pan . 297 | $merchantResponse . $timestamp . $reference . 298 | $entity . $clientReceipt . $additionalErrorMessage . 299 | $reloadCode 300 | ; 301 | 302 | return base64_encode(hash('sha512', $toHash, true)); 303 | } 304 | 305 | } 306 | 307 | ?> -------------------------------------------------------------------------------- /src/Faxi/samples/buy.php: -------------------------------------------------------------------------------- 1 | lang = "pt"; 9 | 10 | // generate your transaction id 11 | // it can be max of 15 characters 12 | // after a successful payment you should not reuse that id for new transaction 13 | $transaction_id = "T" . date('YmdHms'); 14 | 15 | $buyForm = $payment->buyForm( 16 | $transaction_id, 17 | 1000, 18 | "http://localhost/sisp-php/src/Faxi/samples/callback-buy.php" 19 | ); 20 | 21 | //echo($buyForm); 22 | 23 | ?> 24 | 25 | 26 | 27 |Payment sucessfully for $transaction_id
"; 15 | 16 | echo "merchantRespCP: " . $clearingPeriod. "
"; 17 | echo "merchantRespTid: " . $sisp_transaction_id . "
"; 18 | 19 | }, 20 | 21 | // error callback 22 | function ($transaction_id, $errorDescription, $errorDetail, $errorAdditionalMessage){ 23 | 24 | echo "Error on transaction $transaction_id
"; 25 | echo "Error: description $errorDescription
"; 26 | echo "Error: detail $errorDetail
"; 27 | echo "Error: additional $errorAdditionalMessage
"; 28 | 29 | }, 30 | 31 | // cancellation callback 32 | function (){ 33 | 34 | echo "Transaction cancelled
"; 35 | 36 | } 37 | 38 | ); 39 | 40 | ?> 41 | 42 | -------------------------------------------------------------------------------- /src/Faxi/samples/callback-refund.php: -------------------------------------------------------------------------------- 1 | onRefundResult( 10 | 11 | // success callback 12 | function ($transaction_id){ 13 | 14 | echo "Refunded done for $transaction_id
"; 15 | 16 | }, 17 | 18 | // error callback 19 | function ($transaction_id, $errorDescription, $errorDetail, $errorAdditionalMessage){ 20 | 21 | echo "Error on refund for $transaction_id
"; 22 | echo "Error: description $errorDescription
"; 23 | echo "Error: detail $errorDetail
"; 24 | echo "Error: additional $errorAdditionalMessage
"; 25 | 26 | }, 27 | 28 | // cancellation callback 29 | function (){ 30 | 31 | echo "Refund cancelled
"; 32 | 33 | } 34 | 35 | ); 36 | 37 | ?> 38 | 39 | -------------------------------------------------------------------------------- /src/Faxi/samples/phone-recharge.php: -------------------------------------------------------------------------------- 1 | phoneRechargeForm( 11 | $transaction_id, 12 | 1000, 13 | 9112233, 14 | 2, 15 | "http://localhost/sisp-php/src/Faxi/samples/callback-buy.php" 16 | ); 17 | 18 | ?> 19 | 20 | 21 | 22 |