├── .gitignore ├── src ├── ApiAuthentication.php ├── Consumer.php ├── RSAService │ ├── RSAServiceContract.php │ ├── SeclibRSAService.php │ └── OpenSSL_RSAService.php ├── RSAServiceFactory.php ├── DailyClosure.php ├── PreAuthorizedPaymentToken.php ├── Payment.php ├── Api.php └── Request.php ├── examples ├── get-payments.php ├── get-consumer.php ├── get-payment.php ├── auth-with-token.php ├── get-daily-closure.php ├── create-payment.php ├── get-pre-authorized-payment-token.php ├── create-pre-authorized-payment-token.php ├── update-payment.php └── update-pre-authorized-payment-token.php ├── composer.json ├── init.php ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /examples/authentication.json 3 | composer.lock 4 | .idea 5 | -------------------------------------------------------------------------------- /src/ApiAuthentication.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $payments = \SatispayGBusiness\Payment::all(); 14 | 15 | var_dump($payments); 16 | -------------------------------------------------------------------------------- /examples/get-consumer.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $consumer = \SatispayGBusiness\Consumer::get('+390000000000'); 14 | 15 | var_dump($consumer); 16 | -------------------------------------------------------------------------------- /examples/get-payment.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $payment = \SatispayGBusiness\Payment::get('5f11eb3d-e442-441c-af7c-7c1d707e1f4e'); 14 | 15 | var_dump($payment); 16 | -------------------------------------------------------------------------------- /examples/auth-with-token.php: -------------------------------------------------------------------------------- 1 | publicKey; 10 | $privateKey = $authentication->privateKey; 11 | $keyId = $authentication->keyId; 12 | 13 | file_put_contents(__DIR__ . '/authentication.json', json_encode([ 14 | 'public_key' => $publicKey, 15 | 'private_key' => $privateKey, 16 | 'key_id' => $keyId 17 | ], JSON_PRETTY_PRINT)); 18 | -------------------------------------------------------------------------------- /examples/get-daily-closure.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $dailyClosure = \SatispayGBusiness\DailyClosure::get(null, [ 14 | 'generate_pdf' => 'true' 15 | ]); 16 | 17 | var_dump($dailyClosure); 18 | -------------------------------------------------------------------------------- /examples/create-payment.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $payment = \SatispayGBusiness\Payment::create([ 14 | 'flow' => 'MATCH_CODE', 15 | 'amount_unit' => 199, 16 | 'currency' => 'EUR' 17 | ]); 18 | 19 | var_dump($payment); 20 | -------------------------------------------------------------------------------- /examples/get-pre-authorized-payment-token.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $preAuthorizedPaymentToken = \SatispayGBusiness\PreAuthorizedPaymentToken::get('8de0732f-8626-407a-a05f-135fc441df6e'); 14 | 15 | var_dump($preAuthorizedPaymentToken); 16 | -------------------------------------------------------------------------------- /examples/create-pre-authorized-payment-token.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $preAuthorizedPaymentToken = \SatispayGBusiness\PreAuthorizedPaymentToken::create([ 14 | 'reason' => 'Monthly Payments' 15 | ]); 16 | 17 | var_dump($preAuthorizedPaymentToken); 18 | -------------------------------------------------------------------------------- /src/Consumer.php: -------------------------------------------------------------------------------- 1 | value] 13 | */ 14 | public static function get($phoneNumber, $headers = []) 15 | { 16 | return 17 | Request::get( 18 | self::$apiPath . '/' . $phoneNumber, 19 | [ 20 | 'headers' => $headers, 21 | 'sign' => true 22 | ] 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "satispay/gbusiness-api-php-sdk", 3 | "description": "Satispay GBusiness API PHP SDK", 4 | "license": "MIT", 5 | "keywords": [ 6 | "satispay", 7 | "gbusiness", 8 | "api", 9 | "php", 10 | "sdk" 11 | ], 12 | "homepage": "https://www.satispay.com", 13 | "authors": [ 14 | { 15 | "name": "Satispay", 16 | "homepage": "https://www.satispay.com" 17 | } 18 | ], 19 | "require": { 20 | "phpseclib/phpseclib": "^2", 21 | "php": ">=5.4.0", 22 | "ext-curl": "*", 23 | "ext-json": "*", 24 | "ext-mbstring": "*" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "SatispayGBusiness\\": "src/" 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /init.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $payment = \SatispayGBusiness\Payment::create([ 14 | 'flow' => 'MATCH_CODE', 15 | 'amount_unit' => 199, 16 | 'currency' => 'EUR' 17 | ]); 18 | 19 | var_dump($payment); 20 | 21 | $updatePayment = \SatispayGBusiness\Payment::update($payment->id, [ 22 | 'action' => 'CANCEL' 23 | ]); 24 | 25 | var_dump($updatePayment); 26 | -------------------------------------------------------------------------------- /src/RSAService/RSAServiceContract.php: -------------------------------------------------------------------------------- 1 | public_key); 10 | \SatispayGBusiness\Api::setPrivateKey($authData->private_key); 11 | \SatispayGBusiness\Api::setKeyId($authData->key_id); 12 | 13 | $preAuthorizedPaymentToken = \SatispayGBusiness\PreAuthorizedPaymentToken::create([ 14 | 'reason' => 'Monthly Payments' 15 | ]); 16 | 17 | var_dump($preAuthorizedPaymentToken); 18 | 19 | $updatePreAuthorizedPaymentToken = \SatispayGBusiness\PreAuthorizedPaymentToken::update($preAuthorizedPaymentToken->id, [ 20 | 'status' => 'CANCELED' 21 | ]); 22 | 23 | var_dump($updatePreAuthorizedPaymentToken); 24 | -------------------------------------------------------------------------------- /src/RSAServiceFactory.php: -------------------------------------------------------------------------------- 1 | $headers, 33 | 'sign' => true 34 | ] 35 | ); 36 | } 37 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-present Satispay 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. 22 | -------------------------------------------------------------------------------- /src/PreAuthorizedPaymentToken.php: -------------------------------------------------------------------------------- 1 | value] 13 | */ 14 | public static function create($body, $headers = []) 15 | { 16 | return 17 | Request::post( 18 | self::$apiPath, 19 | [ 20 | 'headers' => $headers, 21 | 'body' => $body, 22 | 'sign' => true 23 | ] 24 | ); 25 | } 26 | 27 | /** 28 | * Get a pre authorized payment token. 29 | * 30 | * @param string $id 31 | */ 32 | public static function get($id, $headers = []) 33 | { 34 | return 35 | Request::get( 36 | self::$apiPath . '/' . $id, 37 | [ 38 | 'headers' => $headers, 39 | 'sign' => true 40 | ] 41 | ); 42 | } 43 | 44 | /** 45 | * Update a pre authorized payment token. 46 | * 47 | * @param string $id 48 | * @param array $body 49 | * @param array $headers The format is: [header => value] 50 | */ 51 | public static function update($id, $body, $headers = []) 52 | { 53 | return 54 | Request::put( 55 | self::$apiPath. '/' . $id, 56 | [ 57 | 'headers' => $headers, 58 | 'body' => $body, 59 | 'sign' => true 60 | ] 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/RSAService/SeclibRSAService.php: -------------------------------------------------------------------------------- 1 | setPublicKeyFormat(\phpseclib\Crypt\RSA::PUBLIC_FORMAT_PKCS1); 31 | $rsa->setPrivateKeyFormat(\phpseclib\Crypt\RSA::PRIVATE_FORMAT_PKCS1); 32 | $rsa->setEncryptionMode(\phpseclib\Crypt\RSA::ENCRYPTION_PKCS1); 33 | 34 | $privateKey = $rsa->createKey(2048); 35 | 36 | return ['private_key' => $privateKey['privatekey'], 'public_key' => $privateKey['publickey']]; 37 | } catch (Exception $e) { 38 | throw new Exception('An unexpected error occurred: ' . $e->getMessage()); 39 | } 40 | } 41 | 42 | /** 43 | * @inheritdoc 44 | */ 45 | public static function sign($privateKey, $message) 46 | { 47 | try { 48 | $rsa = new \phpseclib\Crypt\RSA(); 49 | $rsa->loadKey($privateKey, \phpseclib\Crypt\RSA::PRIVATE_FORMAT_PKCS8); 50 | $rsa->setHash('sha256'); 51 | $rsa->setSignatureMode(\phpseclib\Crypt\RSA::SIGNATURE_PKCS1); 52 | 53 | return $rsa->sign($message); 54 | } catch (Exception $e) { 55 | throw new Exception('Signing failed: ' . $e->getMessage()); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/RSAService/OpenSSL_RSAService.php: -------------------------------------------------------------------------------- 1 | 'sha256', 29 | 'private_key_bits' => 2048, 30 | ]); 31 | 32 | if ($pkeyResource === false) { 33 | throw new Exception('Failed to generate private key: ' . openssl_error_string()); 34 | } 35 | 36 | $privateKeyExported = openssl_pkey_export($pkeyResource, $newPrivateKey); 37 | 38 | if ($privateKeyExported === false) { 39 | throw new Exception('Failed to export private key: ' . openssl_error_string()); 40 | } 41 | 42 | $pkeyResourceDetails = openssl_pkey_get_details($pkeyResource); 43 | 44 | if ($pkeyResourceDetails === false) { 45 | throw new Exception('Failed to get key details: ' . openssl_error_string()); 46 | } 47 | 48 | $newPublicKey = $pkeyResourceDetails['key']; 49 | 50 | return ['private_key' => $newPrivateKey, 'public_key' => $newPublicKey]; 51 | } 52 | 53 | /** 54 | * @inheritdoc 55 | */ 56 | public static function sign($privateKey, $message) 57 | { 58 | $privateKeyResource = openssl_pkey_get_private($privateKey); 59 | 60 | if (!$privateKeyResource) { 61 | throw new Exception('Failed to get private key: ' . openssl_error_string()); 62 | } 63 | 64 | $signed = ''; 65 | 66 | if (!openssl_sign($message, $signed, $privateKeyResource, OPENSSL_ALGO_SHA256)) { 67 | throw new Exception('Signing failed: ' . openssl_error_string()); 68 | } 69 | 70 | return $signed; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Payment.php: -------------------------------------------------------------------------------- 1 | value] 13 | */ 14 | public static function create($body, $headers = []) 15 | { 16 | return 17 | Request::post( 18 | self::$apiPath, 19 | [ 20 | 'headers' => $headers, 21 | 'body' => $body, 22 | 'sign' => true 23 | ] 24 | ); 25 | } 26 | 27 | /** 28 | * Get payment by id. 29 | * 30 | * @param string $id 31 | * @param array $headers The format is: [header => value] 32 | */ 33 | public static function get($id, $headers = []) 34 | { 35 | return 36 | Request::get( 37 | self::$apiPath . '/' . $id, 38 | [ 39 | 'headers' => $headers, 40 | 'sign' => true 41 | ] 42 | ); 43 | } 44 | 45 | /** 46 | * Get the payments list. 47 | * 48 | * @param array $options 49 | * @param array $headers The format is: [header => value] 50 | */ 51 | public static function all($query = [], $headers = []) 52 | { 53 | $path = self::$apiPath; 54 | 55 | if (!empty($query)) { 56 | $path .= '?' . http_build_query($query); 57 | } 58 | 59 | return 60 | Request::get( 61 | $path, 62 | [ 63 | 'headers' => $headers, 64 | 'sign' => true 65 | ] 66 | ); 67 | } 68 | 69 | /** 70 | * Update a payment. 71 | * 72 | * @param string $id 73 | * @param array $body 74 | * @param array $headers The format is: [header => value] 75 | */ 76 | public static function update($id, $body, $headers = []) 77 | { 78 | return 79 | Request::put( 80 | self::$apiPath. '/' . $id, 81 | [ 82 | 'headers' => $headers, 83 | 'body' => $body, 84 | 'sign' => true 85 | ] 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Satispay GBusiness API PHP SDK 2 | 3 | [![Packagist Version](https://img.shields.io/packagist/v/satispay/gbusiness-api-php-sdk.svg?style=flat-square)](https://packagist.org/packages/satispay/gbusiness-api-php-sdk) 4 | [![Packagist Downloads](https://img.shields.io/packagist/dt/satispay/gbusiness-api-php-sdk.svg?style=flat-square)](https://packagist.org/packages/satispay/gbusiness-api-php-sdk) 5 | 6 | ## Installation 7 | 8 | Run the following command: 9 | 10 | ```bash 11 | composer require satispay/gbusiness-api-php-sdk 12 | ``` 13 | 14 | If you do not wish to use Composer, import the `init.php` file. 15 | 16 | ```php 17 | require_once("/path/init.php"); 18 | ``` 19 | 20 | ## Documentation 21 | 22 | https://developers.satispay.com 23 | 24 | ## Authenticate with RSA Signature 25 | 26 | Sign in to your [Dashboard](https://business.satispay.com) at [business.satispay.com](https://business.satispay.com), click "Negozi Online" or "Negozi Fisici", and then click on "Genera un token di attivazione" to generate an activation token. 27 | 28 | Use the activation token with the `authenticateWithToken` function to generate and exchange a pair of RSA keys. 29 | 30 | Save the keys in your database or in a **safe place** not accesibile from your website. 31 | 32 | ```php 33 | // Authenticate and generate the keys 34 | $authentication = \SatispayGBusiness\Api::authenticateWithToken("XXXXXX"); 35 | 36 | // Export keys 37 | $publicKey = $authentication->publicKey; 38 | $privateKey = $authentication->privateKey; 39 | $keyId = $authentication->keyId; 40 | ``` 41 | 42 | Reuse the keys after authentication. 43 | 44 | ```php 45 | // Keys variables 46 | $publicKey = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhk..."; 47 | $privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBg..."; 48 | $keyId = "ldg9sbq283og7ua1abpj989kbbm2g60us6f18c1sciq..."; 49 | 50 | // Set keys 51 | \SatispayGBusiness\Api::setPublicKey($publicKey); 52 | \SatispayGBusiness\Api::setPrivateKey($privateKey); 53 | \SatispayGBusiness\Api::setKeyId($keyId); 54 | ``` 55 | 56 | ## Enable Sandbox 57 | 58 | To enable sandbox use `setSandbox` function. 59 | ```php 60 | \SatispayGBusiness\Api::setSandbox(true); 61 | ``` 62 | 63 | ## Changelog 64 | 65 | ### 1.4.0 66 | 67 | - Added custom header support in every HTTP call. 68 | - Improve code formatting and documentation. 69 | - Added RSA generation fallback with seclib (available via Composer only). 70 | 71 | ### 1.3.0 72 | 73 | - Added `\SatispayGBusiness\Api::getPlatformHeader()` method. 74 | - Added `\SatispayGBusiness\Api::setPlatformHeader()` method. 75 | - Added `\SatispayGBusiness\Api::getTrackingHeader()` method. 76 | - Added `\SatispayGBusiness\Api::setTrackingHeader()` method. 77 | - Added `\SatispayGBusiness\Request::HEADER_OS` constant for `x-satispay-os` request header. 78 | - Added `\SatispayGBusiness\Request::HEADER_OS_VERSION` constant for `x-satispay-osv` request headers. 79 | - Added `\SatispayGBusiness\Request::HEADER_APP_VERSION` constant for `x-satispay-appv` request headers 80 | - Added `\SatispayGBusiness\Request::HEADER_APP_NAME` constant for `x-satispay-appn` request headers. 81 | - Added `\SatispayGBusiness\Request::HEADER_DEVICE_TYPE` constant for `x-satispay-devicetype` request headers. 82 | - Added `\SatispayGBusiness\Request::HEADER_TRACKING_CODE` constant for `x-satispay-tracking-code` request headers. 83 | 84 | - Changed in `\SatispayGBusiness\Request` header key from `X-Satispay-Platformv` to `x-satispay-osv` 85 | - Changed in `\SatispayGBusiness\Request` header key from `X-Satispay-Plugin-Version` to `x-satispay-appv` 86 | - Changed in `\SatispayGBusiness\Request` header key from `X-Satispay-Plugin-Name` to `x-satispay-appn` 87 | - Changed in `\SatispayGBusiness\Request` header key from `X-Satispay-Type` to `x-satispay-devicetype` 88 | 89 | ### 1.2.1 90 | 91 | - Added `\SatispayGBusiness\ApiAuthentication` class. 92 | - Performed code refactoring to adhere to PSR2 Coding Standards 93 | 94 | ### 1.2.0 95 | 96 | - Added `\SatispayGBusiness\PreAuthorizedPaymentToken` class. 97 | 98 | ### 1.1.1 99 | 100 | - Fixed composer file version 101 | 102 | ### 1.1.0 103 | 104 | - Removed `\SatispayGBusiness\Api::testAuthentication()` method. 105 | - Removed `\SatispayGBusiness\Api::getSecurityBearer()` method. 106 | - Removed `\SatispayGBusiness\Api::setSecurityBearer()` method. 107 | 108 | - Added `\SatispayGBusiness\Api::getPlatformVersionHeader()` method. 109 | - Added `\SatispayGBusiness\Api::setPlatformVersionHeader()` method. 110 | 111 | - Added `\SatispayGBusiness\Api::getPluginVersionHeader()` method. 112 | - Added `\SatispayGBusiness\Api::setPluginVersionHeader()` method. 113 | 114 | - Added `\SatispayGBusiness\Api::getPluginNameHeader()` method. 115 | - Added `\SatispayGBusiness\Api::setPluginNameHeader()` method. 116 | 117 | - Added `\SatispayGBusiness\Api::getTypeHeader()` method. 118 | - Added `\SatispayGBusiness\Api::setTypeHeader()` method. 119 | -------------------------------------------------------------------------------- /src/Api.php: -------------------------------------------------------------------------------- 1 | [ 36 | 'public_key' => $generatedPublicKey, 37 | 'token' => $token 38 | ] 39 | ] 40 | ); 41 | 42 | self::$privateKey = $generatedPrivateKey; 43 | self::$publicKey = $generatedPublicKey; 44 | self::$keyId = $requestResult->key_id; 45 | 46 | $returnClass = new ApiAuthentication(); 47 | $returnClass->privateKey = $generatedPrivateKey; 48 | $returnClass->publicKey = $generatedPublicKey; 49 | $returnClass->keyId = $requestResult->key_id; 50 | 51 | return $returnClass; 52 | } 53 | 54 | /** 55 | * Get the current environment. 56 | * 57 | * @return string 58 | */ 59 | public static function getEnv() 60 | { 61 | return self::$env; 62 | } 63 | 64 | /** 65 | * Set the current environment. 66 | * 67 | * @param string $value 68 | */ 69 | public static function setEnv($value) 70 | { 71 | self::$env = $value; 72 | 73 | if ($value == 'production') { 74 | self::$authservicesUrl = 'https://authservices.satispay.com'; 75 | } else { 76 | self::$authservicesUrl = 'https://' . $value . '.authservices.satispay.com'; 77 | } 78 | } 79 | 80 | /** 81 | * Get platform version header. 82 | * 83 | * @return string 84 | */ 85 | public static function getPlatformVersionHeader() 86 | { 87 | return self::$platformVersionHeader; 88 | } 89 | 90 | /** 91 | * Set platform version header. 92 | * 93 | * @param string $value 94 | */ 95 | public static function setPlatformVersionHeader($value) 96 | { 97 | self::$platformVersionHeader = $value; 98 | } 99 | 100 | /** 101 | * Get platform header. 102 | * 103 | * @return string 104 | */ 105 | public static function getPlatformHeader() 106 | { 107 | return self::$platformHeader; 108 | } 109 | 110 | /** 111 | * Set platform header. 112 | * 113 | * @param string $value 114 | */ 115 | public static function setPlatformHeader($value) 116 | { 117 | self::$platformHeader = $value; 118 | } 119 | 120 | /** 121 | * Get plugin version header. 122 | * 123 | * @return string 124 | */ 125 | public static function getPluginVersionHeader() 126 | { 127 | return self::$pluginVersionHeader; 128 | } 129 | 130 | /** 131 | * Set plugin version header. 132 | * 133 | * @param string $value 134 | */ 135 | public static function setPluginVersionHeader($value) 136 | { 137 | self::$pluginVersionHeader = $value; 138 | } 139 | 140 | /** 141 | * Get plugin name header 142 | * @return string 143 | */ 144 | public static function getPluginNameHeader() 145 | { 146 | return self::$pluginNameHeader; 147 | } 148 | 149 | /** 150 | * Set plugin name header. 151 | * 152 | * @param string $value 153 | */ 154 | public static function setPluginNameHeader($value) 155 | { 156 | self::$pluginNameHeader = $value; 157 | } 158 | 159 | /** 160 | * Get type header. 161 | * 162 | * @return string 163 | */ 164 | public static function getTypeHeader() 165 | { 166 | return self::$typeHeader; 167 | } 168 | 169 | /** 170 | * Set type header. 171 | * 172 | * @param string $value 173 | */ 174 | public static function setTypeHeader($value) 175 | { 176 | self::$typeHeader = $value; 177 | } 178 | 179 | /** 180 | * Get tracking header. 181 | * 182 | * @return string 183 | */ 184 | public static function getTrackingHeader() 185 | { 186 | return self::$trackingHeader; 187 | } 188 | 189 | /** 190 | * Set tracking header. 191 | * 192 | * @param string $value 193 | */ 194 | public static function setTrackingHeader($value) 195 | { 196 | self::$trackingHeader = $value; 197 | } 198 | 199 | /** 200 | * Get private key. 201 | * 202 | * @return string 203 | */ 204 | public static function getPrivateKey() 205 | { 206 | return self::$privateKey; 207 | } 208 | 209 | /** 210 | * Set the private key. 211 | * 212 | * @param string $value 213 | */ 214 | public static function setPrivateKey($value) 215 | { 216 | self::$privateKey = $value; 217 | } 218 | 219 | /** 220 | * Get public key. 221 | * 222 | * @return string 223 | */ 224 | public static function getPublicKey() 225 | { 226 | return self::$publicKey; 227 | } 228 | 229 | /** 230 | * Set the public key. 231 | * 232 | * @param string $value 233 | */ 234 | public static function setPublicKey($value) 235 | { 236 | self::$publicKey = $value; 237 | } 238 | 239 | /** 240 | * Get the current KeyId. 241 | * 242 | * @return string 243 | */ 244 | public static function getKeyId() 245 | { 246 | return self::$keyId; 247 | } 248 | 249 | /** 250 | * Set the KeyId. 251 | * 252 | * @param string $value 253 | */ 254 | public static function setKeyId($value) 255 | { 256 | self::$keyId = $value; 257 | } 258 | 259 | /** 260 | * Get version. 261 | * 262 | * @return string 263 | */ 264 | public static function getVersion() 265 | { 266 | return self::$version; 267 | } 268 | 269 | /** 270 | * Get authservices url. 271 | * 272 | * @return string 273 | */ 274 | public static function getAuthservicesUrl() 275 | { 276 | return self::$authservicesUrl; 277 | } 278 | 279 | /** 280 | * Is sandbox enabled? 281 | * 282 | * @return boolean 283 | */ 284 | public static function getSandbox() 285 | { 286 | return self::$env === 'staging'; 287 | } 288 | 289 | /** 290 | * Enable or disable sandbox. 291 | * 292 | * @param boolean $value 293 | */ 294 | public static function setSandbox($value = true) 295 | { 296 | self::setEnv((bool) $value === true ? 'staging' : 'production'); 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /src/Request.php: -------------------------------------------------------------------------------- 1 | $path, 25 | 'method' => 'GET' 26 | ]; 27 | 28 | if (!empty($options['headers'])) { 29 | $requestOptions['headers'] = $options['headers']; 30 | } 31 | 32 | if (!empty($options['sign'])) { 33 | $requestOptions['sign'] = $options['sign']; 34 | } 35 | 36 | return self::request($requestOptions); 37 | } 38 | 39 | /** 40 | * Make a POST request. 41 | * 42 | * @param string $path 43 | * @param array $options 44 | */ 45 | public static function post($path, $options = []) 46 | { 47 | $requestOptions = [ 48 | 'path' => $path, 49 | 'method' => 'POST', 50 | 'body' => $options['body'] 51 | ]; 52 | 53 | if (!empty($options['headers'])) { 54 | $requestOptions['headers'] = $options['headers']; 55 | } 56 | 57 | if (!empty($options['sign'])) { 58 | $requestOptions['sign'] = $options['sign']; 59 | } 60 | 61 | return self::request($requestOptions); 62 | } 63 | 64 | /** 65 | * Make a PUT request. 66 | * 67 | * @param string $path 68 | * @param array $options 69 | */ 70 | public static function put($path, $options = []) 71 | { 72 | $requestOptions = [ 73 | 'path' => $path, 74 | 'method' => 'PUT', 75 | 'body' => $options['body'] 76 | ]; 77 | 78 | if (!empty($options['headers'])) { 79 | $requestOptions['headers'] = $options['headers']; 80 | } 81 | 82 | if (!empty($options['sign'])) { 83 | $requestOptions['sign'] = $options['sign']; 84 | } 85 | 86 | return self::request($requestOptions); 87 | } 88 | 89 | /** 90 | * Make a PATCH request. 91 | * 92 | * @param string $path 93 | * @param array $options 94 | */ 95 | public static function patch($path, $options = []) 96 | { 97 | $requestOptions = [ 98 | 'path' => $path, 99 | 'method' => 'PATCH', 100 | 'body' => $options['body'] 101 | ]; 102 | 103 | if (!empty($options['headers'])) { 104 | $requestOptions['headers'] = $options['headers']; 105 | } 106 | 107 | if (!empty($options['sign'])) { 108 | $requestOptions['sign'] = $options['sign']; 109 | } 110 | 111 | return self::request($requestOptions); 112 | } 113 | 114 | /** 115 | * Sign the request. 116 | * 117 | * @param array $options 118 | */ 119 | private static function signRequest($options = []) 120 | { 121 | $headers = []; 122 | $authorizationHeader = ''; 123 | 124 | $privateKey = Api::getPrivateKey(); 125 | $keyId = Api::getKeyId(); 126 | 127 | if (!empty($privateKey) && !empty($keyId)) { 128 | $date = date('r'); 129 | $headers['Date'] = $date; 130 | 131 | $signature = '(request-target): ' . strtolower($options['method']) . ' ' . $options['path'] . "\n"; 132 | $signature .= 'host: ' . str_replace('https://', '', Api::getAuthservicesUrl()) . "\n"; 133 | 134 | $digest = base64_encode(hash('sha256', $options['body'], true)); 135 | $headers['Digest'] = 'SHA-256=' . $digest; 136 | 137 | if (!empty($options['body'])) { 138 | $signature .= "content-type: application/json\n"; 139 | $signature .= 'content-length: ' . strlen($options['body']) . "\n"; 140 | } 141 | 142 | $signature .= "digest: SHA-256=$digest\n"; 143 | $signature .= "date: $date"; 144 | 145 | $RSAService = RSAServiceFactory::get(); 146 | $signedSignature = $RSAService::sign($privateKey, $signature); 147 | $base64SignedSignature = base64_encode($signedSignature); 148 | 149 | $signatureHeaders = '(request-target) host digest date'; 150 | 151 | if (!empty($options['body'])) { 152 | $signatureHeaders = '(request-target) host content-type content-length digest date'; 153 | } 154 | 155 | $authorizationHeader = sprintf( 156 | 'Signature keyId="%s", algorithm="rsa-sha256", headers="%s", signature="%s"', 157 | $keyId, 158 | $signatureHeaders, 159 | $base64SignedSignature 160 | ); 161 | } 162 | 163 | if (!empty($authorizationHeader)) { 164 | $headers['Authorization'] = $authorizationHeader; 165 | } 166 | 167 | return [ 168 | 'headers' => $headers 169 | ]; 170 | } 171 | 172 | /** 173 | * Execute HTTP request. 174 | * 175 | * @param array $options 176 | */ 177 | private static function request($options = []) 178 | { 179 | $body = ''; 180 | 181 | $headers = [ 182 | 'Accept' => 'application/json', 183 | 'User-Agent' => self::$userAgentName . '/' . Api::getVersion() 184 | ]; 185 | 186 | if (key_exists('headers', $options)) { 187 | $headers = array_merge($headers, $options['headers']); 188 | } 189 | 190 | $platformHeader = Api::getPlatformHeader(); 191 | $platformVersionHeader = Api::getPlatformVersionHeader(); 192 | $pluginVersionHeader = Api::getPluginVersionHeader(); 193 | $pluginNameHeader = Api::getPluginNameHeader(); 194 | $typeHeader = Api::getTypeHeader(); 195 | $trackingHeader = Api::getTrackingHeader(); 196 | 197 | if (!empty($platformHeader)) { 198 | $headers[self::HEADER_OS] = $platformHeader; 199 | } 200 | 201 | if (!empty($platformVersionHeader)) { 202 | $headers[self::HEADER_OS_VERSION] = $platformVersionHeader; 203 | } 204 | 205 | if (!empty($pluginVersionHeader)) { 206 | $headers[self::HEADER_APP_VERSION] = $pluginVersionHeader; 207 | } 208 | 209 | if (!empty($pluginNameHeader)) { 210 | $headers[self::HEADER_APP_NAME] = $pluginNameHeader; 211 | } 212 | 213 | if (!empty($typeHeader)) { 214 | $headers[self::HEADER_DEVICE_TYPE] = $typeHeader; 215 | } 216 | 217 | if (!empty($trackingHeader)) { 218 | $headers[self::HEADER_TRACKING_CODE] = $trackingHeader; 219 | } 220 | 221 | $method = 'GET'; 222 | 223 | if (!empty($options['method'])) { 224 | $method = $options['method']; 225 | } 226 | 227 | if (!empty($options['body'])) { 228 | $headers['Content-Type'] = 'application/json'; 229 | 230 | $body = json_encode($options['body']); 231 | 232 | $headers['Content-Length'] = strlen($body); 233 | } 234 | 235 | $sign = key_exists('sign', $options) && $options['sign']; 236 | 237 | if ($sign) { 238 | $signResult = self::signRequest([ 239 | 'body' => $body, 240 | 'method' => $method, 241 | 'path' => $options['path'] 242 | ]); 243 | 244 | $headers = array_merge($headers, $signResult['headers']); 245 | } 246 | 247 | $headers = array_map(function($key, $value) { 248 | return "$key: $value"; 249 | }, array_keys($headers), $headers); 250 | 251 | $curlResult = self::curl([ 252 | 'url' => Api::getAuthservicesUrl() . $options['path'], 253 | 'method' => $method, 254 | 'body' => $body, 255 | 'headers' => $headers 256 | ]); 257 | 258 | if (!empty($curlResult['errorCode']) && !empty($curlResult['errorMessage'])) { 259 | throw new \Exception($curlResult['errorMessage'], $curlResult['errorCode']); 260 | } 261 | 262 | $isResponseOk = true; 263 | if ($curlResult['status'] < 200 || $curlResult['status'] > 299) { 264 | $isResponseOk = false; 265 | } 266 | 267 | $responseData = json_decode($curlResult['body']); 268 | 269 | if (!$isResponseOk) { 270 | if (!empty($responseData->message) && !empty($responseData->code) && !empty($responseData->wlt)) { 271 | throw new \Exception($responseData->message . ', request id: ' . $responseData->wlt, $responseData->code); 272 | } else { 273 | throw new \Exception('HTTP status is not 2xx'); 274 | } 275 | } 276 | 277 | return $responseData; 278 | } 279 | 280 | /** 281 | * Curl request. 282 | * 283 | * @param array $options 284 | */ 285 | private static function curl($options = []) 286 | { 287 | $curlOptions = []; 288 | $curl = curl_init(); 289 | 290 | $curlOptions[CURLOPT_URL] = $options['url']; 291 | $curlOptions[CURLOPT_RETURNTRANSFER] = true; 292 | 293 | if ($options['method'] != 'GET') { 294 | if ($options['method'] != 'POST') { 295 | $curlOptions[CURLOPT_CUSTOMREQUEST] = $options['method']; 296 | } 297 | $curlOptions[CURLOPT_POSTFIELDS] = $options['body']; 298 | $curlOptions[CURLOPT_POST] = true; 299 | } else { 300 | $curlOptions[CURLOPT_HTTPGET] = true; 301 | } 302 | 303 | if (Api::getEnv() == 'test') { 304 | $curlOptions[CURLOPT_VERBOSE] = true; 305 | $curlOptions[CURLOPT_SSL_VERIFYHOST] = false; 306 | $curlOptions[CURLOPT_SSL_VERIFYPEER] = false; 307 | } 308 | 309 | $curlOptions[CURLOPT_HTTPHEADER] = $options['headers']; 310 | curl_setopt_array($curl, $curlOptions); 311 | 312 | $responseJson = curl_exec($curl); 313 | $responseStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE); 314 | $curlErrorCode = curl_errno($curl); 315 | $curlErrorMessage = curl_error($curl); 316 | curl_close($curl); 317 | 318 | return [ 319 | 'body' => $responseJson, 320 | 'status' => $responseStatus, 321 | 'errorCode' => $curlErrorCode, 322 | 'errorMessage' => $curlErrorMessage 323 | ]; 324 | } 325 | } 326 | --------------------------------------------------------------------------------