├── src ├── Model │ ├── DefaultModel.php │ ├── Common │ │ ├── ShippingInformation.php │ │ ├── FundTransferType.php │ │ ├── BackendResponseStatus.php │ │ ├── BillingInformation.php │ │ ├── Basket.php │ │ ├── PaymentType.php │ │ ├── Address.php │ │ └── BasketItem.php │ ├── Seamless │ │ └── Frontend │ │ │ ├── InitPaymentResult.php │ │ │ ├── DataStorageInitResult.php │ │ │ ├── DataStorageReadResult.php │ │ │ └── PaymentInformation.php │ └── Model.php ├── Exception │ ├── InvalidHashingMethodException.php │ └── RequiredParameterMissingException.php ├── Response │ ├── WirecardBackendResponse.php │ ├── WirecardResponseInterface.php │ ├── WirecardCheckoutPageBackendResponse.php │ └── WirecardResponse.php ├── MessageFactory.php ├── Request │ ├── Seamless │ │ ├── Backend │ │ │ ├── GenerateOrderNumberRequest.php │ │ │ ├── ApproveReversalRequest.php │ │ │ ├── GetOrderDetailsRequest.php │ │ │ ├── GetFinancialInstitutionsRequest.php │ │ │ ├── DepositReversalRequest.php │ │ │ ├── RefundRequest.php │ │ │ ├── DepositRequest.php │ │ │ ├── RefundReversalRequest.php │ │ │ ├── AbstractBackendRequest.php │ │ │ ├── RecurPaymentRequest.php │ │ │ └── TransferFundRequest.php │ │ └── Frontend │ │ │ ├── InitPaymentRequest.php │ │ │ ├── ReadDataStorageRequest.php │ │ │ └── InitDataStorageRequest.php │ ├── CheckoutPage │ │ ├── Backend │ │ │ ├── GenerateOrderNumberRequest.php │ │ │ ├── ApproveReversalRequest.php │ │ │ ├── GetOrderDetailsRequest.php │ │ │ ├── GetFinancialInstitutionsRequest.php │ │ │ ├── DepositReversalRequest.php │ │ │ ├── DepositRequest.php │ │ │ ├── RefundRequest.php │ │ │ ├── RefundReversalRequest.php │ │ │ ├── AbstractBackendRequest.php │ │ │ ├── RecurPaymentRequest.php │ │ │ └── TransferFundRequest.php │ │ └── InitCheckoutPageRequest.php │ ├── ParameterBag.php │ ├── WirecardRequestInterface.php │ ├── AbstractWirecardRequest.php │ └── AbstractPaymentRequest.php ├── GuzzlePsrMessageFactory.php ├── Helper │ └── WirecardHelper.php ├── Fingerprint.php └── Context.php ├── .editorconfig ├── CHANGELOG.md ├── example └── checkout-page │ ├── success.php │ └── index.php ├── LICENSE.md ├── CONTRIBUTING.md ├── composer.json └── README.md /src/Model/DefaultModel.php: -------------------------------------------------------------------------------- 1 | getParam('redirectUrl'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /src/Response/WirecardBackendResponse.php: -------------------------------------------------------------------------------- 1 | parameters['status']); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/MessageFactory.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | abstract class FundTransferType 12 | { 13 | const EXISTINGORDER = 'EXISTINGORDER'; 14 | const MONETA = 'MONETA'; 15 | const SEPA_CT = 'SEPA-CT'; 16 | const SKRILLWALLET = 'SKRILLWALLET'; 17 | } 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All Notable changes to `hochstrasserio/wirecard` will be documented in this file 4 | 5 | ## v0.1.0 - 2015-09-01 6 | 7 | ### Added 8 | - Support for frontend requests of Wirecard Checkout Page 9 | - Support for frontend requests of Wirecard Seamless Checkout 10 | - Models for Basket, ShippingInformation, and BillingInformation 11 | - Fingerprint validation 12 | - PSR-7 compatible request/response handling 13 | 14 | ### Deprecated 15 | - Nothing 16 | 17 | ### Fixed 18 | - Nothing 19 | 20 | ### Removed 21 | - Nothing 22 | 23 | ### Security 24 | - Nothing 25 | -------------------------------------------------------------------------------- /src/Request/Seamless/Frontend/InitPaymentRequest.php: -------------------------------------------------------------------------------- 1 | requiredParameters = array_merge($this->requiredParameters, [ 17 | 'paymentType', 'confirmUrl', 18 | 'consumerIpAddress', 'consumerUserAgent' 19 | ]); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Model/Common/BackendResponseStatus.php: -------------------------------------------------------------------------------- 1 | status = $status; 18 | } 19 | 20 | function getValue() 21 | { 22 | return $this->status; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Response/WirecardCheckoutPageBackendResponse.php: -------------------------------------------------------------------------------- 1 | parameters['errorCode']); 10 | } 11 | 12 | function getErrors() 13 | { 14 | if ($this->hasErrors()) { 15 | return [ 16 | [ 17 | 'errorCode' => $this->parameters['errorCode'], 18 | 'message' => $this->parameters['message'], 19 | 'paySysMessage' => $this->parameters['paySysMessage'], 20 | ] 21 | ]; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Model/Seamless/Frontend/DataStorageInitResult.php: -------------------------------------------------------------------------------- 1 | getParam('storageId'); 17 | } 18 | 19 | /** 20 | * URL to a JavaScript resource which has to be included for storing data in 21 | * the data storage 22 | * 23 | * @return string 24 | */ 25 | function getJavascriptUrl() 26 | { 27 | return $this->getParam('javascriptUrl'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Exception/RequiredParameterMissingException.php: -------------------------------------------------------------------------------- 1 | param = $param; 19 | 20 | return $self; 21 | } 22 | 23 | /** 24 | * Returns the parameter name 25 | * 26 | * @return string 27 | */ 28 | function getParam() 29 | { 30 | return $this->param; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Request/Seamless/Frontend/ReadDataStorageRequest.php: -------------------------------------------------------------------------------- 1 | setStorageId($storageId); 18 | 19 | return $request; 20 | } 21 | 22 | function setStorageId($storageId) 23 | { 24 | return $this->addParam('storageId', $storageId); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/ApproveReversalRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ; 17 | } 18 | 19 | /** 20 | * ID of the order 21 | * 22 | * @param string $orderNumber 23 | * @return ApproveReversalRequest 24 | */ 25 | function setOrderNumber($orderNumber) 26 | { 27 | return $this->addParam('orderNumber', $orderNumber); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/GetOrderDetailsRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ; 17 | } 18 | 19 | /** 20 | * ID of the order 21 | * 22 | * @param string $orderNumber 23 | * @return GetOrderDetailsRequest 24 | */ 25 | function setOrderNumber($orderNumber) 26 | { 27 | return $this->addParam('orderNumber', $orderNumber); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/ApproveReversalRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ; 17 | } 18 | 19 | /** 20 | * ID of the order 21 | * 22 | * @param string $orderNumber 23 | * @return ApproveReversalRequest 24 | */ 25 | function setOrderNumber($orderNumber) 26 | { 27 | return $this->addParam('orderNumber', $orderNumber); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/GetOrderDetailsRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ; 17 | } 18 | 19 | /** 20 | * ID of the order 21 | * 22 | * @param string $orderNumber 23 | * @return GetOrderDetailsRequest 24 | */ 25 | function setOrderNumber($orderNumber) 26 | { 27 | return $this->addParam('orderNumber', $orderNumber); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/GetFinancialInstitutionsRequest.php: -------------------------------------------------------------------------------- 1 | addParam('paymentType', $paymentType); 15 | } 16 | 17 | function setTransactionType($transactionType) 18 | { 19 | return $this->addParam('transactionType', $transactionType); 20 | } 21 | 22 | function setBankCountry($bankCountry) 23 | { 24 | return $this->addParam('bankCountry', $bankCountry); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/GetFinancialInstitutionsRequest.php: -------------------------------------------------------------------------------- 1 | addParam('paymentType', $paymentType); 15 | } 16 | 17 | function setTransactionType($transactionType) 18 | { 19 | return $this->addParam('transactionType', $transactionType); 20 | } 21 | 22 | function setBankCountry($bankCountry) 23 | { 24 | return $this->addParam('bankCountry', $bankCountry); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Request/ParameterBag.php: -------------------------------------------------------------------------------- 1 | parameters = $parameters; 14 | } 15 | 16 | function set($param, $value) 17 | { 18 | $this->parameters[$param] = $value; 19 | } 20 | 21 | function put($param, $value) 22 | { 23 | if ($this->has($param)) { 24 | return; 25 | } 26 | 27 | $this->set($param, $value); 28 | } 29 | 30 | function get($param) 31 | { 32 | if ($this->has($param)) { 33 | return $this->parameters[$param]; 34 | } 35 | } 36 | 37 | function has($param) 38 | { 39 | return array_key_exists($param, $this->parameters); 40 | } 41 | 42 | function all() 43 | { 44 | return $this->parameters; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/checkout-page/success.php: -------------------------------------------------------------------------------- 1 | 'D200001', 10 | 'secret' => 'B8AKTPWBRMNBV455FG6M2DANE99WU2', 11 | 'language' => 'de', 12 | 'shop_id' => 'qmore' 13 | ]); 14 | 15 | $fingerprint = Fingerprint::fromResponseParameters($_POST, $context); 16 | $fingerprintIsValid = hash_equals((string) $fingerprint, $_POST['responseFingerprint']); 17 | 18 | ?> 19 | 20 |

Response Parameters

21 |
22 | 23 | 24 |

Fingerprint

25 | 26 |

27 | Fingerprint is valid' : 'invalid' ?> 28 |

29 | 30 |
Expected:
31 |
32 | 33 |
34 |
Actual:
35 |
36 | 37 |
38 | 39 |

40 | New Request 41 |

42 | -------------------------------------------------------------------------------- /src/Model/Seamless/Frontend/DataStorageReadResult.php: -------------------------------------------------------------------------------- 1 | addParam('paymentInformation', array_map( 14 | function ($parameters) { 15 | return new PaymentInformation($parameters); 16 | }, 17 | $this->getParam('paymentInformation') ?: [] 18 | )); 19 | } 20 | 21 | /** 22 | * Unique reference to the data storage of a consumer 23 | * 24 | * @return string 25 | */ 26 | function getStorageId() 27 | { 28 | return $this->getParam('storageId'); 29 | } 30 | 31 | /** 32 | * Array of PaymentInformation objects, representing the sanitized data which was 33 | * stored in the data storage by the user 34 | * 35 | * @return array 36 | */ 37 | function getPaymentInformation() 38 | { 39 | return $this->getParam('paymentInformation'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/DepositReversalRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ->setPaymentNumber($paymentNumber) 17 | ; 18 | } 19 | 20 | /** 21 | * ID of the order 22 | * 23 | * @param string $orderNumber 24 | * @return DepositReversalRequest 25 | */ 26 | function setOrderNumber($orderNumber) 27 | { 28 | return $this->addParam('orderNumber', $orderNumber); 29 | } 30 | 31 | function setPaymentNumber($paymentNumber) 32 | { 33 | return $this->addParam('paymentNumber', $paymentNumber); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/DepositReversalRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ->setPaymentNumber($paymentNumber) 17 | ; 18 | } 19 | 20 | /** 21 | * ID of the order 22 | * 23 | * @param string $orderNumber 24 | * @return DepositReversalRequest 25 | */ 26 | function setOrderNumber($orderNumber) 27 | { 28 | return $this->addParam('orderNumber', $orderNumber); 29 | } 30 | 31 | function setPaymentNumber($paymentNumber) 32 | { 33 | return $this->addParam('paymentNumber', $paymentNumber); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Christoph Hochstrasser 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 13 | > all 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 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/DepositRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ; 17 | } 18 | 19 | /** 20 | * ID of the order 21 | * 22 | * @param string $orderNumber 23 | * @return DepositRequest 24 | */ 25 | function setOrderNumber($orderNumber) 26 | { 27 | return $this->addParam('orderNumber', $orderNumber); 28 | } 29 | 30 | function setAmount($amount) 31 | { 32 | return $this->addParam('amount', $amount); 33 | } 34 | 35 | function setCurrency($currency) 36 | { 37 | return $this->addParam('currency', $currency); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/RefundRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ->setAmount($amount) 17 | ->setCurrency($currency) 18 | ; 19 | } 20 | 21 | /** 22 | * ID of the order 23 | * 24 | * @param string $orderNumber 25 | * @return RefundRequest 26 | */ 27 | function setOrderNumber($orderNumber) 28 | { 29 | return $this->addParam('orderNumber', $orderNumber); 30 | } 31 | 32 | function setAmount($amount) 33 | { 34 | return $this->addParam('amount', $amount); 35 | } 36 | 37 | function setCurrency($currency) 38 | { 39 | return $this->addParam('currency', $currency); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/DepositRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ->setAmount($amount) 17 | ->setCurrency($currency) 18 | ; 19 | } 20 | 21 | /** 22 | * ID of the order 23 | * 24 | * @param string $orderNumber 25 | * @return DepositRequest 26 | */ 27 | function setOrderNumber($orderNumber) 28 | { 29 | return $this->addParam('orderNumber', $orderNumber); 30 | } 31 | 32 | function setAmount($amount) 33 | { 34 | return $this->addParam('amount', $amount); 35 | } 36 | 37 | function setCurrency($currency) 38 | { 39 | return $this->addParam('currency', $currency); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/RefundRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ->setAmount($amount) 17 | ->setCurrency($currency) 18 | ; 19 | } 20 | 21 | /** 22 | * ID of the order 23 | * 24 | * @param string $orderNumber 25 | * @return RefundRequest 26 | */ 27 | function setOrderNumber($orderNumber) 28 | { 29 | return $this->addParam('orderNumber', $orderNumber); 30 | } 31 | 32 | function setAmount($amount) 33 | { 34 | return $this->addParam('amount', $amount); 35 | } 36 | 37 | function setCurrency($currency) 38 | { 39 | return $this->addParam('currency', $currency); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/RefundReversalRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ->setCreditNumber($creditNumber) 17 | ; 18 | } 19 | 20 | /** 21 | * ID of the order 22 | * 23 | * @param string $orderNumber 24 | * @return RefundReversalRequest 25 | */ 26 | function setOrderNumber($orderNumber) 27 | { 28 | return $this->addParam('orderNumber', $orderNumber); 29 | } 30 | 31 | /** 32 | * ID of the credit note created by the RefundRequest 33 | * 34 | * @param string $creditNumber 35 | * @return RefundReversalRequest 36 | */ 37 | function setOrderNumber($creditNumber) 38 | { 39 | return $this->addParam('creditNumber', $creditNumber); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/RefundReversalRequest.php: -------------------------------------------------------------------------------- 1 | setOrderNumber($orderNumber) 16 | ->setCreditNumber($creditNumber) 17 | ; 18 | } 19 | 20 | /** 21 | * ID of the order 22 | * 23 | * @param string $orderNumber 24 | * @return RefundReversalRequest 25 | */ 26 | function setOrderNumber($orderNumber) 27 | { 28 | return $this->addParam('orderNumber', $orderNumber); 29 | } 30 | 31 | /** 32 | * ID of the credit note created by the RefundRequest 33 | * 34 | * @param string $creditNumber 35 | * @return RefundReversalRequest 36 | */ 37 | function setOrderNumber($creditNumber) 38 | { 39 | return $this->addParam('creditNumber', $creditNumber); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/hochstrasserio/wirecard). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ composer test 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hochstrasserio/wirecard", 3 | "description": "A modern client for the Wirecard payment gateway", 4 | "keywords": [ 5 | "hochstrasserio", 6 | "wirecard" 7 | ], 8 | "homepage": "https://github.com/hochstrasserio/wirecard", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Christoph Hochstrasser", 13 | "email": "christoph@hochstrasser.io", 14 | "homepage": "https://www.hochstrasser.io", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.4.0", 20 | "guzzlehttp/psr7": "^1.0.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "4.*", 24 | "guzzlehttp/guzzle": "^6.0.0", 25 | "egeloen/http-adapter": "~0.8.0@dev" 26 | }, 27 | "suggest": { 28 | "php-http/httplug": "Adapters to existing HTTP clients", 29 | "sebastian/money": "Robust handling of money amounts" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Hochstrasser\\Wirecard\\": "src" 34 | } 35 | }, 36 | "autoload-dev": { 37 | "psr-4": { 38 | "Hochstrasser\\Wirecard\\Test\\": ["tests/unit", "tests/functional"] 39 | } 40 | }, 41 | "scripts": { 42 | "test": "phpunit" 43 | }, 44 | "extra": { 45 | "branch-alias": { 46 | "dev-master": "1.2-dev" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Model/Common/BillingInformation.php: -------------------------------------------------------------------------------- 1 | setFirstname($shipping->getFirstname()); 15 | $billing->setLastname($shipping->getLastname()); 16 | $billing->setAddress1($shipping->getAddress1()); 17 | $billing->setAddress2($shipping->getAddress2()); 18 | $billing->setCity($shipping->getCity()); 19 | $billing->setState($shipping->getState()); 20 | $billing->setCountry($shipping->getCountry()); 21 | $billing->setZipCode($shipping->getZipCode()); 22 | $billing->setPhone($shipping->getPhone()); 23 | $billing->setFax($shipping->getFax()); 24 | 25 | return $billing; 26 | } 27 | 28 | function setConsumerBirthDate(\DateTime $value) 29 | { 30 | return $this->addParam('consumerBirthDate', $value->format('Y-m-d')); 31 | } 32 | 33 | function getConsumerBirthDate() 34 | { 35 | return \DateTime::createFromFormat('Y-m-d', $this->getParam('consumerBirthDate')); 36 | } 37 | 38 | function setConsumerEmail($value) 39 | { 40 | return $this->addParam('consumerEmail', $value); 41 | } 42 | 43 | function getConsumerEmail() 44 | { 45 | return $this->getParam('consumerEmail'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Helper/WirecardHelper.php: -------------------------------------------------------------------------------- 1 | context = $context; 35 | $this->client = $client; 36 | } 37 | 38 | /** 39 | * Synchronously sends the request with the configured client 40 | * 41 | * @return WirecardResponseInterface 42 | */ 43 | function send(WirecardRequestInterface $wirecardRequest) 44 | { 45 | $wirecardRequest->setContext($this->getContext()); 46 | 47 | $httpRequest = $wirecardRequest->createHttpRequest(); 48 | $httpResponse = call_user_func($this->client, $httpRequest); 49 | 50 | return $wirecardRequest->createResponse($httpResponse); 51 | } 52 | 53 | /** 54 | * @return Context 55 | */ 56 | private function getContext() 57 | { 58 | return $this->context; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Request/WirecardRequestInterface.php: -------------------------------------------------------------------------------- 1 | getParam('paymentType'); 12 | } 13 | 14 | function getAnonymousPan() 15 | { 16 | return $this->getParam('anonymousPan'); 17 | } 18 | 19 | function getMaskedPan() 20 | { 21 | return $this->getParam('maskedPan'); 22 | } 23 | 24 | function getFinancialInstitution() 25 | { 26 | return $this->getParam('financialInstitution'); 27 | } 28 | 29 | function getBrand() 30 | { 31 | return $this->getParam('brand'); 32 | } 33 | 34 | function getCardholdername() 35 | { 36 | return $this->getParam('cardholdername'); 37 | } 38 | 39 | function getExpiry() 40 | { 41 | return $this->getParam('expiry'); 42 | } 43 | 44 | function getAccountOwner() 45 | { 46 | return $this->getParam('accountOwner'); 47 | } 48 | 49 | function getBankName() 50 | { 51 | return $this->getParam('bankName'); 52 | } 53 | 54 | function getBankCountry() 55 | { 56 | return $this->getParam('bankCountry'); 57 | } 58 | 59 | function getBankAccount() 60 | { 61 | return $this->getParam('bankAccount'); 62 | } 63 | 64 | function getBankBic() 65 | { 66 | return $this->getParam('bankBic'); 67 | } 68 | 69 | function getBankAccountIban() 70 | { 71 | return $this->getParam('bankAccountIban'); 72 | } 73 | 74 | function getPayerPayboxNumber() 75 | { 76 | return $this->getParam('payerPayboxNumber'); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/AbstractBackendRequest.php: -------------------------------------------------------------------------------- 1 | operation; 16 | } 17 | 18 | function createResponse(\Psr\Http\Message\ResponseInterface $response) 19 | { 20 | return WirecardBackendResponse::fromHttpResponse( 21 | $response, 22 | $this->resultClass 23 | ); 24 | } 25 | 26 | protected function getRawParameters() 27 | { 28 | $params = parent::getRawParameters(); 29 | 30 | if (empty($params['language'])) { 31 | $params['language'] = $this->getContext()->getLanguage(); 32 | } 33 | 34 | if (empty($params['password'])) { 35 | $params['password'] = $this->getContext()->getBackendPassword(); 36 | } 37 | 38 | return $params; 39 | } 40 | 41 | function getRequestParameters() 42 | { 43 | $params = $this->getRawParameters(); 44 | 45 | $params['requestFingerprint'] = Fingerprint::fromParameters($params) 46 | ->setContext($this->getContext()) 47 | ->setFingerprintOrder(array_merge(['customerId', 'shopId', 'password', 'secret', 'language'], $this->fingerprintOrder)); 48 | 49 | $this->assertParametersAreValid($params, array_merge(['customerId', 'requestFingerprint', 'password', 'language'], $this->requiredParameters)); 50 | 51 | return $params; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Model/Model.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | abstract class Model implements \Serializable 11 | { 12 | private $parameters; 13 | 14 | /** 15 | * Constructor 16 | * 17 | * @param array $parameters 18 | */ 19 | function __construct(array $parameters = []) 20 | { 21 | $this->parameters = $parameters; 22 | } 23 | 24 | /** 25 | * Initializes the model from parameters 26 | * 27 | * @param array $parameters 28 | * @return Model 29 | */ 30 | static function fromParameters(array $parameters) 31 | { 32 | return new static($parameters); 33 | } 34 | 35 | /** 36 | * Returns a parameter 37 | * 38 | * @param string $param 39 | * @return mixed 40 | */ 41 | function getParam($param) 42 | { 43 | if (array_key_exists($param, $this->parameters)) { 44 | return $this->parameters[$param]; 45 | } 46 | } 47 | 48 | /** 49 | * Modifies a parameter on the model 50 | * 51 | * @param string $param 52 | * @param mixed $value 53 | * @return Model 54 | */ 55 | function addParam($param, $value) 56 | { 57 | $this->parameters[$param] = $value; 58 | return $this; 59 | } 60 | 61 | /** 62 | * @return array 63 | */ 64 | function toArray() 65 | { 66 | return $this->parameters; 67 | } 68 | 69 | /** 70 | * Implement Serializable 71 | */ 72 | function serialize() 73 | { 74 | return serialize($this->parameters); 75 | } 76 | 77 | /** 78 | * Implement Serializable 79 | */ 80 | function unserialize($data) 81 | { 82 | $this->parameters = unserialize($data); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/AbstractBackendRequest.php: -------------------------------------------------------------------------------- 1 | resultClass 19 | ); 20 | } 21 | 22 | protected function getRawParameters() 23 | { 24 | $params = parent::getRawParameters(); 25 | 26 | if (empty($params['language'])) { 27 | $params['language'] = $this->getContext()->getLanguage(); 28 | } 29 | 30 | if (empty($params['toolkitPassword'])) { 31 | $params['toolkitPassword'] = $this->getContext()->getBackendPassword(); 32 | } 33 | 34 | if (empty($params['command'])) { 35 | $params['command'] = $this->operation; 36 | } 37 | 38 | return $params; 39 | } 40 | 41 | function getRequestParameters() 42 | { 43 | $params = $this->getRawParameters(); 44 | 45 | $params['requestFingerprint'] = Fingerprint::fromParameters($params) 46 | ->setContext($this->getContext()) 47 | ->setFingerprintOrder(array_merge(['customerId', 'shopId', 'toolkitPassword', 'secret', 'command', 'language'], $this->fingerprintOrder)); 48 | 49 | $this->assertParametersAreValid($params, array_merge(['customerId', 'requestFingerprint', 'toolkitPassword', 'language'], $this->requiredParameters)); 50 | 51 | return $params; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Model/Common/Basket.php: -------------------------------------------------------------------------------- 1 | addParam('amount', $amount); 20 | } 21 | 22 | /** 23 | * Returns total amount of shopping basket 24 | * 25 | * @return float 26 | */ 27 | function getAmount() 28 | { 29 | return $this->getParam('amount'); 30 | } 31 | 32 | /** 33 | * Sets currency as ISO code or numeric identifier 34 | * 35 | * @param string|int $currency 36 | * @return Basket 37 | */ 38 | function setCurrency($currency) 39 | { 40 | return $this->addParam('currency', $currency); 41 | } 42 | 43 | /** 44 | * Returns the currency as ISO code or numeric identifier 45 | * 46 | * @returns string|int 47 | */ 48 | function getCurrency() 49 | { 50 | return $this->getParam('currency'); 51 | } 52 | 53 | /** 54 | * Adds an item to the basket 55 | * 56 | * @param BasketItem $item 57 | * @return Basket 58 | */ 59 | function addItem(BasketItem $item) 60 | { 61 | $basketItems = $this->getParam('basketItems') ?: 0; 62 | $basketItems++; 63 | 64 | $this->items[$basketItems] = $item; 65 | $this->addParam('basketItems', $basketItems); 66 | 67 | foreach ($item->toArray() as $param => $value) { 68 | $this->addParam('basketItem'.$basketItems.ucfirst($param), $value); 69 | } 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Returns a list of added BasketItem objects 76 | * 77 | * @return array 78 | */ 79 | function getItems() 80 | { 81 | return $this->items; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Request/Seamless/Frontend/InitDataStorageRequest.php: -------------------------------------------------------------------------------- 1 | setOrderIdent($orderIdent) 23 | ->setReturnUrl($returnUrl) 24 | ; 25 | } 26 | 27 | /** 28 | * Unique reference to the order of your consumer 29 | * 30 | * @param string $orderIdent 31 | * @return InitDataStorageRequest 32 | */ 33 | function setOrderIdent($orderIdent) 34 | { 35 | return $this->addParam('orderIdent', $orderIdent); 36 | } 37 | 38 | /** 39 | * Return URL for outdated browsers 40 | * 41 | * @param string $returnUrl 42 | * @return InitDataStorageRequest 43 | */ 44 | function setReturnUrl($returnUrl) 45 | { 46 | return $this->addParam('returnUrl', $returnUrl); 47 | } 48 | 49 | protected function getRawParameters() 50 | { 51 | $params = parent::getRawParameters(); 52 | 53 | if (empty($params['language'])) { 54 | $params['language'] = $this->getContext()->getLanguage(); 55 | } 56 | 57 | if (empty($params['javascriptScriptVersion'])) { 58 | $params['javascriptScriptVersion'] = $this->getContext()->getJavascriptScriptVersion(); 59 | } 60 | 61 | return $params; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Model/Common/PaymentType.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | abstract class PaymentType 15 | { 16 | /** 17 | * @var array 18 | */ 19 | private static $constants; 20 | 21 | /** 22 | * The consumer may select one of the activated payment methods directly in 23 | * Wirecard Checkout Page. Please note that SELECT is only available for 24 | * Wirecard Checkout Page. 25 | */ 26 | const Select = 'SELECT'; 27 | const BancontactMisterCash = 'BANCONTACT_MISTERCASH'; 28 | const CreditCard = 'CCARD'; 29 | const CreditCardMailOrderAndTelephoneOrder = 'CCARD-MOTO'; 30 | const eKonto = 'EKONTO'; 31 | const ePayBg = 'EPAY_BG'; 32 | const EPS = 'EPS'; 33 | const giropay = 'GIROPAY'; 34 | const iDEAL = 'IDL'; 35 | const Installment = 'INSTALLMENT'; 36 | const Invoice = 'INVOICE'; 37 | const monetaRu = 'MONETA'; 38 | const mpass = 'MPASS'; 39 | const Przelewy24 = 'PRZELEWY24'; 40 | const PayPal = 'PAYPAL'; 41 | const paybox = 'PBX'; 42 | const POLi = 'POLI'; 43 | const paysafecard = 'PSC'; 44 | const Quick = 'QUICK'; 45 | const SEPADirectDebit = 'SEPA-DD'; 46 | const SkrillDirect = 'SKRILLDIRECT'; 47 | const SkrillDigitalWallet = 'SKRILLWALLET'; 48 | const SOFORTBanking = 'SOFORTUEBERWEISUNG'; 49 | const TatraPay = 'TATRAPAY'; 50 | const Trustly = 'TRUSTLY'; 51 | const TrustPay = 'TRUSTPAY'; 52 | const MyVoucher = 'VOUCHER'; 53 | 54 | /** 55 | * @param string $paymentType 56 | * @return bool 57 | */ 58 | static function isValid($paymentType) 59 | { 60 | return in_array($paymentType, static::getValues(), true); 61 | } 62 | 63 | /** 64 | * @return array 65 | */ 66 | static function getValues() 67 | { 68 | if (null === static::$constants) { 69 | static::$constants = (new \ReflectionClass(get_called_class()))->getConstants(); 70 | } 71 | 72 | return static::$constants; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /example/checkout-page/index.php: -------------------------------------------------------------------------------- 1 | 'D200411', 15 | 'secret' => 'CHCSH7UGHVVX2P7EHDHSY4T2S4CGYK4QBE4M5YUUG2ND5BEZWNRZW5EJYVJQ', 16 | 'language' => 'de', 17 | 'shop_id' => 'qmore' 18 | ]); 19 | 20 | $basket = new Basket(); 21 | $basket->setAmount('18.00'); 22 | $basket->setCurrency('EUR'); 23 | $basket->addItem((new BasketItem) 24 | ->setArticleNumber('A001') 25 | ->setDescription('Product A1') 26 | ->setQuantity(1) 27 | ->setUnitPrice('10.00') 28 | ->setTax('2.00') 29 | ); 30 | $basket->addItem((new BasketItem) 31 | ->setArticleNumber('SHIPPING') 32 | ->setDescription('Shipping') 33 | ->setQuantity(1) 34 | ->setUnitPrice('5.00') 35 | ->setTax('1.00') 36 | ); 37 | 38 | $shipping = (new ShippingInformation) 39 | ->setFirstname('Christoph') 40 | ->setLastname('Hochstrasser') 41 | ->setAddress1('Markt 1') 42 | ->setZipCode('1234') 43 | ->setCity('Musterstadt') 44 | ->setState('Niederösterreich') 45 | ->setCountry('AT'); 46 | 47 | $billing = BillingInformation::fromShippingInformation($shipping) 48 | ->setConsumerEmail('me@christophh.net') 49 | ->setConsumerBirthdate(new \DateTime('01.01.1970')) 50 | ; 51 | 52 | $request = InitCheckoutPageRequest::withBasket($basket) 53 | ->setPaymentType(PaymentType::Select) 54 | ->setConsumerShippingInformation($shipping) 55 | ->setConsumerBillingInformation($billing) 56 | ->setContext($context) 57 | ->setOrderDescription("12345") 58 | ->setSuccessUrl("http://localhost:8001/success.php") 59 | ->setFailureUrl("http://localhost") 60 | ->setCancelUrl("http://localhost") 61 | ->setServiceUrl("http://localhost") 62 | ; 63 | ?> 64 | 65 |
66 | getRequestParameters() as $param => $value): ?> 67 | 68 | 69 | 70 | 71 |
72 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/RecurPaymentRequest.php: -------------------------------------------------------------------------------- 1 | addParam('orderNumber', $orderNumber); 24 | } 25 | 26 | function setSourceOrderNumber($sourceOrderNumber) 27 | { 28 | return $this->addParam('sourceOrderNumber', $sourceOrderNumber); 29 | } 30 | 31 | function setAutoDeposit($autoDeposit) 32 | { 33 | return $this->addParam('autoDeposit', $autoDeposit ? 'Yes' : 'No'); 34 | } 35 | 36 | function setOrderDescription($orderDescription) 37 | { 38 | return $this->addParam('orderDescription', $orderDescription); 39 | } 40 | 41 | function setOrderReference($orderReference) 42 | { 43 | return $this->addParam('orderReference', $orderReference); 44 | } 45 | 46 | function setCustomerStatement($customerStatement) 47 | { 48 | return $this->addParam('customerStatement', $customerStatement); 49 | } 50 | 51 | function setAmount($amount) 52 | { 53 | return $this->addParam('amount', $amount); 54 | } 55 | 56 | function setCurrency($currency) 57 | { 58 | return $this->addParam('currency', $currency); 59 | } 60 | 61 | function setTransactionIdentifier($transactionIdentifier) 62 | { 63 | return $this->addParam('transactionIdentifier', $transactionIdentifier); 64 | } 65 | 66 | function setMandateId($mandateId) 67 | { 68 | return $this->addParam('mandateId', $mandateId); 69 | } 70 | 71 | function setMandateSignatureDate(\DateTime $mandateSignatureDate) 72 | { 73 | return $this->addParam('mandateSignatureDate', $mandateSignatureDate->format('d.m.Y')); 74 | } 75 | 76 | function setCreditorId($creditorId) 77 | { 78 | return $this->addParam('creditorId', $creditorId); 79 | } 80 | 81 | function setDueDate(\DateTime $dueDate) 82 | { 83 | return $this->addParam('dueDate', $dueDate->format('d.m.Y')); 84 | } 85 | 86 | function setUseIbanBic($useIbanBic) 87 | { 88 | return $this->addParam('useIbanBic', $useIbanBic ? 'Yes' : 'No'); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/RecurPaymentRequest.php: -------------------------------------------------------------------------------- 1 | addParam('orderNumber', $orderNumber); 25 | } 26 | 27 | function setSourceOrderNumber($sourceOrderNumber) 28 | { 29 | return $this->addParam('sourceOrderNumber', $sourceOrderNumber); 30 | } 31 | 32 | function setAutoDeposit($autoDeposit) 33 | { 34 | return $this->addParam('autoDeposit', $autoDeposit ? 'Yes' : 'No'); 35 | } 36 | 37 | function setOrderDescription($orderDescription) 38 | { 39 | return $this->addParam('orderDescription', $orderDescription); 40 | } 41 | 42 | function setOrderReference($orderReference) 43 | { 44 | return $this->addParam('orderReference', $orderReference); 45 | } 46 | 47 | function setCustomerStatement($customerStatement) 48 | { 49 | return $this->addParam('customerStatement', $customerStatement); 50 | } 51 | 52 | function setAmount($amount) 53 | { 54 | return $this->addParam('amount', $amount); 55 | } 56 | 57 | function setCurrency($currency) 58 | { 59 | return $this->addParam('currency', $currency); 60 | } 61 | 62 | function setTransactionIdentifier($transactionIdentifier) 63 | { 64 | return $this->addParam('transactionIdentifier', $transactionIdentifier); 65 | } 66 | 67 | function setMandateId($mandateId) 68 | { 69 | return $this->addParam('mandateId', $mandateId); 70 | } 71 | 72 | function setMandateSignatureDate(\DateTime $mandateSignatureDate) 73 | { 74 | return $this->addParam('mandateSignatureDate', $mandateSignatureDate->format('d.m.Y')); 75 | } 76 | 77 | function setCreditorId($creditorId) 78 | { 79 | return $this->addParam('creditorId', $creditorId); 80 | } 81 | 82 | function setDueDate(\DateTime $dueDate) 83 | { 84 | return $this->addParam('dueDate', $dueDate->format('d.m.Y')); 85 | } 86 | 87 | function setUseIbanBic($useIbanBic) 88 | { 89 | return $this->addParam('useIbanBic', $useIbanBic ? 'Yes' : 'No'); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Fingerprint.php: -------------------------------------------------------------------------------- 1 | parameters = $parameters; 33 | 34 | return $self; 35 | } 36 | 37 | /** 38 | * Create a fingerprint based on received response paramaters 39 | * 40 | * @param array $parameters 41 | * @param Context $context 42 | * @return Fingerprint 43 | */ 44 | public static function fromResponseParameters(array $parameters, Context $context = null) 45 | { 46 | if (empty($parameters['responseFingerprintOrder'])) { 47 | throw new \UnexpectedValueException('The responseFingerprintOrder parameter is missing'); 48 | } 49 | 50 | $self = static::fromParameters($parameters); 51 | $self->setFingerprintOrder(explode(',', $parameters['responseFingerprintOrder'])); 52 | 53 | if (null !== $context) { 54 | $self->setContext($context); 55 | } 56 | 57 | return $self; 58 | } 59 | 60 | /** 61 | * Sets the context for fingerprint calculation 62 | * 63 | * @param Context $context 64 | * @return Fingerprint 65 | */ 66 | public function setContext(Context $context) 67 | { 68 | $this->context = $context; 69 | 70 | if (empty($this->parameters['secret'])) { 71 | $this->parameters['secret'] = $context->getSecret(); 72 | } 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Sets the parameter order for fingerprint calculation 79 | * 80 | * @param array $fingerprintOrder List of parameter names 81 | * @return Fingerprint 82 | */ 83 | public function setFingerprintOrder(array $fingerprintOrder) 84 | { 85 | $this->fingerprintOrder = $fingerprintOrder; 86 | 87 | return $this; 88 | } 89 | 90 | /** 91 | * @return string 92 | */ 93 | public function __toString() 94 | { 95 | $raw = ''; 96 | 97 | foreach ($this->fingerprintOrder as $parameter) { 98 | if (isset($this->parameters[$parameter])) { 99 | $raw .= $this->parameters[$parameter]; 100 | } 101 | } 102 | 103 | if (null !== $this->context && Context::HASHING_HMAC === $this->context->getHashingMethod()) { 104 | return hash_hmac('sha512', $raw, $this->parameters['secret']); 105 | } 106 | 107 | return hash('sha512', $raw); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Model/Common/Address.php: -------------------------------------------------------------------------------- 1 | addParam($this->addressParameterPrefix.'Firstname', $value); 17 | } 18 | 19 | function getFirstname() 20 | { 21 | return $this->getParam($this->addressParameterPrefix.'Firstname'); 22 | } 23 | 24 | /** 25 | * @return Address 26 | */ 27 | function setLastname($value) 28 | { 29 | return $this->addParam($this->addressParameterPrefix.'Lastname', $value); 30 | } 31 | 32 | function getLastname() 33 | { 34 | return $this->getParam($this->addressParameterPrefix.'Lastname'); 35 | } 36 | 37 | /** 38 | * @return Address 39 | */ 40 | function setAddress1($value) 41 | { 42 | return $this->addParam($this->addressParameterPrefix.'Address1', $value); 43 | } 44 | 45 | function getAddress1() 46 | { 47 | return $this->getParam($this->addressParameterPrefix.'Address1'); 48 | } 49 | 50 | /** 51 | * @return Address 52 | */ 53 | function setAddress2($value) 54 | { 55 | return $this->addParam($this->addressParameterPrefix.'Address2', $value); 56 | } 57 | 58 | function getAddress2() 59 | { 60 | return $this->getParam($this->addressParameterPrefix.'Address2'); 61 | } 62 | 63 | /** 64 | * @return Address 65 | */ 66 | function setCity($value) 67 | { 68 | return $this->addParam($this->addressParameterPrefix.'City', $value); 69 | } 70 | 71 | function getCity() 72 | { 73 | return $this->getParam($this->addressParameterPrefix.'City'); 74 | } 75 | 76 | /** 77 | * @return Address 78 | */ 79 | function setState($value) 80 | { 81 | return $this->addParam($this->addressParameterPrefix.'State', $value); 82 | } 83 | 84 | function getState() 85 | { 86 | return $this->getParam($this->addressParameterPrefix.'State'); 87 | } 88 | 89 | /** 90 | * @return Address 91 | */ 92 | function setCountry($value) 93 | { 94 | return $this->addParam($this->addressParameterPrefix.'Country', $value); 95 | } 96 | 97 | function getCountry() 98 | { 99 | return $this->getParam($this->addressParameterPrefix.'Country'); 100 | } 101 | 102 | /** 103 | * @return Address 104 | */ 105 | function setZipCode($value) 106 | { 107 | return $this->addParam($this->addressParameterPrefix.'ZipCode', $value); 108 | } 109 | 110 | function getZipCode() 111 | { 112 | return $this->getParam($this->addressParameterPrefix.'ZipCode'); 113 | } 114 | 115 | /** 116 | * @return Address 117 | */ 118 | function setPhone($value) 119 | { 120 | return $this->addParam($this->addressParameterPrefix.'Phone', $value); 121 | } 122 | 123 | function getPhone() 124 | { 125 | return $this->getParam($this->addressParameterPrefix.'Phone'); 126 | } 127 | 128 | /** 129 | * @return Address 130 | */ 131 | function setFax($value) 132 | { 133 | return $this->addParam($this->addressParameterPrefix.'Fax', $value); 134 | } 135 | 136 | function getFax() 137 | { 138 | return $this->getParam($this->addressParameterPrefix.'Fax'); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/Context.php: -------------------------------------------------------------------------------- 1 | $value) { 38 | $property = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $option)))); 39 | 40 | if (!property_exists($this, $property)) { 41 | throw new \InvalidArgumentException(sprintf('Option %s is not defined', $option)); 42 | } 43 | 44 | if ('hashingMethod' === $property && !in_array($value, $this->validHashingMethods)) { 45 | throw new InvalidHashingMethodException( 46 | sprintf('Valid hashing methods are: %s; provided value: %s.', 47 | implode(', ', $this->validHashingMethods), 48 | $value) 49 | ); 50 | } 51 | 52 | $this->{$property} = $value; 53 | } 54 | 55 | if (null === $this->messageFactory) { 56 | $this->messageFactory = new GuzzlePsrMessageFactory(); 57 | } 58 | } 59 | 60 | /** 61 | * @return string 62 | */ 63 | function getCustomerId() 64 | { 65 | return $this->customerId; 66 | } 67 | 68 | /** 69 | * @return string 70 | */ 71 | function getSecret() 72 | { 73 | return $this->secret; 74 | } 75 | 76 | /** 77 | * @return string 78 | */ 79 | function getLanguage() 80 | { 81 | return $this->language; 82 | } 83 | 84 | /** 85 | * @return string 86 | */ 87 | function getShopId() 88 | { 89 | return $this->shopId; 90 | } 91 | 92 | /** 93 | * @return string 94 | */ 95 | function getJavascriptScriptVersion() 96 | { 97 | return $this->javascriptScriptVersion; 98 | } 99 | 100 | /** 101 | * @return string 102 | */ 103 | function getUserAgent() 104 | { 105 | return $this->userAgent; 106 | } 107 | 108 | /** 109 | * @return string 110 | */ 111 | function getBackendPassword() 112 | { 113 | return $this->backendPassword; 114 | } 115 | 116 | /** 117 | * @return MessageFactory 118 | */ 119 | function getMessageFactory() 120 | { 121 | return $this->messageFactory; 122 | } 123 | 124 | /** 125 | * @return string 126 | */ 127 | public function getHashingMethod() 128 | { 129 | return $this->hashingMethod; 130 | } 131 | 132 | /** 133 | * @return string 134 | */ 135 | function serialize() 136 | { 137 | return serialize(get_object_vars($this)); 138 | } 139 | 140 | /** 141 | * @return Context 142 | */ 143 | function unserialize($data) 144 | { 145 | foreach (unserialize($data) as $property => $value) { 146 | $this->{$property} = $value; 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/Model/Common/BasketItem.php: -------------------------------------------------------------------------------- 1 | addParam('articleNumber', $articleNumber); 18 | } 19 | 20 | /** 21 | * @return string 22 | */ 23 | function getArticleNumber() 24 | { 25 | return $this->getParam('articleNumber'); 26 | } 27 | 28 | /** 29 | * Set the item's name 30 | * 31 | * @param string $name 32 | * @return BasketItem 33 | */ 34 | function setName($name) 35 | { 36 | return $this->addParam('name', $name); 37 | } 38 | 39 | /** 40 | * @return string 41 | */ 42 | function getName() 43 | { 44 | return $this->getParam('name'); 45 | } 46 | 47 | /** 48 | * Set the item description, typically a product name 49 | * 50 | * @param string $description 51 | * @return BasketItem 52 | */ 53 | function setDescription($description) 54 | { 55 | return $this->addParam('description', $description); 56 | } 57 | 58 | /** 59 | * @return string 60 | */ 61 | function getDescription() 62 | { 63 | return $this->getParam('description'); 64 | } 65 | 66 | /** 67 | * Set item quantity 68 | * 69 | * @param int $quantity 70 | * @return BasketItem 71 | */ 72 | function setQuantity($quantity) 73 | { 74 | return $this->addParam('quantity', $quantity); 75 | } 76 | 77 | /** 78 | * @return int 79 | */ 80 | function getQuantity() 81 | { 82 | return $this->getParam('quantity'); 83 | } 84 | 85 | /** 86 | * Set item tax amount as string, formatted as float, e.g. "2.50" 87 | * 88 | * @param string $amount 89 | * @return BasketItem 90 | */ 91 | function setUnitTaxAmount($amount) 92 | { 93 | return $this->addParam('unitTaxAmount', $amount); 94 | } 95 | 96 | /** 97 | * @return string 98 | */ 99 | function getUnitTaxAmount() 100 | { 101 | return $this->getParam('unitTaxAmount'); 102 | } 103 | 104 | /** 105 | * Set item tax rate as string, formatted as float, e.g. "25" 106 | * 107 | * @param string $rate 108 | * @return BasketItem 109 | */ 110 | function setUnitTaxRate($rate) 111 | { 112 | return $this->addParam('unitTaxRate', $rate); 113 | } 114 | 115 | /** 116 | * @return string 117 | */ 118 | function getUnitTaxRate() 119 | { 120 | return $this->getParam('unitTaxRate'); 121 | } 122 | 123 | /** 124 | * Set item gross amount as string, formatted as float, e.g. "12.50" 125 | * 126 | * @param string $amount 127 | * @return BasketItem 128 | */ 129 | function setUnitGrossAmount($amount) 130 | { 131 | return $this->addParam('unitGrossAmount', $amount); 132 | } 133 | 134 | /** 135 | * @return string 136 | */ 137 | function getUnitGrossAmount() 138 | { 139 | return $this->getParam('unitGrossAmount'); 140 | } 141 | 142 | /** 143 | * Set item net amount as string, formatted as float, e.g. "10.00" 144 | * 145 | * @param string $amount 146 | * @return BasketItem 147 | */ 148 | function setUnitNetAmount($amount) 149 | { 150 | return $this->addParam('unitNetAmount', $amount); 151 | } 152 | 153 | /** 154 | * @return string 155 | */ 156 | function getUnitNetAmount() 157 | { 158 | return $this->getParam('unitNetAmount'); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/Response/WirecardResponse.php: -------------------------------------------------------------------------------- 1 | getBody()); 17 | 18 | $wirecardResponse = new static; 19 | $wirecardResponse->resultClass = $resultClass; 20 | 21 | static::parseResponseParameters($wirecardResponse, $responseParameters); 22 | 23 | return $wirecardResponse; 24 | } 25 | 26 | private static function parseResponseParameters(WirecardResponse $wirecardResponse, array $parameters) 27 | { 28 | foreach ($parameters as $param => $value) { 29 | if (strpos($param, '.', 0) !== false) { 30 | $params = &$wirecardResponse->parameters; 31 | $parts = explode('.', $param); 32 | 33 | while (count($parts) > 1) { 34 | $key = array_shift($parts); 35 | if (empty($params[$key])) { 36 | $params[$key] = []; 37 | } 38 | $params = &$params[$key]; 39 | } 40 | 41 | $key = reset($parts); 42 | $params[$key] = $value; 43 | } else { 44 | $wirecardResponse->parameters[$param] = $value; 45 | } 46 | } 47 | } 48 | 49 | /** 50 | * Parse a query string into an associative array. 51 | * 52 | * If multiple values are found for the same key, the value of that key 53 | * value pair will become an array. This function does not parse nested 54 | * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will 55 | * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']). 56 | * 57 | * @param string $str Query string to parse 58 | * @param bool|string $urlEncoding How the query string is encoded 59 | * 60 | * @return array 61 | */ 62 | private static function parseQuery($str, $urlEncoding = true) 63 | { 64 | $result = []; 65 | if ($str === '') { 66 | return $result; 67 | } 68 | if ($urlEncoding === true) { 69 | $decoder = function ($value) { 70 | return rawurldecode(str_replace('+', ' ', $value)); 71 | }; 72 | } elseif ($urlEncoding == PHP_QUERY_RFC3986) { 73 | $decoder = 'rawurldecode'; 74 | } elseif ($urlEncoding == PHP_QUERY_RFC1738) { 75 | $decoder = 'urldecode'; 76 | } else { 77 | $decoder = function ($str) { return $str; }; 78 | } 79 | foreach (explode('&', $str) as $kvp) { 80 | $parts = explode('=', $kvp, 2); 81 | $key = $decoder($parts[0]); 82 | $value = isset($parts[1]) ? $decoder($parts[1]) : null; 83 | if (!isset($result[$key])) { 84 | $result[$key] = $value; 85 | } else { 86 | if (!is_array($result[$key])) { 87 | $result[$key] = [$result[$key]]; 88 | } 89 | $result[$key][] = $value; 90 | } 91 | } 92 | return $result; 93 | } 94 | 95 | function toObject() 96 | { 97 | if ($this->hasErrors()) { 98 | return; 99 | } 100 | 101 | if (null === $this->resultClass) { 102 | return; 103 | } 104 | 105 | $class = $this->resultClass; 106 | return $class::fromParameters($this->parameters); 107 | } 108 | 109 | function toArray() 110 | { 111 | return $this->parameters; 112 | } 113 | 114 | function hasErrors() 115 | { 116 | return isset($this->parameters['errors']) && (int) $this->parameters['errors'] > 0; 117 | } 118 | 119 | function getErrors() 120 | { 121 | if (!$this->hasErrors()) { 122 | return []; 123 | } 124 | 125 | return $this->parameters['error']; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Request/Seamless/Backend/TransferFundRequest.php: -------------------------------------------------------------------------------- 1 | getRawParameters(); 18 | 19 | $fingerprintOrder = array_merge( 20 | ['customerId', 'shopId', 'password', 'secret', 'language'], 21 | $this->fingerprintOrder 22 | ); 23 | 24 | $requiredParameters = array_merge( 25 | ['customerId', 'requestFingerprint', 'password', 'language'], 26 | $this->requiredParameters 27 | ); 28 | 29 | switch ($this->getParam('fundTransferType')) { 30 | case FundTransferType::EXISTINGORDER: 31 | $fingerprintOrder[] = 'sourceOrderNumber'; 32 | $requiredParameters[] = 'sourceOrderNumber'; 33 | break; 34 | case FundTransferType::MONETA: 35 | $fingerprintOrder[] = 'consumerWalletId'; 36 | $requiredParameters[] = 'consumerWalletId'; 37 | break; 38 | case FundTransferType::SEPA_CT: 39 | $fingerprintOrder[] = 'bankAccountOwner'; 40 | $fingerprintOrder[] = 'bankBic'; 41 | $fingerprintOrder[] = 'bankAccountIban'; 42 | $requiredParameters[] = 'bankAccountOwner'; 43 | $requiredParameters[] = 'bankBic'; 44 | $requiredParameters[] = 'bankAccountIban'; 45 | break; 46 | case FundTransferType::SKRILLWALLET: 47 | $fingerprintOrder[] = 'consumerEmail'; 48 | $requiredParameters[] = 'consumerEmail'; 49 | $requiredParameters[] = 'customerStatement'; 50 | break; 51 | } 52 | 53 | $params['requestFingerprint'] = Fingerprint::fromParameters($params) 54 | ->setContext($this->getContext()) 55 | ->setFingerprintOrder($fingerprintOrder); 56 | $this->assertParametersAreValid($params, $requiredParameters); 57 | 58 | return $params; 59 | } 60 | 61 | /** 62 | * ID of the order 63 | * 64 | * @param string $orderNumber 65 | * @return RefundRequest 66 | */ 67 | function setOrderNumber($orderNumber) 68 | { 69 | return $this->addParam('orderNumber', $orderNumber); 70 | } 71 | 72 | function setAmount($amount) 73 | { 74 | return $this->addParam('amount', $amount); 75 | } 76 | 77 | function setCurrency($currency) 78 | { 79 | return $this->addParam('currency', $currency); 80 | } 81 | 82 | function setCreditNumber($creditNumber) 83 | { 84 | return $this->addParam('creditNumber', $creditNumber); 85 | } 86 | 87 | function setOrderDescription($orderDescription) 88 | { 89 | return $this->addParam('orderDescription', $orderDescription); 90 | } 91 | 92 | function setOrderReference($orderReference) 93 | { 94 | return $this->addParam('orderReference', $orderReference); 95 | } 96 | 97 | function setCustomerStatement($customerStatement) 98 | { 99 | return $this->addParam('customerStatement', $customerStatement); 100 | } 101 | 102 | function setFundTransferType($fundTransferType) 103 | { 104 | return $this->addParam('fundTransferType', $fundTransferType); 105 | } 106 | 107 | function setConsumerEmail($consumerEmail) 108 | { 109 | return $this->addParam('consumerEmail', $consumerEmail); 110 | } 111 | 112 | function setBankBic($bankBic) 113 | { 114 | return $this->addParam('bankBic', $bankBic); 115 | } 116 | 117 | function setBankAccountOwner($bankAccountOwner) 118 | { 119 | return $this->addParam('bankAccountOwner', $bankAccountOwner); 120 | } 121 | 122 | function setBankAccountIban($bankAccountIban) 123 | { 124 | return $this->addParam('bankAccountIban', $bankAccountIban); 125 | } 126 | 127 | function setConsumerWalletId($consumerWalletId) 128 | { 129 | return $this->addParam('consumerWalletId', $consumerWalletId); 130 | } 131 | 132 | function setSourceOrderNumber($sourceOrderNumber) 133 | { 134 | return $this->addParam('sourceOrderNumber', $sourceOrderNumber); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/Request/CheckoutPage/Backend/TransferFundRequest.php: -------------------------------------------------------------------------------- 1 | getRawParameters(); 18 | 19 | $fingerprintOrder = array_merge( 20 | ['customerId', 'shopId', 'password', 'secret', 'language'], 21 | $this->fingerprintOrder 22 | ); 23 | 24 | $requiredParameters = array_merge( 25 | ['customerId', 'requestFingerprint', 'password', 'language'], 26 | $this->requiredParameters 27 | ); 28 | 29 | switch ($this->getParam('fundTransferType')) { 30 | case FundTransferType::EXISTINGORDER: 31 | $fingerprintOrder[] = 'sourceOrderNumber'; 32 | $requiredParameters[] = 'sourceOrderNumber'; 33 | break; 34 | case FundTransferType::MONETA: 35 | $fingerprintOrder[] = 'consumerWalletId'; 36 | $requiredParameters[] = 'consumerWalletId'; 37 | break; 38 | case FundTransferType::SEPA_CT: 39 | $fingerprintOrder[] = 'bankAccountOwner'; 40 | $fingerprintOrder[] = 'bankBic'; 41 | $fingerprintOrder[] = 'bankAccountIban'; 42 | $requiredParameters[] = 'bankAccountOwner'; 43 | $requiredParameters[] = 'bankBic'; 44 | $requiredParameters[] = 'bankAccountIban'; 45 | break; 46 | case FundTransferType::SKRILLWALLET: 47 | $fingerprintOrder[] = 'consumerEmail'; 48 | $requiredParameters[] = 'consumerEmail'; 49 | $requiredParameters[] = 'customerStatement'; 50 | break; 51 | } 52 | 53 | $params['requestFingerprint'] = Fingerprint::fromParameters($params) 54 | ->setContext($this->getContext()) 55 | ->setFingerprintOrder($fingerprintOrder); 56 | $this->assertParametersAreValid($params, $requiredParameters); 57 | 58 | return $params; 59 | } 60 | 61 | /** 62 | * ID of the order 63 | * 64 | * @param string $orderNumber 65 | * @return RefundRequest 66 | */ 67 | function setOrderNumber($orderNumber) 68 | { 69 | return $this->addParam('orderNumber', $orderNumber); 70 | } 71 | 72 | function setAmount($amount) 73 | { 74 | return $this->addParam('amount', $amount); 75 | } 76 | 77 | function setCurrency($currency) 78 | { 79 | return $this->addParam('currency', $currency); 80 | } 81 | 82 | function setCreditNumber($creditNumber) 83 | { 84 | return $this->addParam('creditNumber', $creditNumber); 85 | } 86 | 87 | function setOrderDescription($orderDescription) 88 | { 89 | return $this->addParam('orderDescription', $orderDescription); 90 | } 91 | 92 | function setOrderReference($orderReference) 93 | { 94 | return $this->addParam('orderReference', $orderReference); 95 | } 96 | 97 | function setCustomerStatement($customerStatement) 98 | { 99 | return $this->addParam('customerStatement', $customerStatement); 100 | } 101 | 102 | function setFundTransferType($fundTransferType) 103 | { 104 | return $this->addParam('fundTransferType', $fundTransferType); 105 | } 106 | 107 | function setConsumerEmail($consumerEmail) 108 | { 109 | return $this->addParam('consumerEmail', $consumerEmail); 110 | } 111 | 112 | function setBankBic($bankBic) 113 | { 114 | return $this->addParam('bankBic', $bankBic); 115 | } 116 | 117 | function setBankAccountOwner($bankAccountOwner) 118 | { 119 | return $this->addParam('bankAccountOwner', $bankAccountOwner); 120 | } 121 | 122 | function setBankAccountIban($bankAccountIban) 123 | { 124 | return $this->addParam('bankAccountIban', $bankAccountIban); 125 | } 126 | 127 | function setConsumerWalletId($consumerWalletId) 128 | { 129 | return $this->addParam('consumerWalletId', $consumerWalletId); 130 | } 131 | 132 | function setSourceOrderNumber($sourceOrderNumber) 133 | { 134 | return $this->addParam('sourceOrderNumber', $sourceOrderNumber); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/Request/AbstractWirecardRequest.php: -------------------------------------------------------------------------------- 1 | setContext($context); 29 | } 30 | } 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | function getEndpoint() 36 | { 37 | return $this->endpoint; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | function setEndpoint($endpoint) 44 | { 45 | return $this->endpoint = $endpoint; 46 | } 47 | 48 | /** 49 | * Converts the request to a PSR-7 RequestInterface 50 | * 51 | * @return \Psr\Http\Message\RequestInterface 52 | */ 53 | function createHttpRequest() 54 | { 55 | $headers = [ 56 | 'User-Agent' => $this->getContext()->getUserAgent(), 57 | 'Content-Type' => 'application/x-www-form-urlencoded' 58 | ]; 59 | 60 | $body = $this->buildQuery($this->getRequestParameters()); 61 | 62 | return $this->getContext()->getMessageFactory()->createRequest( 63 | 'POST', 64 | $this->getEndpoint(), 65 | $headers, 66 | $body 67 | ); 68 | 69 | $httpRequest = new Request( 70 | 'POST', 71 | $this->getEndpoint(), 72 | $headers, 73 | $body 74 | ); 75 | 76 | return $httpRequest; 77 | } 78 | 79 | /** 80 | * Converts the PSR-7 ResponseInterface to a Wirecard Response 81 | * 82 | * @param \Psr\Http\Message\ResponseInterface $response 83 | * @return WirecardResponse 84 | */ 85 | function createResponse(\Psr\Http\Message\ResponseInterface $response) 86 | { 87 | return WirecardResponse::fromHttpResponse( 88 | $response, 89 | $this->resultClass 90 | ); 91 | } 92 | 93 | /** 94 | * {@inheritDoc} 95 | */ 96 | function setContext(Context $context) 97 | { 98 | $this->context = $context; 99 | return $this; 100 | } 101 | 102 | /** 103 | * {@inheritDoc} 104 | */ 105 | function getContext() 106 | { 107 | return $this->context; 108 | } 109 | 110 | /** 111 | * {@inheritDoc} 112 | */ 113 | function addParam($param, $value) 114 | { 115 | $this->parameters[$param] = $value; 116 | return $this; 117 | } 118 | 119 | /** 120 | * {@inheritDoc} 121 | */ 122 | function getParam($param) 123 | { 124 | if (!array_key_exists($param, $this->parameters)) { 125 | return; 126 | } 127 | 128 | return $this->parameters[$param]; 129 | } 130 | 131 | /** 132 | * Returns the request parameters without calculated fingerprint 133 | * 134 | * Override this method in your subclasses to modify parameters before they are 135 | * passed to the PSR-7 request message. 136 | */ 137 | protected function getRawParameters() 138 | { 139 | $params = $this->parameters; 140 | $context = $this->getContext(); 141 | 142 | if (empty($params['customerId'])) { 143 | $params['customerId'] = $context->getCustomerId(); 144 | } 145 | 146 | if ($context->getShopId() and empty($params['shopId'])) { 147 | $params['shopId'] = $context->getShopId(); 148 | } 149 | 150 | return $params; 151 | } 152 | 153 | /** 154 | * {@inheritDoc} 155 | */ 156 | function getRequestParameters() 157 | { 158 | $params = $this->getRawParameters(); 159 | 160 | $params['requestFingerprint'] = Fingerprint::fromParameters($params) 161 | ->setContext($this->getContext()) 162 | ->setFingerprintOrder(array_merge(['customerId', 'shopId'], $this->fingerprintOrder, ['secret'])); 163 | 164 | $this->assertParametersAreValid($params, array_merge(['customerId', 'requestFingerprint'], $this->requiredParameters)); 165 | 166 | return $params; 167 | } 168 | 169 | /** 170 | * Validates that all required parameters are set, otherwise throws an exception 171 | * 172 | * @param array $parameters 173 | * @param array $requiredParameters List of required parameters 174 | * @throws RequiredParameterMissingException 175 | */ 176 | protected function assertParametersAreValid(array $parameters, array $requiredParameters) 177 | { 178 | foreach ($requiredParameters as $parameter) { 179 | if (empty($parameters[$parameter])) { 180 | throw RequiredParameterMissingException::withParameter($parameter); 181 | } 182 | } 183 | } 184 | 185 | /** 186 | * {@inheritDoc} 187 | */ 188 | function serialize() 189 | { 190 | return serialize([ 191 | 'context' => $this->context, 192 | 'parameters' => $this->parameters 193 | ]); 194 | } 195 | 196 | /** 197 | * {@inheritDoc} 198 | */ 199 | function unserialize($data) 200 | { 201 | $data = unserialize($data); 202 | 203 | $this->context = $data['context']; 204 | $this->parameters = $data['parameters']; 205 | } 206 | 207 | /** 208 | * Build a query string from an array of key value pairs. 209 | * 210 | * This function can use the return value of parseQuery() to build a query 211 | * string. This function does not modify the provided keys when an array is 212 | * encountered (like http_build_query would). 213 | * 214 | * @param array $params Query string parameters. 215 | * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986 216 | * to encode using RFC3986, or PHP_QUERY_RFC1738 217 | * to encode using RFC1738. 218 | * @return string 219 | */ 220 | protected function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986) 221 | { 222 | if (!$params) { 223 | return ''; 224 | } 225 | if ($encoding === false) { 226 | $encoder = function ($str) { return $str; }; 227 | } elseif ($encoding == PHP_QUERY_RFC3986) { 228 | $encoder = 'rawurlencode'; 229 | } elseif ($encoding == PHP_QUERY_RFC1738) { 230 | $encoder = 'urlencode'; 231 | } else { 232 | throw new \InvalidArgumentException('Invalid type'); 233 | } 234 | $qs = ''; 235 | foreach ($params as $k => $v) { 236 | $k = $encoder($k); 237 | if (!is_array($v)) { 238 | $qs .= $k; 239 | if ($v !== null) { 240 | $qs .= '=' . $encoder($v); 241 | } 242 | $qs .= '&'; 243 | } else { 244 | foreach ($v as $vv) { 245 | $qs .= $k; 246 | if ($vv !== null) { 247 | $qs .= '=' . $encoder($vv); 248 | } 249 | $qs .= '&'; 250 | } 251 | } 252 | } 253 | return $qs ? (string) substr($qs, 0, -1) : ''; 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/Request/AbstractPaymentRequest.php: -------------------------------------------------------------------------------- 1 | setBasket($basket) 52 | ->setAmount($basket->getAmount()) 53 | ->setCurrency($basket->getCurrency()); 54 | } 55 | 56 | /** 57 | * @return AbstractPaymentRequest 58 | */ 59 | function setPaymentType($value) 60 | { 61 | return $this->addParam('paymentType', $value); 62 | } 63 | 64 | /** 65 | * @param string $value 66 | * @return AbstractPaymentRequest 67 | */ 68 | function setAmount($value) 69 | { 70 | return $this->addParam('amount', $value); 71 | } 72 | 73 | /** 74 | * @param string $value 75 | * @return AbstractPaymentRequest 76 | */ 77 | function setCurrency($value) 78 | { 79 | return $this->addParam('currency', $value); 80 | } 81 | 82 | /** 83 | * @param string $value 84 | * @return AbstractPaymentRequest 85 | */ 86 | function setOrderDescription($value) 87 | { 88 | return $this->addParam('orderDescription', $value); 89 | } 90 | 91 | /** 92 | * @param string $value 93 | * @return AbstractPaymentRequest 94 | */ 95 | function setSuccessUrl($value) 96 | { 97 | return $this->addParam('successUrl', $value); 98 | } 99 | 100 | /** 101 | * @return AbstractPaymentRequest 102 | */ 103 | function setCancelUrl($value) 104 | { 105 | return $this->addParam('cancelUrl', $value); 106 | } 107 | 108 | /** 109 | * @return AbstractPaymentRequest 110 | */ 111 | function setFailureUrl($value) 112 | { 113 | return $this->addParam('failureUrl', $value); 114 | } 115 | 116 | /** 117 | * @return AbstractPaymentRequest 118 | */ 119 | function setServiceUrl($value) 120 | { 121 | return $this->addParam('serviceUrl', $value); 122 | } 123 | 124 | /** 125 | * @return AbstractPaymentRequest 126 | */ 127 | function setConfirmUrl($value) 128 | { 129 | return $this->addParam('confirmUrl', $value); 130 | } 131 | 132 | /** 133 | * @return AbstractPaymentRequest 134 | */ 135 | function setConsumerIpAddress($value) 136 | { 137 | return $this->addParam('consumerIpAddress', $value); 138 | } 139 | 140 | /** 141 | * @return AbstractPaymentRequest 142 | */ 143 | function setConsumerUserAgent($value) 144 | { 145 | return $this->addParam('consumerUserAgent', $value); 146 | } 147 | 148 | /** 149 | * @return AbstractPaymentRequest 150 | */ 151 | function setPendingUrl($value) 152 | { 153 | return $this->addParam('pendingUrl', $value); 154 | } 155 | 156 | /** 157 | * @return AbstractPaymentRequest 158 | */ 159 | function setImageUrl($value) 160 | { 161 | return $this->addParam('imageUrl', $value); 162 | } 163 | 164 | /** 165 | * @return AbstractPaymentRequest 166 | */ 167 | function setNoScriptInfoUrl($value) 168 | { 169 | return $this->addParam('noScriptInfoUrl', $value); 170 | } 171 | 172 | /** 173 | * @return AbstractPaymentRequest 174 | */ 175 | function setOrderNumber($value) 176 | { 177 | return $this->addParam('orderNumber', $value); 178 | } 179 | 180 | /** 181 | * @return AbstractPaymentRequest 182 | */ 183 | function setWindowName($value) 184 | { 185 | return $this->addParam('windowName', $value); 186 | } 187 | 188 | /** 189 | * @return AbstractPaymentRequest 190 | */ 191 | function setDuplicateRequestCheck($value) 192 | { 193 | if ($value) { 194 | return $this->addParam('duplicateRequestCheck', 'yes'); 195 | } 196 | return $this; 197 | } 198 | 199 | /** 200 | * @return AbstractPaymentRequest 201 | */ 202 | function setCustomerStatement($value) 203 | { 204 | return $this->addParam('customerStatement', $value); 205 | } 206 | 207 | /** 208 | * @return AbstractPaymentRequest 209 | */ 210 | function setOrderReference($value) 211 | { 212 | return $this->addParam('orderReference', $value); 213 | } 214 | 215 | /** 216 | * @return AbstractPaymentRequest 217 | */ 218 | function setTransactionIdentifier($value) 219 | { 220 | return $this->addParam('transactionIdentifier', $value); 221 | } 222 | 223 | /** 224 | * @return AbstractPaymentRequest 225 | */ 226 | function setFinancialInstitution($value) 227 | { 228 | return $this->addParam('financialInstitution', $value); 229 | } 230 | 231 | /** 232 | * @return AbstractPaymentRequest 233 | */ 234 | function setOrderIdent($value) 235 | { 236 | return $this->addParam('orderIdent', $value); 237 | } 238 | 239 | /** 240 | * @return AbstractPaymentRequest 241 | */ 242 | function setStorageId($value) 243 | { 244 | return $this->addParam('storageId', $value); 245 | } 246 | 247 | /** 248 | * @return AbstractPaymentRequest 249 | */ 250 | function setAutoDeposit($value) 251 | { 252 | return $this->addParam('autoDeposit', $value ? 'yes' : 'no'); 253 | } 254 | 255 | /** 256 | * @return AbstractPaymentRequest 257 | */ 258 | function setConfirmMail($value) 259 | { 260 | return $this->addParam('confirmMail', $value); 261 | } 262 | 263 | /** 264 | * @return AbstractPaymentRequest 265 | */ 266 | function setRiskSuppress($value) 267 | { 268 | return $this->addParam('riskSuppress', $value ? 'yes' : 'no'); 269 | } 270 | 271 | /** 272 | * @return AbstractPaymentRequest 273 | */ 274 | function setRiskConfigAlias($value) 275 | { 276 | return $this->addParam('riskConfigAlias', $value); 277 | } 278 | 279 | /** 280 | * @return AbstractPaymentRequest 281 | */ 282 | function setConsumerShippingInformation(ShippingInformation $info) 283 | { 284 | foreach ($info->toArray() as $param => $value) { 285 | $this->addParam($param, $value); 286 | } 287 | 288 | return $this; 289 | } 290 | 291 | /** 292 | * @return AbstractPaymentRequest 293 | */ 294 | function setConsumerBillingInformation(BillingInformation $info) 295 | { 296 | foreach ($info->toArray() as $param => $value) { 297 | $this->addParam($param, $value); 298 | } 299 | 300 | return $this; 301 | } 302 | 303 | /** 304 | * Adds the basket to the payment, required for some payment methods 305 | * 306 | * @param Basket $basket 307 | * @return InitPaymentRequest 308 | */ 309 | function setBasket(Basket $basket) 310 | { 311 | foreach ($basket->toArray() as $param => $value) { 312 | $this->addParam($param, $value); 313 | } 314 | 315 | return $this; 316 | } 317 | 318 | protected function getRawParameters() 319 | { 320 | $params = parent::getRawParameters(); 321 | 322 | if (empty($params['language'])) { 323 | $params['language'] = $this->getContext()->getLanguage(); 324 | } 325 | 326 | return $params; 327 | } 328 | 329 | function getRequestParameters() 330 | { 331 | $params = $this->getRawParameters(); 332 | 333 | $requestFingerprintOrder = array_merge(array_keys($params), ['requestFingerprintOrder', 'secret']); 334 | $params['requestFingerprintOrder'] = join(',', $requestFingerprintOrder); 335 | 336 | $params['requestFingerprint'] = Fingerprint::fromParameters($params) 337 | ->setContext($this->getContext()) 338 | ->setFingerprintOrder($requestFingerprintOrder); 339 | 340 | $this->assertParametersAreValid($params, array_merge(['customerId', 'requestFingerprint'], $this->requiredParameters)); 341 | 342 | return $params; 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ IMPORTANT 2 | 3 | Starting with September 30, 2020 the methods used by this SDK are no longer supported by Wirecard. 4 | 5 | This repository is therefore archived and is no longer maintained. You're free to fork this code under the terms of the license. 6 | 7 | # Wirecard 8 | 9 | [![Latest Version on Packagist][ico-version]][link-packagist] 10 | [![Software License][ico-license]](LICENSE.md) 11 | [![Build Status][ico-travis]][link-travis] 12 | [![Total Downloads][ico-downloads]][link-downloads] 13 | 14 | An unofficial SDK for making payments with [Wirecard](http://wirecard.at). 15 | 16 | For general information about making payments with Wirecard in your application, visit the [Wirecard Integration Wiki][Integration Wiki]. 17 | 18 | Get an account for the Integration Wiki, by signing up on the Wiki’s signup page for free. 19 | 20 | [Integration Wiki]: https://guides.wirecard.at/ 21 | 22 | SDK Coverage: 23 | 24 | - [x] Wirecard Checkout Page 25 | - [x] Wirecard Seamless Checkout 26 | - [x] Seamless Backend operations 27 | - [x] Checkout Page Backend operations 28 | 29 | ## Install 30 | 31 | Via Composer in your project directory: 32 | 33 | ``` bash 34 | $ composer require hochstrasserio/wirecard 35 | ``` 36 | 37 | ## Usage 38 | 39 | ### Setup 40 | 41 | This library does not ship with functionality to send HTTP requests over the wire. You need to get a library to do this for you. Any PSR-7 compliant library will work, like [Guzzle v6+][guzzle6] or the [Ivory HTTP Adapters library][ivory]. 42 | 43 | $ composer require 'guzzlehttp/guzzle:^6.0.0' 44 | 45 | [guzzle6]: http://guzzle.readthedocs.org/en/latest/ 46 | [ivory]: http://github.com/egeloen/ivory-http-adapter 47 | 48 | Then, configure a Wirecard *Context* with your Customer ID, Customer secret, and optionally your Shop ID. You should have received both by Wirecard. Demo or Test credentials are also available in the [Integration Wiki][]. 49 | 50 | ``` php 51 | 'D200001', 58 | 'secret' => 'B8AKTPWBRMNBV455FG6M2DANE99WU2', 59 | 'language' => 'de', 60 | 'shop_id' => 'qmore', 61 | 'hashing_method' => Context::HASHING_HMAC, 62 | ]); 63 | ``` 64 | 65 | The *Context* has some more options that you can pass to the constructor: 66 | 67 | 1. `customer_id`: Your customer ID, which you got from Wirecard or the [Integration Wiki][] 68 | 2. `secret`: Your customer secret, which you got from Wirecard or the [Integration Wiki][]. Do not share this with anyone 69 | 3. `language`: Language of Wirecard’s UIs and error messages 70 | 4. `shop_id` (Optional): Set this if one set of credentials is used for many shops (if Wirecard tells you to) 71 | 5. `javascript_script_version` (Optional): Enable [PCI DSS SAQ A compliance features](https://guides.wirecard.at/wcs:pci3_fallback) 72 | 6. `user_agent` (Optional): Library user agent used for HTTP requests, you can optionally set this to your site’s name 73 | 7. `hashing_method` (Optional): The used method for computing the fingerprint hash. If omitted, the old method `Context::HASHING_SHA` is used for compatibility reasons. New Wirecard customers should use `Context::HASHING_HMAC`, as it is the current Wirecard default. The demo customer still uses `Context::HASHING_SHA`, though. 74 | 75 | ### SDK Patterns 76 | 77 | #### Requests 78 | 79 | All requests are simple classes which implement the [WirecardRequestInterface](src/Request/WirecardRequestInterface.php) and can be constructed directly. Most classes have a specific named constructor, which starts with `with*`, e.g. `withBasket`, or `withOrderIdentAndReturnUrl`. These should be preferred over the simple constructor. 80 | 81 | #### Sending Requests 82 | 83 | Requests are converted to PSR-7 compatible requests with the 84 | `createHttpRequest` method. The context has to be set before. Then you can send the PSR-7 compatible request message with your HTTP client. The `createResponse` method converts any PSR-7 compatible response object to WirecardResponseInterface after you sent the request. 85 | 86 | ```php 87 | setContext($context); 93 | 94 | $httpResponse = $client->send($request->createHttpRequest()); 95 | $response = $request->createResponse($httpResponse); 96 | ``` 97 | 98 | It may seem a bit cumbersome, but it has the big benefit of freeing you of any imposed dependency on a particular version of a HTTP client library, like Guzzle, or Buzz. You may use the client that suits you best, or offers you the best performance, which will always be better, faster, and have more features than anything this library could ever provide. Plus there’s little risk of dependencies of the SDK conflicting with your application’s. 99 | 100 | #### Using the WirecardHelper 101 | 102 | There’s a small utility included, the `WirecardHelper` which saves you a couple of lines every time you make a request. Initialize with the context and send the request with a configured client. 103 | 104 | You pass it two things: the Wirecard context and a function to send a `Psr\Http\Message\RequestInterface` over the wire which returns a `Psr\Http\Message\ResponseInterface`. 105 | 106 | ```php 107 | send($request); 116 | }); 117 | 118 | // Sets the context, converts the request and makes the http response to a 119 | // WirecardResponseInterface 120 | $response = $helper->send(InitDataStorageRequest::withOrderIdentAndReturnUrl( 121 | '1234', 'http://example.com' 122 | )); 123 | 124 | $dataStorage = $response->toObject(); 125 | ``` 126 | 127 | Note, that the helper sends requests only synchronously. If you want async requests you have to use your HTTP library directly. 128 | 129 | #### Required Parameters 130 | 131 | Requests know about their required parameters. If a known required parameter is missing, then a [RequiredParameterMissingException](src/Exception/RequiredParameterMissingException.php) is thrown. 132 | 133 | #### Responses 134 | 135 | All responses implement the [WirecardResponseInterface](src/Response/WirecardResponseInterface.php). 136 | 137 | ##### Getting Results 138 | 139 | Results are retrieved by using the `toObject` or `toArray` methods. The `toObject` method is usually used. This method returns a model class, which has methods to conveniently retrieve returned values. This methods are defined in the model class, so your IDE should be able to suggest them to you. 140 | 141 | The `toArray` method returns the raw response parameters returned by the request. This is useful for debugging and checking with the official documentation. 142 | 143 | ```php 144 | toArray(); 147 | var_dump($a['redirectUrl']); 148 | 149 | $b = $response->toObject(); 150 | var_dump($b->getRedirectUrl()); 151 | ``` 152 | 153 | ##### Errors 154 | 155 | Every response has the `hasErrors` method, which checks for any returned errors. All returned errors can be retrieved as array by using `getErrors` on the response object. 156 | 157 | ```php 158 | hasErrors()) { 161 | foreach ($response->getErrors() as $error) { 162 | echo $error, "
"; 163 | } 164 | } 165 | ``` 166 | 167 | ### Wirecard Checkout Page 168 | 169 | With Wirecard Checkout Page you don’t handle the UI for selecting the payment type or storing the credit card data. The InitCheckoutPageRequest is also an exception in another way: it can’t be sent with the client, you have to use a HTML form, which has to be submitted by the customers themselves. 170 | 171 | The InitCheckoutPageRequest takes the same parameters and is initialized the same way as the InitPaymentRequest from Seamless Checkout. 172 | 173 | The only differences are: 174 | 175 | * `confirmUrl` is not required 176 | * `paymentType` does not have to be set in the request object, can be set in the form 177 | 178 | [Example:](example/checkout-page/index.php) 179 | 180 | ```php 181 | 'D200001', 'secret' => 'B8AKTPWBRMNBV455FG6M2DANE99WU2', 'language' => 'de']); 188 | $request = InitCheckoutPageRequest::with() 189 | ->setPaymentType(PaymentType::Select) 190 | ->setContext($context) 191 | ->setAmount('33.00') 192 | ->setCurrency('EUR') 193 | ->setOrderDescription("12345") 194 | ->setSuccessUrl("http://localhost:8001/") 195 | ->setFailureUrl("http://localhost") 196 | ->setCancelUrl("http://localhost") 197 | ->setServiceUrl("http://localhost") 198 | ; 199 | ?> 200 | 201 |
202 | getRequestParameters() as $param => $value): ?> 203 | 204 | 205 | 206 | 207 |
208 | ``` 209 | 210 | Another major difference of Checkout Page is, that the `successUrl` receives all payment response parameters as a POST request, just like the `confirmUrl`. The `confirmUrl` can additionally be set to receive the parameters independent of user actions, for you to record for reference. 211 | 212 | You can find out more about this here: [Receiving the Results of the Payment Process in your Online Shop](https://guides.wirecard.at/wcp:integration#receiving_the_payment_process_result) 213 | 214 | ### Wirecard Seamless Checkout 215 | 216 | With Wirecard Seamless Checkout, your customer uses your own custom page to select the payment methods which you did enable for your site. How this UI looks and works is completely up to you. 217 | 218 | There are a couple of requests that you have to make: 219 | 220 | 1. `InitDataStorageRequest`: Usually you want not to deal with PCI compliance yourself and want Wirecard to take care of it. This request initializes a data storage, which is on Wirecard’s servers and securely stores the customer’s credit card data for you. The only way to store data is via an JavaScript library. The `InitDataStorageRequest` returns the URL for including the library after a succcessful call. This is only necessary if you are taking credit card payments and has to be made before requesting the payment. 221 | 2. Optionally, `ReadDataStorageRequest`: You can use this request to display the credit card data, which the customer entered, with all sensitive information removed. You can use this to give your customer a last look at the entered payment data before making the payment. 222 | 3. `InitPaymentRequest`: Makes the payment and returns an URL. Redirect the customer to the URL to complete the requested payment. If this was successful, your site gets a POST request by Wirecard at the Confirm URL, which contains the payment details, like the transaction number. Finally the customer is then redirected back to your site. 223 | 224 | #### InitDataStorageRequest 225 | 226 | Response Model: [DataStorageInitResult](src/Model/Seamless/Frontend/DataStorageInitResult.php) 227 | 228 | Sets up the data storage and returns a URL to the JavaScript library and the storage ID. It’s only necessary to make this request when your customer intends to pay by credit card. The storage ID can be used to read masked data out of the data storage, and has to be passed to the `InitPaymentRequest` later on. 229 | 230 | To create the request use the `withOrderIdentAndReturnUrl` named constructor. The "order ident" should be a unique value for the checkout and the "return URL" passed as second argument is used for legacy browsers. 231 | 232 | ``` php 233 | setContext($context); 239 | 240 | $response = $request->createResponse($client->send($request->createHttpRequest())); 241 | 242 | // Store the storage ID for later usage with the payment request 243 | $_SESSION['wirecardDataStorageId'] = $response->toObject()->getStorageId(); 244 | 245 | var_dump($response->hasErrors()); 246 | var_dump($response->toObject()->getStorageId()); 247 | var_dump($response->toObject()->getJavascriptUrl()); 248 | ``` 249 | 250 | #### ReadDataStorageRequest 251 | 252 | Response Model: [DataStorageReadResult](src/Model/Seamless/Frontend/DataStorageReadResult.php) 253 | 254 | Reads the data storage and returns an array of masked [customer data](src/Model/Seamless/Frontend/PaymentInformation.php). 255 | 256 | ``` php 257 | setContext($context); 263 | 264 | $response = $request->createResponse($client->send($request->createHttpRequest())); 265 | 266 | var_dump($response->hasErrors()); 267 | var_dump($response->toObject()->getStorageId()); 268 | 269 | foreach ($response->toObject()->getPaymentInformation() as $paymentInformation) { 270 | var_dump($paymentInformation->getMaskedPan()); 271 | } 272 | ``` 273 | 274 | #### Making a payment with InitPaymentRequest 275 | 276 | Response Model: [InitPaymentResult](src/Model/Seamless/Frontend/InitPaymentResult.php) 277 | 278 | Requests the payment and returns a redirect URL. Redirect your customer to this URL to finish the payment. 279 | 280 | ##### Required payment parameters 281 | 282 | * `amount`: Payment amount in the currency’s base units, e.g. `12.00`. Set from the basket when `withBasket` is used. Set as string to avoid rounding errors, which can happen with floats. 283 | * `currency`: ISO Currency Code, e.g. `EUR`. Set from the basket when `withBasket` is used. 284 | * `paymentType` ([PaymentType](src/Model/Common/PaymentType.php)): The payment type, which was selected by your customer. You can use `PaymentType::isValid()` to validate the identifier of the requested payment type. 285 | * `orderDescription`: Description of your order, can be e.g. structured data about the order. 286 | * `successUrl`: If the payment was successful, then the customer gets redirected by Wirecard to this URL. 287 | * `failureUrl`: If there was some kind of failure during confirmation of the checkout, then the customer gets redirected by Wirecard to this URL. 288 | * `cancelUrl`: If the payment was cancelled during confirmation (e.g. at the PayPal screen), then the customer gets redirected by Wirecard to this URL. 289 | * `serviceUrl`: A page which lists your terms of service and contact information, usually your "Contact us" or "Imprint" page. 290 | * `confirmUrl`: An endpoint in your site, which receives detailed information about the payment via a POST request by Wirecard after the customer successfully confirmed the payment. Usually you send the order confirmation email at this endpoint. 291 | * `consumerUserAgent` and `consumerIpAddress`: For optional prevention of duplicate payments. 292 | 293 | These parameters can be either set with the `addParam` method on the request object, or with their respective `set*` method, e.g. `setSuccessUrl`. 294 | 295 | There are a lot more optional parameters for payment requests, to e.g. make recurring payments, set the statement which is displayed on the credit card bill, and more. Look at the [Documentation about Request Parameters](https://guides.wirecard.at/request_parameters) for more information. 296 | 297 | ##### Adding a Basket 298 | 299 | The payment request uses a [Basket](src/Model/Common/Basket.php) filled with [Basket Items](src/Model/Common/BasketItem.php) to show the customer’s products at the checkout screen of e.g. PayPal. You can also use this to easily set the amount and currency of your order. In most cases you should be able to infer the basket from your site’s own basket model. 300 | 301 | **Note:** If a basket is set on the payment request, Wirecard validates on the server if all prices of the basket items and the total amount add up correctly. Otherwise, Wirecard returns an error. 302 | 303 | ``` php 304 | setAmount('17.00'); 314 | $basket->setCurrency('EUR'); 315 | $basket->addItem((new BasketItem) 316 | ->setArticleNumber('A001') 317 | ->setDescription('Product A1') 318 | ->setQuantity(1) 319 | ->setUnitPrice('10.00') 320 | ->setTax('1.00') 321 | ); 322 | $basket->addItem((new BasketItem) 323 | ->setArticleNumber('SHIPPING') 324 | ->setDescription('Shipping') 325 | ->setQuantity(1) 326 | ->setUnitPrice('5.00') 327 | ->setTax('1.00') 328 | ); 329 | ``` 330 | 331 | ##### Adding Shipping and Billing Information 332 | 333 | [ShippingInformation]: src/Model/Common/ShippingInformation.php 334 | [BillingInformation]: src/Model/Common/BillingInformation.php 335 | 336 | Some payment types require shipping and billing information. The SDK provides [ShippingInformation][] and [BillingInformation][] classes to help you with that. 337 | 338 | ``` php 339 | setFirstname('Max') 346 | ->setLastname('Mustermann') 347 | ->setAddress1('Musterstraße') 348 | ->setAddress2('2') 349 | ->setZipCode('1234') 350 | ->setState('Lower Austria') 351 | ->setCity('Musterstadt') 352 | ->setCountry('AT') 353 | ->setPhone('+431231231234') 354 | ->setFax('+431231231234'); 355 | ``` 356 | 357 | If the customer’s billing information matches the shipping information, then the [BillingInformation][] class provides a named constructor for convenience. Otherwise the [BillingInformation][] class features the same methods as [ShippingInformation][]. 358 | 359 | ```php 360 | setConsumerEmail("max@mustermann.com"); 371 | $billingInformation->setConsumerBirthDate(new \DateTime("Sept 1 1970")); 372 | ``` 373 | 374 | Finally you can add the shipping and billing information to the request with the `setConsumerShippingInformation` and `setConsumerBillingInformation` methods. 375 | 376 | ##### Requesting the payment 377 | 378 | With our basket object in hand, we can now initialize the payment request: 379 | 380 | ``` php 381 | setPaymentType($_POST['paymentType']) 393 | ->setOrderDescription('Some test order') 394 | ->setSuccessUrl('http://example.com') 395 | ->setFailureUrl('http://example.com') 396 | ->setCancelUrl('http://example.com') 397 | ->setServiceUrl('http://example.com') 398 | // Your callback controller for handling the result of the payment, you will 399 | // receive a POST request at this URL 400 | ->setConfirmUrl('http://example.com') 401 | ->setConsumerShippingInformation($shippingInformation) 402 | ->setConsumerBillingInformation($billingInformation) 403 | ->setConsumerUserAgent($_SERVER['HTTP_USER_AGENT']) 404 | ->setConsumerIpAddress($_SERVER['REMOTE_IP']) 405 | ->setContext($context) 406 | ; 407 | 408 | // Set the data storage ID if the data storage was initialized 409 | if (isset($_SESSION['wirecardDataStorageId'])) { 410 | $request->setStorageId($_SESSION['wirecardDataStorageId']); 411 | } 412 | 413 | $response = $request->createResponse($client->send($request->createHttpRequest())); 414 | ``` 415 | 416 | Using the response model, you now can redirect customers to Wirecard’s payment confirmation flow. This flow will then connect your customers to their selected payment provider, e.g. PayPal or 3-D secure, where they’ll confirm the payment. 417 | 418 | ```php 419 | hasErrors()) { 422 | // Show errors in the UI 423 | } 424 | 425 | // Redirect if no errors happened 426 | header('Location: '.$response->toObject()->getRedirectUrl()); 427 | ``` 428 | 429 | ##### Handling response parameters 430 | 431 | Afterwards, Wirecard will send a POST request to the URL passed as confirmUrl with the response parameters of the payment request. These parameters contain the order number, and more. Store these parameters for reference. 432 | 433 | You can use the provided Fingerprint class to verify the supplied response fingerprint: 434 | 435 | ``` php 436 |