diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0bdbb24
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.idea/
+/build/
+phpunit.xml
+/vendor/
\ No newline at end of file
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
new file mode 100644
index 0000000..2299bfa
--- /dev/null
+++ b/.scrutinizer.yml
@@ -0,0 +1,15 @@
+# .scrutinizer.yml
+
+checks:
+ php:
+ code_rating: true
+ duplication: true
+
+build:
+ tests:
+ override:
+ -
+ command: 'phpunit --coverage-clover=some-file'
+ coverage:
+ file: 'some-file'
+ format: 'clover'
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8fc5c8b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,14 @@
+language: php
+php:
+ - 5.3
+ - 5.4
+ - 5.5
+ - 5.6
+ - 7.0
+
+notifications:
+ email:
+ - dieter@marlon.be
+
+before_script:
+ - composer install --dev
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7fba130
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Marlon BVBA
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..71a7bd8
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..0c0a563
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,42 @@
+{
+ "name": "ingenico/ogone-sdk-php-postfinance",
+ "description": "Ingenico SDK for PHP",
+ "version": "1.0.0",
+ "authors": [
+ {
+ "name": "Limegrow",
+ "email": "info@limegrow.com",
+ "homepage": "https://limegrow.com"
+ },
+ {
+ "name": "Marlon BVBA",
+ "email": "info@marlon.be",
+ "homepage": "https://www.marlon.be"
+ },
+ {
+ "name": "Nicolas Clavaud",
+ "email": "nicolas@lrqdo.fr",
+ "homepage": "https://github.com/nclavaud"
+ }
+ ],
+ "support": {
+ "email": "support.ecom@ingenico.com"
+ },
+ "require": {
+ "php": ">=7.0",
+ "ext-libxml": "*",
+ "ext-simplexml": "*",
+ "ext-intl": "*",
+ "monolog/monolog": "^1.24"
+ },
+ "require-dev" : {
+ "phpunit/phpunit": "^7",
+ "symfony/class-loader": "@stable"
+ },
+ "autoload": {
+ "psr-4": {
+ "Ogone\\": "lib/Ogone/",
+ "Ogone\\Tests\\": "tests/Ogone/Tests/"
+ }
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..94869a6
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,1546 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "cba35085e80fa226fc1755b3c4d8b867",
+ "packages": [
+ {
+ "name": "monolog/monolog",
+ "version": "1.24.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/monolog.git",
+ "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266",
+ "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "psr/log": "~1.0"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0.0"
+ },
+ "require-dev": {
+ "aws/aws-sdk-php": "^2.4.9 || ^3.0",
+ "doctrine/couchdb": "~1.0@dev",
+ "graylog2/gelf-php": "~1.0",
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "php-amqplib/php-amqplib": "~2.4",
+ "php-console/php-console": "^3.1.3",
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "2.3.0",
+ "ruflin/elastica": ">=0.90 <3.0",
+ "sentry/sentry": "^0.13",
+ "swiftmailer/swiftmailer": "^5.3|^6.0"
+ },
+ "suggest": {
+ "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+ "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
+ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+ "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
+ "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+ "php-console/php-console": "Allow sending log messages to Google Chrome",
+ "rollbar/rollbar": "Allow sending log messages to Rollbar",
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+ "sentry/sentry": "Allow sending log messages to a Sentry server"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Monolog\\": "src/Monolog"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+ "homepage": "http://github.com/Seldaek/monolog",
+ "keywords": [
+ "log",
+ "logging",
+ "psr-3"
+ ],
+ "time": "2018-11-05T09:00:11+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
+ "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "time": "2018-11-20T15:27:04+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+ "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "athletic/athletic": "~0.1.8",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpunit/phpunit": "^6.2.3",
+ "squizlabs/php_codesniffer": "^3.0.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "http://ocramius.github.com/"
+ }
+ ],
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://github.com/doctrine/instantiator",
+ "keywords": [
+ "constructor",
+ "instantiate"
+ ],
+ "time": "2017-07-22T11:58:36+00:00"
+ },
+ {
+ "name": "guzzle/guzzle",
+ "version": "v3.9.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle3.git",
+ "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9",
+ "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "php": ">=5.3.3",
+ "symfony/event-dispatcher": "~2.1"
+ },
+ "replace": {
+ "guzzle/batch": "self.version",
+ "guzzle/cache": "self.version",
+ "guzzle/common": "self.version",
+ "guzzle/http": "self.version",
+ "guzzle/inflection": "self.version",
+ "guzzle/iterator": "self.version",
+ "guzzle/log": "self.version",
+ "guzzle/parser": "self.version",
+ "guzzle/plugin": "self.version",
+ "guzzle/plugin-async": "self.version",
+ "guzzle/plugin-backoff": "self.version",
+ "guzzle/plugin-cache": "self.version",
+ "guzzle/plugin-cookie": "self.version",
+ "guzzle/plugin-curlauth": "self.version",
+ "guzzle/plugin-error-response": "self.version",
+ "guzzle/plugin-history": "self.version",
+ "guzzle/plugin-log": "self.version",
+ "guzzle/plugin-md5": "self.version",
+ "guzzle/plugin-mock": "self.version",
+ "guzzle/plugin-oauth": "self.version",
+ "guzzle/service": "self.version",
+ "guzzle/stream": "self.version"
+ },
+ "require-dev": {
+ "doctrine/cache": "~1.3",
+ "monolog/monolog": "~1.0",
+ "phpunit/phpunit": "3.7.*",
+ "psr/log": "~1.0",
+ "symfony/class-loader": "~2.1",
+ "zendframework/zend-cache": "2.*,<2.3",
+ "zendframework/zend-log": "2.*,<2.3"
+ },
+ "suggest": {
+ "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.9-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Guzzle": "src/",
+ "Guzzle\\Tests": "tests/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Guzzle Community",
+ "homepage": "https://github.com/guzzle/guzzle/contributors"
+ }
+ ],
+ "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ],
+ "abandoned": "guzzlehttp/guzzle",
+ "time": "2015-03-18T18:23:50+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
+ "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
+ }
+ ],
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "homepage": "http://www.phpdoc.org",
+ "keywords": [
+ "FQSEN",
+ "phpDocumentor",
+ "phpdoc",
+ "reflection",
+ "static analysis"
+ ],
+ "time": "2017-09-11T18:02:19+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "4.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "94fd0001232e47129dd3504189fa1c7225010d08"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08",
+ "reference": "94fd0001232e47129dd3504189fa1c7225010d08",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "phpdocumentor/reflection-common": "^1.0.0",
+ "phpdocumentor/type-resolver": "^0.4.0",
+ "webmozart/assert": "^1.0"
+ },
+ "require-dev": {
+ "doctrine/instantiator": "~1.0.5",
+ "mockery/mockery": "^1.0",
+ "phpunit/phpunit": "^6.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "time": "2017-11-30T07:14:17+00:00"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "0.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
+ "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.5 || ^7.0",
+ "phpdocumentor/reflection-common": "^1.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "^0.9.4",
+ "phpunit/phpunit": "^5.2||^4.8.24"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "time": "2017-07-14T14:27:02+00:00"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "1.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
+ "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.2",
+ "php": "^5.3|^7.0",
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
+ "sebastian/comparator": "^1.1|^2.0|^3.0",
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^2.5|^3.2",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.8.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Prophecy\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Marcello Duarte",
+ "email": "marcello.duarte@gmail.com"
+ }
+ ],
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
+ "homepage": "https://github.com/phpspec/prophecy",
+ "keywords": [
+ "Double",
+ "Dummy",
+ "fake",
+ "mock",
+ "spy",
+ "stub"
+ ],
+ "time": "2018-08-05T17:53:17+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "2.2.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+ "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "phpunit/php-file-iterator": "~1.3",
+ "phpunit/php-text-template": "~1.2",
+ "phpunit/php-token-stream": "~1.3",
+ "sebastian/environment": "^1.3.2",
+ "sebastian/version": "~1.0"
+ },
+ "require-dev": {
+ "ext-xdebug": ">=2.1.4",
+ "phpunit/phpunit": "~4"
+ },
+ "suggest": {
+ "ext-dom": "*",
+ "ext-xdebug": ">=2.2.1",
+ "ext-xmlwriter": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "time": "2015-10-06T15:47:00+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "1.4.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "time": "2017-11-27T13:52:08+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "time": "2015-06-21T13:50:34+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "1.0.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "time": "2017-02-26T11:10:40+00:00"
+ },
+ {
+ "name": "phpunit/php-token-stream",
+ "version": "1.4.12",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+ "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
+ "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Wrapper around PHP's tokenizer extension.",
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "keywords": [
+ "tokenizer"
+ ],
+ "time": "2017-12-04T08:55:13+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "4.8.36",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "46023de9a91eec7dfb06cc56cb4e260017298517"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517",
+ "reference": "46023de9a91eec7dfb06cc56cb4e260017298517",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-pcre": "*",
+ "ext-reflection": "*",
+ "ext-spl": "*",
+ "php": ">=5.3.3",
+ "phpspec/prophecy": "^1.3.1",
+ "phpunit/php-code-coverage": "~2.1",
+ "phpunit/php-file-iterator": "~1.4",
+ "phpunit/php-text-template": "~1.2",
+ "phpunit/php-timer": "^1.0.6",
+ "phpunit/phpunit-mock-objects": "~2.3",
+ "sebastian/comparator": "~1.2.2",
+ "sebastian/diff": "~1.2",
+ "sebastian/environment": "~1.3",
+ "sebastian/exporter": "~1.2",
+ "sebastian/global-state": "~1.0",
+ "sebastian/version": "~1.0",
+ "symfony/yaml": "~2.1|~3.0"
+ },
+ "suggest": {
+ "phpunit/php-invoker": "~1.1"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.8.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "time": "2017-06-21T08:07:12+00:00"
+ },
+ {
+ "name": "phpunit/phpunit-mock-objects",
+ "version": "2.3.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.2",
+ "php": ">=5.3.3",
+ "phpunit/php-text-template": "~1.2",
+ "sebastian/exporter": "~1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.4"
+ },
+ "suggest": {
+ "ext-soap": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Mock Object library for PHPUnit",
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+ "keywords": [
+ "mock",
+ "xunit"
+ ],
+ "time": "2015-10-02T06:51:40+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "1.2.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
+ "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "sebastian/diff": "~1.2",
+ "sebastian/exporter": "~1.2 || ~2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "http://www.github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "time": "2017-01-29T09:50:25+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "1.4.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff"
+ ],
+ "time": "2017-05-22T07:24:03+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "1.3.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
+ "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8 || ^5.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "time": "2016-08-18T05:49:44+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "1.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
+ "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "sebastian/recursion-context": "~1.0"
+ },
+ "require-dev": {
+ "ext-mbstring": "*",
+ "phpunit/phpunit": "~4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "time": "2016-06-17T09:04:28+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.2"
+ },
+ "suggest": {
+ "ext-uopz": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "time": "2015-10-12T03:26:01+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
+ "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "time": "2016-10-03T07:41:43+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "1.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+ "shasum": ""
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "time": "2015-06-21T13:59:46+00:00"
+ },
+ {
+ "name": "symfony/class-loader",
+ "version": "v3.4.21",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/class-loader.git",
+ "reference": "4513348012c25148f8cbc3a7761a1d1e60ca3e87"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/class-loader/zipball/4513348012c25148f8cbc3a7761a1d1e60ca3e87",
+ "reference": "4513348012c25148f8cbc3a7761a1d1e60ca3e87",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.5.9|>=7.0.8"
+ },
+ "require-dev": {
+ "symfony/finder": "~2.8|~3.0|~4.0",
+ "symfony/polyfill-apcu": "~1.1"
+ },
+ "suggest": {
+ "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\ClassLoader\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony ClassLoader Component",
+ "homepage": "https://symfony.com",
+ "time": "2019-01-01T13:45:19+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher",
+ "version": "v2.8.49",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher.git",
+ "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0",
+ "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "psr/log": "~1.0",
+ "symfony/config": "^2.0.5|~3.0.0",
+ "symfony/dependency-injection": "~2.6|~3.0.0",
+ "symfony/expression-language": "~2.6|~3.0.0",
+ "symfony/stopwatch": "~2.3|~3.0.0"
+ },
+ "suggest": {
+ "symfony/dependency-injection": "",
+ "symfony/http-kernel": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.8-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\EventDispatcher\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony EventDispatcher Component",
+ "homepage": "https://symfony.com",
+ "time": "2018-11-21T14:20:20+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
+ "reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.9-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ },
+ {
+ "name": "Gert de Pagter",
+ "email": "backendtea@gmail.com"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "time": "2018-08-06T14:22:27+00:00"
+ },
+ {
+ "name": "symfony/yaml",
+ "version": "v3.4.21",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/yaml.git",
+ "reference": "554a59a1ccbaac238a89b19c8e551a556fd0e2ea"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/554a59a1ccbaac238a89b19c8e551a556fd0e2ea",
+ "reference": "554a59a1ccbaac238a89b19c8e551a556fd0e2ea",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
+ },
+ "conflict": {
+ "symfony/console": "<3.4"
+ },
+ "require-dev": {
+ "symfony/console": "~3.4|~4.0"
+ },
+ "suggest": {
+ "symfony/console": "For validating YAML files using the lint command"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Yaml\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Yaml Component",
+ "homepage": "https://symfony.com",
+ "time": "2019-01-01T13:45:19+00:00"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozart/assert.git",
+ "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9",
+ "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.6",
+ "sebastian/version": "^1.0.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Assert\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Assertions to validate method input/output with nice error messages.",
+ "keywords": [
+ "assert",
+ "check",
+ "validate"
+ ],
+ "time": "2018-12-25T11:19:39+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": {
+ "guzzle/guzzle": 0,
+ "symfony/class-loader": 0
+ },
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=5.3"
+ },
+ "platform-dev": []
+}
diff --git a/documentation/Ogone_e-Com-ADV_EN.pdf b/documentation/Ogone_e-Com-ADV_EN.pdf
new file mode 100644
index 0000000..22e15e5
Binary files /dev/null and b/documentation/Ogone_e-Com-ADV_EN.pdf differ
diff --git a/documentation/Ogone_e-Com-BAS_EN.pdf b/documentation/Ogone_e-Com-BAS_EN.pdf
new file mode 100644
index 0000000..6cd1adb
Binary files /dev/null and b/documentation/Ogone_e-Com-BAS_EN.pdf differ
diff --git a/documentation/images/ogone_security_allparameters_sha1_utf8.png b/documentation/images/ogone_security_allparameters_sha1_utf8.png
new file mode 100644
index 0000000..f3fbed8
Binary files /dev/null and b/documentation/images/ogone_security_allparameters_sha1_utf8.png differ
diff --git a/documentation/images/ogone_security_legacy.png b/documentation/images/ogone_security_legacy.png
new file mode 100644
index 0000000..de507fb
Binary files /dev/null and b/documentation/images/ogone_security_legacy.png differ
diff --git a/lib/Ogone/AbstractDirectLinkRequest.php b/lib/Ogone/AbstractDirectLinkRequest.php
new file mode 100644
index 0000000..46d20c9
--- /dev/null
+++ b/lib/Ogone/AbstractDirectLinkRequest.php
@@ -0,0 +1,45 @@
+
+ */
+
+namespace Ogone;
+
+use InvalidArgumentException;
+
+abstract class AbstractDirectLinkRequest extends AbstractRequest
+{
+
+ public function setUserId($userid)
+ {
+ if (strlen($userid) < 2) {
+ throw new InvalidArgumentException("User ID is too short");
+ }
+ $this->parameters['userid'] = $userid;
+ }
+
+ public function setPassword($password)
+ {
+ if (strlen($password) < 8) {
+ throw new InvalidArgumentException("Password is too short");
+ }
+ $this->parameters['pswd'] = $password;
+ }
+
+ public function setPayId($payid)
+ {
+ $this->parameters['payid'] = $payid;
+ }
+
+ public function setOrderId($orderid)
+ {
+ $this->parameters['orderid'] = $orderid;
+ }
+
+ protected function getRequiredFieldGroups()
+ {
+ return array(
+ array('payid', 'orderid'),
+ );
+ }
+}
diff --git a/lib/Ogone/AbstractPaymentRequest.php b/lib/Ogone/AbstractPaymentRequest.php
new file mode 100644
index 0000000..0ab1ea9
--- /dev/null
+++ b/lib/Ogone/AbstractPaymentRequest.php
@@ -0,0 +1,278 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone;
+
+use InvalidArgumentException;
+use Ogone\DirectLink\PaymentOperation;
+
+abstract class AbstractPaymentRequest extends AbstractRequest
+{
+ /** Note this is public to allow easy modification, if need be. */
+ public $allowedcurrencies = array(
+ 'AED',
+ 'ANG',
+ 'ARS',
+ 'AUD',
+ 'AWG',
+ 'BGN',
+ 'BRL',
+ 'BYR',
+ 'CAD',
+ 'CHF',
+ 'CNY',
+ 'CZK',
+ 'DKK',
+ 'EEK',
+ 'EGP',
+ 'EUR',
+ 'GBP',
+ 'GEL',
+ 'HKD',
+ 'HRK',
+ 'HUF',
+ 'ILS',
+ 'ISK',
+ 'JPY',
+ 'KRW',
+ 'LTL',
+ 'LVL',
+ 'MAD',
+ 'MXN',
+ 'MYR',
+ 'NOK',
+ 'NZD',
+ 'PLN',
+ 'RON',
+ 'RUB',
+ 'SEK',
+ 'SGD',
+ 'SKK',
+ 'THB',
+ 'TRY',
+ 'UAH',
+ 'USD',
+ 'XAF',
+ 'XOF',
+ 'XPF',
+ 'ZAR'
+ );
+
+ public function setOrderid($orderid)
+ {
+ if (strlen($orderid) > 40) {
+ throw new InvalidArgumentException("Orderid cannot be longer than 40 characters");
+ }
+ if (preg_match('/[^a-zA-Z0-9_-]/', $orderid)) {
+ throw new InvalidArgumentException("Order id cannot contain special characters");
+ }
+ $this->parameters['orderid'] = $orderid;
+
+ return $this;
+ }
+
+ /** Friend alias for setCom() */
+ public function setOrderDescription($orderDescription)
+ {
+ return $this->setCom($orderDescription);
+ }
+
+ public function setCom($com)
+ {
+ if (strlen($com) > 100) {
+ throw new InvalidArgumentException("Order description cannot be longer than 100 characters");
+ }
+ $this->parameters['com'] = $com;
+
+ return $this;
+ }
+
+ /**
+ * Set amount in cents, eg EUR 12.34 is written as 1234
+ */
+ public function setAmount($amount)
+ {
+ if (!is_int($amount)) {
+ throw new InvalidArgumentException("Integer expected. Amount is always in cents");
+ }
+ if ($amount <= 0) {
+ throw new InvalidArgumentException("Amount must be a positive number");
+ }
+ if ($amount >= 1.0E+15) {
+ throw new InvalidArgumentException("Amount is too high");
+ }
+ $this->parameters['amount'] = $amount;
+
+ return $this;
+ }
+
+ public function setCurrency($currency)
+ {
+ if (!in_array(strtoupper($currency), $this->allowedcurrencies)) {
+ throw new InvalidArgumentException("Unknown currency");
+ }
+ $this->parameters['currency'] = $currency;
+
+ return $this;
+ }
+
+ public function setEmail($email)
+ {
+ if (strlen($email) > 50) {
+ throw new InvalidArgumentException("Email is too long");
+ }
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ throw new InvalidArgumentException("Email is invalid");
+ }
+ $this->parameters['email'] = $email;
+
+ return $this;
+ }
+
+ public function setOwnerAddress($owneraddress)
+ {
+ if (strlen($owneraddress) > 35) {
+ throw new InvalidArgumentException("Owner address is too long");
+ }
+ $this->parameters['owneraddress'] = $owneraddress;
+
+ return $this;
+ }
+
+ public function setOwnerZip($ownerzip)
+ {
+ if (strlen($ownerzip) > 10) {
+ throw new InvalidArgumentException("Owner Zip is too long");
+ }
+ $this->parameters['ownerzip'] = $ownerzip;
+
+ return $this;
+ }
+
+ public function setOwnerTown($ownertown)
+ {
+ if (strlen($ownertown) > 40) {
+ throw new InvalidArgumentException("Owner town is too long");
+ }
+ $this->parameters['ownertown'] = $ownertown;
+
+ return $this;
+ }
+
+ /**
+ * Alias for setOwnercty
+ *
+ * @see http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
+ */
+ public function setOwnerCountry($ownercountry)
+ {
+ return $this->setOwnercty($ownercountry);
+ }
+
+ /**
+ * @see http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
+ */
+ public function setOwnercty($ownercty)
+ {
+ if (!preg_match('/^[A-Z]{2}$/', strtoupper($ownercty))) {
+ throw new InvalidArgumentException("Illegal country code");
+ }
+ $this->parameters['ownercty'] = strtoupper($ownercty);
+
+ return $this;
+ }
+
+ /** Alias for setOwnertelno() */
+ public function setOwnerPhone($ownerphone)
+ {
+ return $this->setOwnertelno($ownerphone);
+ }
+
+ public function setOwnertelno($ownertelno)
+ {
+ if (strlen($ownertelno) > 30) {
+ throw new InvalidArgumentException("Owner phone is too long");
+ }
+ $this->parameters['ownertelno'] = $ownertelno;
+
+ return $this;
+ }
+
+ /** Alias for setComplus() */
+ public function setFeedbackMessage($feedbackMessage)
+ {
+ return $this->setComplus($feedbackMessage);
+ }
+
+ public function setComplus($complus)
+ {
+ $this->parameters['complus'] = $complus;
+
+ return $this;
+ }
+
+ public function setBrand($brand)
+ {
+ $this->parameters['brand'] = $brand;
+
+ return $this;
+ }
+
+ public function setPaymentMethod($paymentMethod)
+ {
+ return $this->setPm($paymentMethod);
+ }
+
+ public function setPm($pm)
+ {
+ $this->parameters['pm'] = $pm;
+
+ return $this;
+ }
+
+ public function setParamvar($paramvar)
+ {
+ if (strlen($paramvar) < 2 || strlen($paramvar) > 50) {
+ throw new InvalidArgumentException("Paramvar must be between 2 and 50 characters in length");
+ }
+ $this->parameters['paramvar'] = $paramvar;
+
+ return $this;
+ }
+
+ /** Alias for setTp */
+ public function setDynamicTemplateUri($uri)
+ {
+ $this->validateUri($uri);
+ $this->setTp($uri);
+ }
+
+ /** Alias for setTp */
+ public function setStaticTemplate($tp)
+ {
+ return $this->setTp($tp);
+ }
+
+ public function setTp($tp)
+ {
+ $this->parameters['tp'] = $tp;
+
+ return $this;
+ }
+
+ public function setOperation(PaymentOperation $operation)
+ {
+ $this->parameters['operation'] = (string) $operation;
+
+ return $this;
+ }
+
+ abstract protected function getValidOperations();
+}
diff --git a/lib/Ogone/AbstractPaymentResponse.php b/lib/Ogone/AbstractPaymentResponse.php
new file mode 100644
index 0000000..4b52094
--- /dev/null
+++ b/lib/Ogone/AbstractPaymentResponse.php
@@ -0,0 +1,235 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone;
+
+use InvalidArgumentException;
+
+abstract class AbstractPaymentResponse extends AbstractResponse implements PaymentResponse
+{
+ /**
+ * Response Fields
+ */
+ const FIELD_STATUS = 'STATUS';
+ const FIELD_NCSTATUS = 'NCSTATUS';
+ const FIELD_NCERROR = 'NCERROR';
+ const FIELD_NCERRORPLUS = 'NCERRORPLUS';
+ const FIELD_ORDERID = 'ORDERID';
+ const FIELD_PAYID = 'PAYID';
+ const FIELD_PAYIDSUB = 'PAYIDSUB';
+ const FIELD_AMOUNT = 'AMOUNT';
+ const FIELD_CURRENCY = 'CURRENCY';
+ const FIELD_HTML_ANSWER = 'HTML_ANSWER';
+ const FIELD_ALIAS = 'ALIAS';
+ const FIELD_CARDNO = 'CARDNO';
+ const FIELD_BRAND = 'BRAND';
+ const FIELD_BIN = 'BIN';
+ const FIELD_PM = 'PM';
+ const FIELD_ED = 'ED';
+
+ /**
+ * Get Amount
+ * @return int Amount in cents
+ */
+ public function getAmount()
+ {
+ if (!$this->hasParam(self::FIELD_AMOUNT)) {
+ throw new InvalidArgumentException('Parameter AMOUNT does not exist');
+ }
+
+ $value = trim($this->getParam(self::FIELD_AMOUNT));
+
+ $withoutDecimals = '#^\d*$#';
+ $oneDecimal = '#^\d*\.\d$#';
+ $twoDecimals = '#^\d*\.\d\d$#';
+
+ if (preg_match($withoutDecimals, $value)) {
+ return (int) ($value.'00');
+ }
+
+ if (preg_match($oneDecimal, $value)) {
+ return (int) (str_replace('.', '', $value).'0');
+ }
+
+ if (preg_match($twoDecimals, $value)) {
+ return (int) (str_replace('.', '', $value));
+ }
+
+ throw new \InvalidArgumentException("Not a valid currency amount");
+ }
+
+ /**
+ * Check is payment was successful
+ * @deprecated
+ * @return bool
+ */
+ public function isSuccessful()
+ {
+ return in_array($this->getStatus(), array(
+ PaymentResponse::STATUS_AUTHORISED,
+ PaymentResponse::STATUS_PAYMENT_REQUESTED,
+ PaymentResponse::STATUS_PAYMENT_BY_MERCHANT
+ ));
+ }
+
+ /**
+ * Check is transaction was successful
+ * @return bool
+ */
+ public function isTransactionSuccessful()
+ {
+ return $this->getErrorCode() === '0';
+ }
+
+ /**
+ * Check is 3DS required
+ * @return bool
+ */
+ public function isSecurityCheckRequired()
+ {
+ return $this->getStatus() === 46;
+ }
+
+ /**
+ * Get Status
+ * @return int
+ */
+ public function getStatus()
+ {
+ return (int) $this->getParam(self::FIELD_STATUS);
+ }
+
+ /**
+ * Get Order ID
+ * @return string
+ */
+ public function getOrderId()
+ {
+ return $this->getParam(self::FIELD_ORDERID);
+ }
+
+ /**
+ * Get PayID
+ * @return string
+ */
+ public function getPayID()
+ {
+ return $this->getParam(self::FIELD_PAYID);
+ }
+
+ /**
+ * Get PayID Sub
+ * @return string
+ */
+ public function getPayIDSub()
+ {
+ return $this->getParam(self::FIELD_PAYIDSUB);
+ }
+
+ /**
+ * Get NC Status Code
+ * @return string
+ */
+ public function getNcStatus()
+ {
+ return $this->getParam(self::FIELD_NCSTATUS);
+ }
+
+ /**
+ * Get Error Code
+ * @return string
+ */
+ public function getErrorCode()
+ {
+ return $this->getParam(self::FIELD_NCERROR);
+ }
+
+ /**
+ * Get Error Message
+ * @return string
+ */
+ public function getErrorMessage()
+ {
+ return $this->hasParam(self::FIELD_NCERRORPLUS) ? $this->getParam(self::FIELD_NCERRORPLUS) : '';
+ }
+
+ /**
+ * Get Currency
+ * @return string
+ */
+ public function getCurrency()
+ {
+ return $this->getParam(self::FIELD_CURRENCY);
+ }
+
+ /**
+ * Get HTML Code that use for 3DS
+ * @return string
+ */
+ public function getSecurityHTML()
+ {
+ return base64_decode($this->getParam(self::FIELD_HTML_ANSWER));
+ }
+
+ /**
+ * Get Alias
+ * @return string
+ */
+ public function getAlias()
+ {
+ return $this->getParam(self::FIELD_ALIAS);
+ }
+
+ /**
+ * Get Masked Card Number
+ * @return string
+ */
+ public function getCardno()
+ {
+ return $this->getParam(self::FIELD_CARDNO);
+ }
+
+ /**
+ * Get Bin of Card number
+ * @return string
+ */
+ public function getBin()
+ {
+ // "Redirect" method don't returns BIN parameter
+ return $this->hasParam(self::FIELD_BIN) ? $this->getParam(self::FIELD_BIN) : null;
+ }
+
+ /**
+ * Get Brand
+ * @return string
+ */
+ public function getBrand()
+ {
+ return $this->getParam(self::FIELD_BRAND);
+ }
+
+ /**
+ * Get Payment Method
+ * @return string
+ */
+ public function getPm()
+ {
+ return $this->getParam(self::FIELD_PM);
+ }
+
+ /**
+ * Get Expire Date
+ * @return string
+ */
+ public function getEd()
+ {
+ return $this->getParam(self::FIELD_ED);
+ }
+}
diff --git a/lib/Ogone/AbstractRequest.php b/lib/Ogone/AbstractRequest.php
new file mode 100644
index 0000000..2a3e208
--- /dev/null
+++ b/lib/Ogone/AbstractRequest.php
@@ -0,0 +1,620 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone;
+
+use InvalidArgumentException;
+use Psr\Log\LoggerInterface;
+use RuntimeException;
+use BadMethodCallException;
+use Ogone\ShaComposer\ShaComposer;
+
+/**
+ * Class AbstractRequest
+ * @method $this setCuid($value)
+ * @method mixed getCuid()
+ * @method $this setCivility($value)
+ * @method mixed getCivility()
+ * @method $this setRemoteAddr($value)
+ * @method mixed getRemoteAddr()
+ * @method $this setAddrmatch($value)
+ * @method mixed getAddrmatch()
+ * @method $this setEcomBilltoPostalCity($value)
+ * @method mixed getEcomBilltoPostalCity()
+ * @method $this setEcomBilltoPostalCountrycode($value)
+ * @method mixed getEcomBilltoPostalCountrycode()
+ * @method $this setEcomBilltoPostalNameFirst($value)
+ * @method mixed getEcomBilltoPostalNameFirst()
+ * @method $this setEcomBilltoPostalNameLast($value)
+ * @method mixed getEcomBilltoPostalNameLast()
+ * @method $this setEcomBilltoPostalPostalcode($value)
+ * @method mixed getEcomBilltoPostalPostalcode()
+ * @method $this setEcomBilltoPostalStreetLine1($value)
+ * @method mixed getEcomBilltoPostalStreetLine1()
+ * @method $this setEcomBilltoPostalStreetLine2($value)
+ * @method mixed getEcomBilltoPostalStreetLine2()
+ * @method $this setEcomBilltoPostalStreetLine3($value)
+ * @method mixed getEcomBilltoPostalStreetLine3()
+ * @method $this setEcomBilltoPostalStreetNumber($value)
+ * @method mixed getEcomBilltoPostalStreetNumber()
+ * @method $this setEcomShiptoPostalCity($value)
+ * @method mixed getEcomShiptoPostalCity()
+ * @method $this setEcomShiptoPostalCountrycode($value)
+ * @method mixed getEcomShiptoPostalCountrycode()
+ * @method $this setEcomShiptoPostalNameFirst($value)
+ * @method mixed getEcomShiptoPostalNameFirst()
+ * @method $this setEcomShiptoPostalNameLast($value)
+ * @method mixed getEcomShiptoPostalNameLast()
+ * @method $this setEcomShiptoPostalPostalcode($value)
+ * @method mixed getEcomShiptoPostalPostalcode()
+ * @method $this setEcomShiptoPostalStreetLine1($value)
+ * @method mixed getEcomShiptoPostalStreetLine1()
+ * @method $this setEcomShiptoPostalStreetLine2($value)
+ * @method mixed getEcomShiptoPostalStreetLine2()
+ * @method $this setEcomShiptoPostalStreetLine3($value)
+ * @method mixed getEcomShiptoPostalStreetLine3()
+ * @method $this setEcomShiptoPostalStreetNumber($value)
+ * @method mixed getEcomShiptoPostalStreetNumber()
+ * @method $this setEcomShiptoDob($value)
+ * @method mixed getEcomShiptoDob()
+ *
+ * @package Ogone
+ */
+abstract class AbstractRequest implements Request
+{
+ const WIN3DS_MAIN = 'MAINW';
+ const WIN3DS_POPUP = 'POPUP';
+ const WIN3DS_POPIX = 'POPIX';
+
+ /** @var ShaComposer */
+ protected $shaComposer;
+
+ protected $ogoneUri;
+
+ protected $parameters = array();
+
+ /** @var LoggerInterface|null */
+ protected $logger;
+
+ /** Note this is public to allow easy modification, if need be. */
+ public $allowedlanguages = array(
+ 'en_US' => 'English', 'cs_CZ' => 'Czech', 'de_DE' => 'German',
+ 'dk_DK' => 'Danish', 'el_GR' => 'Greek', 'es_ES' => 'Spanish',
+ 'fr_FR' => 'French', 'it_IT' => 'Italian', 'ja_JP' => 'Japanese',
+ 'nl_BE' => 'Flemish', 'nl_NL' => 'Dutch', 'no_NO' => 'Norwegian',
+ 'pl_PL' => 'Polish', 'pt_PT' => 'Portugese', 'ru_RU' => 'Russian',
+ 'se_SE' => 'Swedish', 'sk_SK' => 'Slovak', 'tr_TR' => 'Turkish',
+ );
+
+ protected $ogoneFields = array(
+ 'orig', 'shoppingcartextensionid', 'pspid', 'orderid', 'com', 'amount', 'currency', 'language', 'cn', 'email',
+ 'cardno', 'cvc', 'ed', 'ownerzip', 'owneraddress', 'ownercty', 'ownertown', 'ownertelno',
+ 'homeurl', 'catalogurl', 'accepturl', 'declineurl', 'exceptionurl', 'cancelurl', 'backurl',
+ 'complus', 'paramplus', 'pm', 'brand', 'title', 'bgcolor', 'txtcolor', 'tblbgcolor',
+ 'tbltxtcolor', 'buttonbgcolor', 'buttontxtcolor', 'logo', 'fonttype', 'tp', 'paramvar',
+ 'alias', 'aliasoperation', 'aliasusage', 'aliaspersistedafteruse', 'device', 'pmlisttype',
+ 'ecom_payment_card_verification', 'operation', 'withroot', 'remote_addr', 'rtimeout',
+ 'pmlist', 'exclpmlist', 'creditdebit', 'userid',
+ // DirectLink with 3-D Secure: Extra request parameters.
+ // https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/directlink-3-d/3-d-transaction-flow-via-directlink#extrarequestparameters
+ // https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/directlink-3-d/version%202#3dtransactionflowviadirectlink
+ // https://payment-services.ingenico.com/ogone/support/~/media/kdb/integration%20guides/directlink%203ds%20v2/odl3dsnew%20parameters%20name%2021en.ashx?la=en
+ 'flag3d', 'http_accept', 'http_user_agent', 'win3ds',
+ // MPI 2.0 (3DS V.2)
+ // https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/directlink-3-d/3-d%20secure%20v2
+ 'browseracceptheader', 'browsercolordepth', 'browserjavaenabled', 'browserlanguage', 'browserscreenheight',
+ 'browserscreenwidth', 'browsertimezone', 'browseruseragent',
+ // Optional integration data: Delivery and Invoicing data.
+ // https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/additional-data/delivery-and-invoicing-data
+ 'addrmatch', 'civility', 'cuid', 'ecom_billto_postal_city', 'ecom_billto_postal_countrycode',
+ 'ecom_billto_postal_name_first', 'ecom_billto_postal_name_last', 'ecom_billto_postal_postalcode',
+ 'ecom_billto_postal_street_line1', 'ecom_billto_postal_street_line2', 'ecom_billto_postal_street_line3',
+ 'ecom_billto_postal_street_number', 'ecom_shipto_dob',
+ 'ecom_shipto_online_email', 'ecom_shipto_postal_city', 'ecom_shipto_postal_countrycode',
+ 'ecom_shipto_postal_name_first', 'ecom_shipto_postal_name_last', 'ecom_shipto_postal_name_prefix',
+ 'ecom_shipto_postal_postalcode', 'ecom_shipto_postal_state',
+ 'ecom_shipto_postal_street_line1', 'ecom_shipto_postal_street_line2','ecom_shipto_postal_street_line3',
+ 'ecom_shipto_postal_street_number', 'ordershipcost', 'ordershipmeth', 'ordershiptaxcode',
+ // Optional integration data: Order data ("ITEM" parameters).
+ // https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/additional-data/order-data
+ 'itemattributes*', 'itemcategory*', 'itemcomments*', 'itemdesc*', 'itemdiscount*',
+ 'itemid*', 'itemname*', 'itemprice*', 'itemquant*', 'itemquantorig*',
+ 'itemunitofmeasure*', 'itemvat*', 'itemvatcode*', 'itemweight*',
+ // Optional integration data: Travel data.
+ // https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/additional-data/travel-data
+ 'datatype', 'aiairname', 'aitinum', 'aitidate', 'aiconjti', 'aipasname',
+ 'aiextrapasname*', 'aichdet', 'aiairtax', 'aivatamnt', 'aivatappl', 'aitypch',
+ 'aieycd', 'aiirst', 'aiorcity*', 'aiorcityl*', 'aidestcity*', 'aidestcityl*',
+ 'aistopov*', 'aicarrier*', 'aibookind*', 'aiflnum*', 'aifldate*', 'aiclass*',
+ // Subscription Manager.
+ // https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/subscription-manager/via-e-commerce-and-directlink#input
+ 'subscription_id', 'sub_amount', 'sub_com', 'sub_orderid', 'sub_period_unit',
+ 'sub_period_number', 'sub_period_moment', 'sub_startdate', 'sub_enddate',
+ 'sub_status', 'sub_comment',
+ );
+
+ /**
+ * Sets Logger.
+ *
+ * @param LoggerInterface|null $logger
+ *
+ * @return $this
+ */
+ public function setLogger(LoggerInterface $logger = null)
+ {
+ $this->logger = $logger;
+
+ return $this;
+ }
+
+ /** @return string */
+ public function getShaSign()
+ {
+ return $this->shaComposer->compose($this->toArray());
+ }
+
+ /** @return string */
+ public function getOgoneUri()
+ {
+ return $this->ogoneUri;
+ }
+
+ /** Ogone uri to send the customer to. Usually PaymentRequest::TEST or PaymentRequest::PRODUCTION */
+ public function setOgoneUri($ogoneUri)
+ {
+ $this->validateOgoneUri($ogoneUri);
+ $this->ogoneUri = $ogoneUri;
+ }
+
+ /**
+ * Set Shopping Cart Extension Id
+ * @param $id
+ * @return $this
+ */
+ public function setShoppingCartExtensionId($id)
+ {
+ $this->parameters['shoppingcartextensionid'] = $id;
+
+ return $this;
+ }
+
+ /**
+ * Get Shopping Cart Extension Id
+ * @return mixed
+ */
+ public function getShoppingCartExtensionId()
+ {
+ return isset($this->parameters['shoppingcartextensionid']) ?: $this->parameters['shoppingcartextensionid'];
+ }
+
+ /**
+ * Set Orig (Plugin version number)
+ * @param $id
+ * @return $this
+ */
+ public function setOrig($id)
+ {
+ $this->parameters['orig'] = $id;
+
+ return $this;
+ }
+
+ /**
+ * Get Orig (Plugin version number)
+ * @return mixed
+ */
+ public function getOrig()
+ {
+ return isset($this->parameters['orig']) ?: $this->parameters['orig'];
+ }
+
+ /**
+ * @param $pspid
+ * @return $this
+ */
+ public function setPspid($pspid)
+ {
+ if (strlen($pspid) > 30) {
+ throw new InvalidArgumentException('PSPId is too long');
+ }
+ $this->parameters['pspid'] = $pspid;
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function setSecure()
+ {
+ return $this->setWin3DS(self::WIN3DS_MAIN);
+ }
+
+ /**
+ * ISO code eg nl_BE.
+ *
+ * @param $language
+ * @return $this
+ */
+ public function setLanguage($language)
+ {
+ if (!array_key_exists($language, $this->allowedlanguages)) {
+ throw new InvalidArgumentException('Invalid language ISO code');
+ }
+ $this->parameters['language'] = $language;
+
+ return $this;
+ }
+
+ /**
+ * Alias for setCn
+ *
+ * @param $customername
+ * @return $this
+ */
+ public function setCustomername($customername)
+ {
+ $this->setCn($customername);
+
+ return $this;
+ }
+
+ /**
+ * @param $cn
+ * @return $this
+ */
+ public function setCn($cn)
+ {
+ $this->parameters['cn'] = str_replace(array("'", '"'), '', $cn); // replace quotes
+
+ return $this;
+ }
+
+ /**
+ * @param $homeurl
+ * @return $this
+ */
+ public function setHomeurl($homeurl)
+ {
+ if (!empty($homeurl)) {
+ $this->validateUri($homeurl);
+ }
+ $this->parameters['homeurl'] = $homeurl;
+
+ return $this;
+ }
+
+ /**
+ * @param $accepturl
+ * @return $this
+ */
+ public function setAccepturl($accepturl)
+ {
+ $this->validateUri($accepturl);
+ $this->parameters['accepturl'] = $accepturl;
+
+ return $this;
+ }
+
+ /**
+ * @param $declineurl
+ * @return $this
+ */
+ public function setDeclineurl($declineurl)
+ {
+ $this->validateUri($declineurl);
+ $this->parameters['declineurl'] = $declineurl;
+
+ return $this;
+ }
+
+ /**
+ * @param $exceptionurl
+ * @return $this
+ */
+ public function setExceptionurl($exceptionurl)
+ {
+ $this->validateUri($exceptionurl);
+ $this->parameters['exceptionurl'] = $exceptionurl;
+
+ return $this;
+ }
+
+ /**
+ * @param $cancelurl
+ * @return $this
+ */
+ public function setCancelurl($cancelurl)
+ {
+ $this->validateUri($cancelurl);
+ $this->parameters['cancelurl'] = $cancelurl;
+
+ return $this;
+ }
+
+ /**
+ * @param $backurl
+ * @return $this
+ */
+ public function setBackurl($backurl)
+ {
+ $this->validateUri($backurl);
+ $this->parameters['backurl'] = $backurl;
+
+ return $this;
+ }
+
+ /**
+ * Alias for setParamplus
+ *
+ * @param array $feedbackParams
+ * @return AbstractRequest
+ */
+ public function setFeedbackParams(array $feedbackParams)
+ {
+ return $this->setParamplus($feedbackParams);
+ }
+
+ /**
+ * @param array $paramplus
+ * @return $this
+ */
+ public function setParamplus(array $paramplus)
+ {
+ $this->parameters['paramplus'] = http_build_query($paramplus);
+
+ return $this;
+ }
+
+ /**
+ * Set Flag3D
+ * Instructs system to perform 3-D Secure identification if necessary.
+ *
+ * @param $flag
+ * @return $this
+ */
+ public function setFlag3D($flag)
+ {
+ $this->validateYesNo($flag);
+ $this->parameters['flag3d'] = $flag;
+
+ return $this;
+ }
+
+ /**
+ * Set HTTP Accept
+ * The Accept request header field in the cardholder browser, used to specify certain media types which are acceptable for the response.
+ * This value is used by the issuer to check if the cardholder browser is compatible with the issuer identification system.
+ *
+ * @param $http_accept
+ * @return $this
+ */
+ public function setHttpAccept($http_accept)
+ {
+ $this->parameters['http_accept'] = $http_accept;
+
+ return $this;
+ }
+
+ /**
+ * Set HTTP User Agent
+ * The User-Agent request-header field in the cardholder browser, containing information about the user agent originating the request.
+ * This value is used by the issuer to check if the cardholder browser is compatible with the issuer identification system.
+ *
+ * @param $http_user_agent
+ * @return $this
+ */
+ public function setHttpUserAgent($http_user_agent)
+ {
+ $this->parameters['http_user_agent'] = $http_user_agent;
+
+ return $this;
+ }
+
+ /**
+ * Set WIN3DS Value
+ * Way to show the identification page to the customer.
+ *
+ * @param $win3ds
+ * @return $this
+ */
+ public function setWin3DS($win3ds)
+ {
+ $this->validateWin3DS($win3ds);
+ $this->parameters['win3ds'] = $win3ds;
+
+ return $this;
+ }
+
+ public function validate()
+ {
+ foreach ($this->getRequiredFields() as $field) {
+ if (empty($this->parameters[$field])) {
+ throw new RuntimeException("$field can not be empty");
+ }
+ }
+
+ if ($this->logger) {
+ $this->logger->debug(sprintf('Request %s', get_class($this)), $this->parameters);
+ }
+ }
+
+ protected function validateUri($uri)
+ {
+ if (!filter_var($uri, FILTER_VALIDATE_URL)) {
+ throw new InvalidArgumentException('Uri is not valid');
+ }
+ if (strlen($uri) > 200) {
+ throw new InvalidArgumentException('Uri is too long');
+ }
+ }
+
+ protected function validateOgoneUri($uri)
+ {
+ $this->validateUri($uri);
+
+ if (!in_array($uri, $this->getValidOgoneUris())) {
+ throw new InvalidArgumentException('No valid Ogone url');
+ }
+ }
+
+ /**
+ * Validate Y/N Values.
+ *
+ * @param $value
+ */
+ protected function validateYesNo($value)
+ {
+ if (!in_array(strtoupper($value), ['Y', 'N'])) {
+ throw new InvalidArgumentException("Value should be 'Y' or 'N'.");
+ }
+ }
+
+ /**
+ * Validate Win3DS.
+ *
+ * @param $win3ds
+ */
+ protected function validateWin3DS($win3ds)
+ {
+ if (!in_array(strtoupper($win3ds), [self::WIN3DS_MAIN, self::WIN3DS_POPUP, self::WIN3DS_POPIX])) {
+ throw new InvalidArgumentException('Win3DS is not valid');
+ }
+ }
+
+ /**
+ * Allows setting ogone parameters that don't have a setter -- usually only
+ * the unimportant ones like bgcolor, which you'd call with setBgcolor().
+ *
+ * @param $method
+ * @param $args
+ */
+ public function __call($method, $args)
+ {
+ switch (substr($method, 0, 3)) {
+ case 'get' :
+ $field = strtolower($this->_underscore(substr($method,3)));
+ if (array_key_exists($field, $this->parameters)) {
+ return $this->parameters[$field];
+ }
+ break;
+ case 'set' :
+ $field = strtolower($this->_underscore(substr($method,3)));
+ if (in_array($field, $this->ogoneFields)) {
+ $this->parameters[$field] = $args[0];
+ return $this;
+ }
+ break;
+ case 'uns' :
+ $key = $this->_underscore(substr($method,3));
+ $this->unsData($key);
+ return $this;
+ case 'has' :
+ $field = strtolower($this->_underscore(substr($method,3)));
+ return array_key_exists($field, $this->parameters);
+ }
+
+ throw new BadMethodCallException("Unknown method $method");
+ }
+
+ /**
+ * Check is data exists
+ * @param $key
+ * @return bool
+ */
+ public function hasData($key)
+ {
+ return isset($this->parameters[$key]);
+ }
+
+ /**
+ * Get Data
+ * @param mixed $key
+ * @return array|mixed
+ */
+ public function getData($key = null)
+ {
+ if (!$key) {
+ return $this->parameters;
+ }
+
+ return isset($this->parameters[$key]) ? $this->parameters[$key] : null;
+ }
+
+ /**
+ * Set Data
+ * @param $key
+ * @param null $value
+ * @return $this
+ */
+ public function setData($key, $value = null)
+ {
+ if (is_array($key)) {
+ foreach ($key as $key1 => $value1) {
+ if (is_scalar($key1)) {
+ $this->setData($key1, $value1);
+ }
+ }
+ } elseif (is_scalar($key)) {
+ $this->parameters[$key] = $value;
+ } else {
+ throw new InvalidArgumentException(sprintf('Invalid type for index %s', var_export($key, true)));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Unset Data
+ * @param $key
+ * @return $this
+ */
+ public function unsData($key)
+ {
+ if ($this->hasData($key)) {
+ unset($this->parameters[$key]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * To Array
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->validate();
+
+ $params = array_filter($this->parameters, 'strlen');
+ $params = array_change_key_case($params, CASE_UPPER);
+
+ foreach ($params as $key => $value) {
+ // Convert to text field
+ if (is_object($value) && method_exists($value, '__toString')) {
+ $params[$key] = $value->__toString();
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * Converts field names for setters and getters
+ *
+ * @param string $name
+ * @return string
+ */
+ protected function _underscore($name)
+ {
+ $result = strtolower(preg_replace('/(.)([A-Z])/', '$1_$2', $name));
+ return $result;
+ }
+}
diff --git a/lib/Ogone/AbstractResponse.php b/lib/Ogone/AbstractResponse.php
new file mode 100644
index 0000000..0881fc0
--- /dev/null
+++ b/lib/Ogone/AbstractResponse.php
@@ -0,0 +1,307 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone;
+
+use InvalidArgumentException;
+use Psr\Log\LoggerInterface;
+
+abstract class AbstractResponse implements Response, \ArrayAccess
+{
+ /**
+ * Available Ogone parameters.
+ *
+ * @var array
+ */
+ protected $ogoneFields = array(
+ 'AAVADDRESS',
+ 'AAVCHECK',
+ 'AAVMAIL',
+ 'AAVNAME',
+ 'AAVPHONE',
+ 'AAVZIP',
+ 'ACCEPTANCE',
+ 'ALIAS',
+ 'AMOUNT',
+ 'BIC',
+ 'BIN',
+ 'BRAND',
+ 'CARDNO',
+ 'CCCTY',
+ 'CN',
+ 'COLLECTOR_BIC',
+ 'COLLECTOR_IBAN',
+ 'COMPLUS',
+ 'CREATION_STATUS',
+ 'CREDITDEBIT',
+ 'CURRENCY',
+ 'CVCCHECK',
+ 'DCC_COMMPERCENTAGE',
+ 'DCC_CONVAMOUNT',
+ 'DCC_CONVCCY',
+ 'DCC_EXCHRATE',
+ 'DCC_EXCHRATESOURCE',
+ 'DCC_EXCHRATETS',
+ 'DCC_INDICATOR',
+ 'DCC_MARGINPERCENTAGE',
+ 'DCC_VALIDHOURS',
+ 'DEVICEID',
+ 'DIGESTCARDNO',
+ 'ECI',
+ 'ED',
+ 'EMAIL',
+ 'ENCCARDNO',
+ 'FXAMOUNT',
+ 'FXCURRENCY',
+ 'HTML_ANSWER',
+ 'IP',
+ 'IPCTY',
+ 'MANDATEID',
+ 'MOBILEMODE',
+ 'NBREMAILUSAGE',
+ 'NBRIPUSAGE',
+ 'NBRIPUSAGE_ALLTX',
+ 'NBRUSAGE',
+ 'NCSTATUS',
+ 'NCERROR',
+ 'NCERRORPLUS',
+ 'ORDERID',
+ 'PAYID',
+ 'PAYIDSUB',
+ 'PAYMENT_REFERENCE',
+ 'PM',
+ 'SCO_CATEGORY',
+ 'SCORING',
+ 'SEQUENCETYPE',
+ 'SIGNDATE',
+ 'STATUS',
+ 'SUBBRAND',
+ 'SUBSCRIPTION_ID',
+ 'TICKET',
+ 'TRXDATE',
+ 'VC',
+ );
+
+ /**
+ * @var array
+ */
+ protected $parameters;
+
+ /**
+ * @var string
+ */
+ protected $shaSign;
+
+ /** @var LoggerInterface|null */
+ protected $logger;
+
+ /**
+ * @param array $httpRequest Typically $_REQUEST
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(array $httpRequest)
+ {
+ // use uppercase internally
+ $httpRequest = array_change_key_case($httpRequest, CASE_UPPER);
+
+ // set sha sign
+ $this->shaSign = $this->extractShaSign($httpRequest);
+
+ // filter request for Ogone parameters
+ $this->parameters = $this->filterRequestParameters($httpRequest);
+
+ if ($this->logger) {
+ $this->logger->debug(sprintf('Response %s', get_class($this)), $this->parameters);
+ }
+ }
+
+ /**
+ * Sets Logger.
+ *
+ * @param LoggerInterface|null $logger
+ *
+ * @return $this
+ */
+ public function setLogger(LoggerInterface $logger = null)
+ {
+ $this->logger = $logger;
+
+ return $this;
+ }
+
+ /**
+ * Filter http request parameters.
+ *
+ * @param array $requestParameters
+ *
+ * @return array
+ */
+ protected function filterRequestParameters(array $requestParameters)
+ {
+ // filter request for Ogone parameters
+ return array_intersect_key($requestParameters, array_flip($this->ogoneFields));
+ }
+
+ /**
+ * Set Ogone SHA sign.
+ *
+ * @param array $parameters
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return mixed
+ */
+ protected function extractShaSign(array $parameters)
+ {
+ if (!array_key_exists(self::SHASIGN_FIELD, $parameters) || '' == $parameters[self::SHASIGN_FIELD]) {
+ throw new InvalidArgumentException('SHASIGN parameter not present in parameters.');
+ }
+
+ return $parameters[self::SHASIGN_FIELD];
+ }
+
+ /**
+ * Check if response parameter exists.
+ *
+ * @param $key
+ *
+ * @return bool
+ */
+ public function hasParam($key)
+ {
+ return array_key_exists($key, $this->parameters);
+ }
+
+ /**
+ * Retrieves a response parameter.
+ *
+ * @param string $key
+ *
+ * @throws \InvalidArgumentException
+ * @return string
+ */
+ public function getParam($key)
+ {
+ // always use uppercase
+ $key = strtoupper($key);
+
+ if (!$this->hasParam($key)) {
+ throw new InvalidArgumentException('Parameter '.$key.' does not exist.');
+ }
+
+ return $this->parameters[$key];
+ }
+
+ /**
+ * Set a Response parameter
+ * @param $key
+ * @param $value
+ */
+ public function setParam($key, $value)
+ {
+ $key = strtoupper($key);
+ $this->parameters[$key] = $value;
+ }
+
+ /**
+ * Get all parameters + SHASIGN
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->parameters + array('SHASIGN' => $this->shaSign);
+ }
+
+ /**
+ * Implementation of \ArrayAccess::offsetSet()
+ *
+ * @param string $offset
+ * @param mixed $value
+ * @return void
+ * @link http://www.php.net/manual/en/arrayaccess.offsetset.php
+ */
+ public function offsetSet($offset, $value)
+ {
+ $offset = strtoupper($offset);
+ if (is_null($offset)) {
+ $this->parameters[] = $value;
+ } else {
+ $this->parameters[$offset] = $value;
+ }
+ }
+
+ /**
+ * Implementation of \ArrayAccess::offsetExists()
+ *
+ * @param string $offset
+ * @return bool
+ * @link http://www.php.net/manual/en/arrayaccess.offsetexists.php
+ */
+ public function offsetExists($offset)
+ {
+ $offset = strtoupper($offset);
+ return isset($this->parameters[$offset]);
+ }
+
+ /**
+ * Implementation of \ArrayAccess::offsetUnset()
+ *
+ * @param string $offset
+ * @return void
+ * @link http://www.php.net/manual/en/arrayaccess.offsetunset.php
+ */
+ public function offsetUnset($offset)
+ {
+ $offset = strtoupper($offset);
+ unset($this->parameters[$offset]);
+ }
+
+ /**
+ * Implementation of \ArrayAccess::offsetGet()
+ *
+ * @param string $offset
+ * @return mixed
+ * @link http://www.php.net/manual/en/arrayaccess.offsetget.php
+ */
+ public function offsetGet($offset)
+ {
+ $offset = strtoupper($offset);
+ return isset($this->parameters[$offset]) ? $this->parameters[$offset] : null;
+ }
+
+ /**
+ * Set/Get attribute wrapper
+ *
+ * @param $method
+ * @param $arguments
+ *
+ * @return mixed
+ * @throws \Exception
+ */
+ public function __call($method, $arguments)
+ {
+ $key = strtoupper(substr($method, 3, strlen($method)));
+ switch (substr($method, 0, 3)) {
+ case 'get':
+ return isset($this->parameters[$key]) ? $this->parameters[$key] : null;
+ case 'set':
+ $this->parameters[$key] = isset($arguments[0]) ? $arguments[0] : null;
+ return $this;
+ case 'uns':
+ unset($this->parameters[$key]);
+ return $this;
+ case 'has':
+ return isset($this->parameters[$key]);
+ }
+
+ throw new \Exception(sprintf('Invalid method %s::%s', get_class($this), $method));
+ }
+}
diff --git a/lib/Ogone/DirectLink/Alias.php b/lib/Ogone/DirectLink/Alias.php
new file mode 100644
index 0000000..483d228
--- /dev/null
+++ b/lib/Ogone/DirectLink/Alias.php
@@ -0,0 +1,80 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\DirectLink;
+
+use InvalidArgumentException;
+
+class Alias
+{
+
+ /** @var string */
+ private $alias;
+
+ /** @var string */
+ private $cardName;
+
+ /** @var string */
+ private $cardNumber;
+
+ /** @var string */
+ private $expiryDate;
+
+ /**
+ * @param $alias
+ * @param string|null $cardName
+ * @param string|null $cardNumber
+ * @param string|null $expiryDate
+ */
+ public function __construct($alias, $cardName = null, $cardNumber = null, $expiryDate = null)
+ {
+ if (empty($alias)) {
+ throw new InvalidArgumentException("Alias cannot be empty");
+ }
+
+ if (strlen($alias) > 50) {
+ throw new InvalidArgumentException("Alias is too long");
+ }
+
+ if (preg_match('/[^a-zA-Z0-9_-]/', $alias)) {
+ throw new InvalidArgumentException("Alias cannot contain special characters");
+ }
+
+ $this->alias = $alias;
+ $this->cardName = $cardName;
+ $this->cardNumber = $cardNumber;
+ $this->expiryDate = $expiryDate;
+ }
+
+ public function getAlias()
+ {
+ return $this->alias;
+ }
+
+ public function getCardName()
+ {
+ return $this->cardName;
+ }
+
+ public function getCardNumber()
+ {
+ return $this->cardNumber;
+ }
+
+ public function getExpiryDate()
+ {
+ return $this->expiryDate;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->alias;
+ }
+}
diff --git a/lib/Ogone/DirectLink/CreateAliasRequest.php b/lib/Ogone/DirectLink/CreateAliasRequest.php
new file mode 100644
index 0000000..b3039c6
--- /dev/null
+++ b/lib/Ogone/DirectLink/CreateAliasRequest.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\DirectLink;
+
+use Ogone\AbstractRequest;
+use Ogone\ShaComposer\ShaComposer;
+
+class CreateAliasRequest extends AbstractRequest
+{
+
+ const TEST = "https://secure.ogone.com/ncol/test/alias_gateway_utf8.asp";
+ const PRODUCTION = "https://secure.ogone.com/ncol/prod/alias_gateway_utf8.asp";
+
+ public function __construct(ShaComposer $shaComposer)
+ {
+ $this->shaComposer = $shaComposer;
+ $this->ogoneUri = self::TEST;
+ }
+
+ public function getRequiredFields()
+ {
+ return array(
+ 'pspid', 'accepturl', 'exceptionurl'
+ );
+ }
+
+ public function getValidOgoneUris()
+ {
+ return array(self::TEST, self::PRODUCTION);
+ }
+
+ public function setAlias(Alias $alias)
+ {
+ $this->parameters['alias'] = (string) $alias;
+ }
+}
diff --git a/lib/Ogone/DirectLink/CreateAliasResponse.php b/lib/Ogone/DirectLink/CreateAliasResponse.php
new file mode 100644
index 0000000..a606914
--- /dev/null
+++ b/lib/Ogone/DirectLink/CreateAliasResponse.php
@@ -0,0 +1,41 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\DirectLink;
+
+use Ogone\AbstractResponse;
+use Ogone\ShaComposer\ShaComposer;
+
+class CreateAliasResponse extends AbstractResponse
+{
+
+ const STATUS_OK = 0;
+ const STATUS_NOK = 1;
+ const STATUS_UPDATED = 2;
+
+ /**
+ * Checks if the response is valid
+ * @return bool
+ */
+ public function isValid(ShaComposer $shaComposer)
+ {
+ return $shaComposer->compose($this->parameters) == $this->shaSign;
+ }
+
+ public function isSuccessful()
+ {
+ return in_array($this->getParam('STATUS'), array(self::STATUS_OK, self::STATUS_UPDATED));
+ }
+
+ public function getAlias()
+ {
+ return new Alias($this->parameters['ALIAS'], $this->parameters['CN'], $this->parameters['CARDNO'], $this->parameters['ED']);
+ }
+}
diff --git a/lib/Ogone/DirectLink/DirectLinkMaintenanceRequest.php b/lib/Ogone/DirectLink/DirectLinkMaintenanceRequest.php
new file mode 100644
index 0000000..3fe1f60
--- /dev/null
+++ b/lib/Ogone/DirectLink/DirectLinkMaintenanceRequest.php
@@ -0,0 +1,67 @@
+
+ */
+
+namespace Ogone\DirectLink;
+
+use Ogone\AbstractDirectLinkRequest;
+use Ogone\ShaComposer\ShaComposer;
+use InvalidArgumentException;
+
+class DirectLinkMaintenanceRequest extends AbstractDirectLinkRequest
+{
+
+ const TEST = "https://e-payment.postfinance.ch/ncol/test/maintenancedirect_utf8.asp";
+ const PRODUCTION = "https://e-payment.postfinance.ch/ncol/prod/maintenancedirect_utf8.asp";
+
+ public function __construct(ShaComposer $shaComposer)
+ {
+ $this->shaComposer = $shaComposer;
+ $this->ogoneUri = self::TEST;
+ }
+
+ public function getRequiredFields()
+ {
+ return array(
+ 'pspid',
+ 'userid',
+ 'pswd',
+ 'operation',
+ );
+ }
+
+ public function getValidOgoneUris()
+ {
+ return array(self::TEST, self::PRODUCTION);
+ }
+
+ public function setAmount($amount)
+ {
+ if (!is_int($amount)) {
+ throw new InvalidArgumentException("Amount should be an integer");
+ }
+
+ $this->parameters['amount'] = $amount;
+ }
+
+ public function setOperation(MaintenanceOperation $operation)
+ {
+ $this->parameters['operation'] = (string) $operation;
+ }
+
+ /**
+ * Set Items.
+ * Items array should contain item with keys like:
+ * ['itemid', 'itemname', 'itemprice', 'itemquant', 'itemvatcode', 'taxincluded']
+ *
+ * @param array $items
+ */
+ public function setItems(array $items) {
+ foreach ($items as $i => $item) {
+ foreach ($item as $key => $value) {
+ $this->parameters[$key . ($i + 1)] = $value;
+ }
+ }
+ }
+}
diff --git a/lib/Ogone/DirectLink/DirectLinkMaintenanceResponse.php b/lib/Ogone/DirectLink/DirectLinkMaintenanceResponse.php
new file mode 100644
index 0000000..c60ae1d
--- /dev/null
+++ b/lib/Ogone/DirectLink/DirectLinkMaintenanceResponse.php
@@ -0,0 +1,27 @@
+
+ */
+
+namespace Ogone\DirectLink;
+
+use Ogone\AbstractResponse;
+
+class DirectLinkMaintenanceResponse extends DirectLinkPaymentResponse
+{
+
+ public function isSuccessful()
+ {
+ return (0 == $this->getParam('NCERROR'));
+ }
+
+ protected function filterRequestParameters(array $httpRequest)
+ {
+ $fields = array(
+ 'NCERRORPLUS',
+ 'PAYIDSUB',
+ );
+
+ return array_intersect_key($httpRequest, array_flip(array_merge($this->ogoneFields, $fields)));
+ }
+}
diff --git a/lib/Ogone/DirectLink/DirectLinkPaymentRequest.php b/lib/Ogone/DirectLink/DirectLinkPaymentRequest.php
new file mode 100644
index 0000000..60ea120
--- /dev/null
+++ b/lib/Ogone/DirectLink/DirectLinkPaymentRequest.php
@@ -0,0 +1,145 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\DirectLink;
+
+use Ogone\AbstractPaymentRequest;
+use Ogone\ShaComposer\ShaComposer;
+use InvalidArgumentException;
+
+class DirectLinkPaymentRequest extends AbstractPaymentRequest
+{
+
+ const TEST = "https://e-payment.postfinance.ch/ncol/test/orderdirect_utf8.asp";
+ const PRODUCTION = "https://e-payment.postfinance.ch/ncol/prod/orderdirect_utf8.asp";
+
+ public function __construct(ShaComposer $shaComposer)
+ {
+ $this->shaComposer = $shaComposer;
+ $this->ogoneUri = self::TEST;
+ }
+
+ public function getRequiredFields()
+ {
+ return array(
+ 'pspid', 'currency', 'amount', 'orderid', 'userid', 'pswd'
+ );
+ }
+
+ public function getValidOgoneUris()
+ {
+ return array(self::TEST, self::PRODUCTION);
+ }
+
+ /**
+ * Set User ID.
+ *
+ * @param $userid
+ * @return $this
+ */
+ public function setUserId($userid)
+ {
+ if (strlen($userid) < 2) {
+ throw new InvalidArgumentException("User ID is too short");
+ }
+ $this->parameters['userid'] = $userid;
+
+ return $this;
+ }
+
+ /**
+ * Alias for setPswd().
+ *
+ * @param $password
+ * @return $this
+ */
+ public function setPassword($password)
+ {
+ return $this->setPswd($password);
+ }
+
+ /**
+ * Set Password.
+ *
+ * @param $password
+ * @return $this
+ */
+ public function setPswd($password)
+ {
+ if (strlen($password) < 8) {
+ throw new InvalidArgumentException("Password is too short");
+ }
+ $this->parameters['pswd'] = $password;
+
+ return $this;
+ }
+
+ /**
+ * Set Alias.
+ *
+ * @param Alias $alias
+ * @return $this
+ */
+ public function setAlias(Alias $alias)
+ {
+ $this->parameters['alias'] = $alias->__toString();
+
+ return $this;
+ }
+
+ /**
+ * Set ECI.
+ *
+ * @param Eci $eci
+ * @return $this
+ */
+ public function setEci(Eci $eci)
+ {
+ $this->parameters['eci'] = (string) $eci;
+
+ return $this;
+ }
+
+ /**
+ * Set CVC.
+ *
+ * @param $cvc
+ * @return $this
+ */
+ public function setCvc($cvc)
+ {
+ $this->parameters['cvc'] = $cvc;
+
+ return $this;
+ }
+
+ /**
+ * Set CreditDebit Flag.
+ *
+ * @param $creditDebit
+ * @return $this
+ */
+ public function setCreditDebit($creditDebit)
+ {
+ $this->parameters['creditdebit'] = $creditDebit;
+
+ return $this;
+ }
+
+ protected function getValidOperations()
+ {
+ return array(
+ PaymentOperation::REQUEST_FOR_AUTHORISATION,
+ PaymentOperation::REQUEST_FOR_DIRECT_SALE,
+ PaymentOperation::REFUND,
+ PaymentOperation::REQUEST_FOR_PRE_AUTHORISATION,
+ );
+ }
+}
diff --git a/lib/Ogone/DirectLink/DirectLinkPaymentResponse.php b/lib/Ogone/DirectLink/DirectLinkPaymentResponse.php
new file mode 100644
index 0000000..e345552
--- /dev/null
+++ b/lib/Ogone/DirectLink/DirectLinkPaymentResponse.php
@@ -0,0 +1,62 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\DirectLink;
+
+use Ogone\AbstractPaymentResponse;
+use SimpleXMLElement;
+use InvalidArgumentException;
+
+class DirectLinkPaymentResponse extends AbstractPaymentResponse
+{
+
+ public function __construct($xml_string)
+ {
+ libxml_use_internal_errors(true);
+
+ if (simplexml_load_string($xml_string)) {
+ $xmlResponse = new SimpleXMLElement($xml_string);
+
+ $attributesArray = $this->xmlAttributesToArray($xmlResponse->attributes());
+
+ // Check HTML_ANSWER if exists
+ $answer = $xmlResponse->xpath('//HTML_ANSWER');
+ if (count($answer) > 0) {
+ $attributesArray['HTML_ANSWER'] = $answer[0]->__toString();
+ }
+
+ // use lowercase internally
+ $attributesArray = array_change_key_case($attributesArray, CASE_UPPER);
+
+ // filter request for Ogone parameters
+ $this->parameters = $this->filterRequestParameters($attributesArray);
+
+ if ($this->logger) {
+ $this->logger->debug(sprintf('Response %s', get_class($this)), $this->parameters);
+ }
+
+ } else {
+ throw new InvalidArgumentException("No valid XML-string given");
+ }
+ }
+
+ private function xmlAttributesToArray($attributes)
+ {
+ $attributesArray = array();
+
+ if (count($attributes)) {
+ foreach ($attributes as $key => $value) {
+ $attributesArray[(string)$key] = (string)$value;
+ }
+ }
+
+ return $attributesArray;
+ }
+}
diff --git a/lib/Ogone/DirectLink/DirectLinkQueryRequest.php b/lib/Ogone/DirectLink/DirectLinkQueryRequest.php
new file mode 100644
index 0000000..2b3db32
--- /dev/null
+++ b/lib/Ogone/DirectLink/DirectLinkQueryRequest.php
@@ -0,0 +1,63 @@
+
+ */
+
+namespace Ogone\DirectLink;
+
+use Ogone\AbstractDirectLinkRequest;
+use Ogone\ShaComposer\ShaComposer;
+
+class DirectLinkQueryRequest extends AbstractDirectLinkRequest
+{
+
+ const TEST = "https://secure.ogone.com/ncol/test/querydirect_utf8.asp";
+ const PRODUCTION = "https://secure.ogone.com/ncol/prod/querydirect_utf8.asp";
+
+ public function __construct(ShaComposer $shaComposer)
+ {
+ $this->shaComposer = $shaComposer;
+ $this->ogoneUri = self::TEST;
+ }
+
+ public function setPayIdSub($payidsub)
+ {
+ $this->parameters['payidsub'] = $payidsub;
+ }
+
+ public function getRequiredFields()
+ {
+ return array(
+ 'pspid',
+ 'userid',
+ 'pswd',
+ );
+ }
+
+ public function getValidOgoneUris()
+ {
+ return array(self::TEST, self::PRODUCTION);
+ }
+
+ public function validate()
+ {
+ parent::validate();
+
+ foreach ($this->getRequiredFieldGroups() as $group) {
+ $empty = true;
+
+ foreach ($group as $field) {
+ if (!empty($this->parameters[$field])) {
+ $empty = false;
+ break;
+ }
+ }
+
+ if ($empty) {
+ throw new \RuntimeException(
+ sprintf("At least one of these fields should not be empty: %s", implode(', ', $group))
+ );
+ }
+ }
+ }
+}
diff --git a/lib/Ogone/DirectLink/DirectLinkQueryResponse.php b/lib/Ogone/DirectLink/DirectLinkQueryResponse.php
new file mode 100644
index 0000000..b62b9ec
--- /dev/null
+++ b/lib/Ogone/DirectLink/DirectLinkQueryResponse.php
@@ -0,0 +1,73 @@
+
+ */
+
+namespace Ogone\DirectLink;
+
+use Ogone\AbstractPaymentResponse;
+use SimpleXMLElement;
+use InvalidArgumentException;
+
+class DirectLinkQueryResponse extends AbstractPaymentResponse
+{
+
+ public function __construct($xml_string)
+ {
+ libxml_use_internal_errors(true);
+
+ if (simplexml_load_string($xml_string)) {
+ $xmlResponse = new SimpleXMLElement($xml_string);
+
+ $attributesArray = $this->xmlAttributesToArray($xmlResponse->attributes());
+
+ // use lowercase internally
+ $attributesArray = array_change_key_case($attributesArray, CASE_UPPER);
+
+ // filter request for Ogone parameters
+ $this->parameters = $this->filterRequestParameters($attributesArray);
+
+ if ($this->logger) {
+ $this->logger->debug(sprintf('Response %s', get_class($this)), $this->parameters);
+ }
+
+ } else {
+ throw new InvalidArgumentException("No valid XML-string given");
+ }
+ }
+
+ public function isSuccessful()
+ {
+ return (0 == $this->getParam('NCERROR'));
+ }
+
+ protected function filterRequestParameters(array $httpRequest)
+ {
+ return array_intersect_key(
+ $httpRequest,
+ array_flip(
+ array_merge(
+ $this->ogoneFields,
+ array(
+ 'PAYIDSUB',
+ 'NCSTATUS',
+ 'NCERRORPLUS',
+ )
+ )
+ )
+ );
+ }
+
+ private function xmlAttributesToArray($attributes)
+ {
+ $attributesArray = array();
+
+ if (count($attributes)) {
+ foreach ($attributes as $key => $value) {
+ $attributesArray[(string)$key] = (string)$value;
+ }
+ }
+
+ return $attributesArray;
+ }
+}
diff --git a/lib/Ogone/DirectLink/Eci.php b/lib/Ogone/DirectLink/Eci.php
new file mode 100644
index 0000000..ad82a6c
--- /dev/null
+++ b/lib/Ogone/DirectLink/Eci.php
@@ -0,0 +1,53 @@
+code = $eciCode;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->code;
+ }
+}
diff --git a/lib/Ogone/DirectLink/MaintenanceOperation.php b/lib/Ogone/DirectLink/MaintenanceOperation.php
new file mode 100644
index 0000000..1516705
--- /dev/null
+++ b/lib/Ogone/DirectLink/MaintenanceOperation.php
@@ -0,0 +1,48 @@
+operation = $operation;
+ }
+
+ public function equals(MaintenanceOperation $other)
+ {
+ return $this->operation === $other->operation;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->operation;
+ }
+
+ private function getAllAvailableOperations()
+ {
+ return array(
+ self::OPERATION_AUTHORISATION_RENEW,
+ self::OPERATION_AUTHORISATION_DELETE,
+ self::OPERATION_AUTHORISATION_DELETE_AND_CLOSE,
+ self::OPERATION_CAPTURE_PARTIAL,
+ self::OPERATION_CAPTURE_LAST_OR_FULL,
+ self::OPERATION_REFUND_PARTIAL,
+ self::OPERATION_REFUND_LAST_OR_FULL,
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/Ogone/DirectLink/PaymentOperation.php b/lib/Ogone/DirectLink/PaymentOperation.php
new file mode 100644
index 0000000..28aaa75
--- /dev/null
+++ b/lib/Ogone/DirectLink/PaymentOperation.php
@@ -0,0 +1,42 @@
+operation = $operation;
+ }
+
+ public function equals(PaymentOperation $other)
+ {
+ return $this->operation === $other->operation;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->operation;
+ }
+
+ public function getAllAvailableOperations()
+ {
+ return array(
+ self::REQUEST_FOR_AUTHORISATION,
+ self::REQUEST_FOR_DIRECT_SALE,
+ self::REFUND,
+ self::REQUEST_FOR_PRE_AUTHORISATION
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/Ogone/Ecommerce/Alias.php b/lib/Ogone/Ecommerce/Alias.php
new file mode 100644
index 0000000..0a8fdc4
--- /dev/null
+++ b/lib/Ogone/Ecommerce/Alias.php
@@ -0,0 +1,75 @@
+ 50) {
+ throw new InvalidArgumentException("Alias is too long");
+ }
+
+ if (preg_match('/[^a-zA-Z0-9_-]/', $alias)) {
+ throw new InvalidArgumentException("Alias cannot contain special characters");
+ }
+
+ $this->aliasOperation = $aliasOperation;
+ $this->aliasUsage = $aliasUsage;
+ $this->alias = $alias;
+ }
+
+ public function operationByMerchant()
+ {
+ $this->aliasOperation = self::OPERATION_BY_MERCHANT;
+ }
+
+ public function operationByPsp()
+ {
+ $this->aliasOperation = self::OPERATION_BY_PSP;
+ }
+
+ public function getAliasOperation()
+ {
+ return $this->aliasOperation;
+ }
+
+ public function getAliasUsage()
+ {
+ return $this->aliasUsage;
+ }
+
+ public function setAliasUsage($aliasUsage)
+ {
+ $this->aliasUsage = $aliasUsage;
+ }
+
+ public function getAlias()
+ {
+ return $this->alias;
+ }
+
+ public function setAlias($alias)
+ {
+ $this->alias = $alias;
+ }
+
+ public function __toString()
+ {
+ return $this->alias;
+ }
+}
diff --git a/lib/Ogone/Ecommerce/EcommercePaymentRequest.php b/lib/Ogone/Ecommerce/EcommercePaymentRequest.php
new file mode 100644
index 0000000..632e7b1
--- /dev/null
+++ b/lib/Ogone/Ecommerce/EcommercePaymentRequest.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Ecommerce;
+
+use Ogone\AbstractPaymentRequest;
+use Ogone\DirectLink\PaymentOperation;
+use Ogone\ShaComposer\ShaComposer;
+
+class EcommercePaymentRequest extends AbstractPaymentRequest
+{
+
+ const TEST = "https://e-payment.postfinance.ch/ncol/test/orderstandard_utf8.asp";
+ const PRODUCTION = "https://e-payment.postfinance.ch/ncol/prod/orderstandard_utf8.asp";
+
+ public function __construct(ShaComposer $shaComposer)
+ {
+ $this->shaComposer = $shaComposer;
+ $this->ogoneUri = self::TEST;
+ }
+
+ public function getRequiredFields()
+ {
+ return array(
+ 'pspid', 'currency', 'amount', 'orderid'
+ );
+ }
+
+ public function getValidOgoneUris()
+ {
+ return array(self::TEST, self::PRODUCTION);
+ }
+
+ public function setAlias(Alias $alias)
+ {
+ $this->parameters['aliasOperation'] = $alias->getAliasOperation();
+ $this->parameters['aliasusage'] = $alias->getAliasUsage();
+ $this->parameters['alias'] = $alias->getAlias();
+
+ return $this;
+ }
+
+ /**
+ * Get SHA Sign
+ * @override AbstractRequest::getShaSign()
+ * @return string
+ */
+ public function getShaSign()
+ {
+ return $this->shaComposer->compose($this->toArray());
+ }
+
+ protected function getValidOperations()
+ {
+ return array(
+ PaymentOperation::REQUEST_FOR_AUTHORISATION,
+ PaymentOperation::REQUEST_FOR_DIRECT_SALE,
+ PaymentOperation::REQUEST_FOR_PRE_AUTHORISATION,
+ );
+ }
+}
diff --git a/lib/Ogone/Ecommerce/EcommercePaymentResponse.php b/lib/Ogone/Ecommerce/EcommercePaymentResponse.php
new file mode 100644
index 0000000..5f21353
--- /dev/null
+++ b/lib/Ogone/Ecommerce/EcommercePaymentResponse.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Ecommerce;
+
+use Ogone\AbstractPaymentResponse;
+use Ogone\ShaComposer\ShaComposer;
+
+class EcommercePaymentResponse extends AbstractPaymentResponse
+{
+
+ /**
+ * Checks if the response is valid
+ * @param ShaComposer $shaComposer
+ * @return bool
+ */
+ public function isValid(ShaComposer $shaComposer)
+ {
+ return $shaComposer->compose($this->parameters, true) == $this->shaSign;
+ }
+}
diff --git a/lib/Ogone/Encoding.php b/lib/Ogone/Encoding.php
new file mode 100644
index 0000000..1ea5c0c
--- /dev/null
+++ b/lib/Ogone/Encoding.php
@@ -0,0 +1,56 @@
+ $value) {
+ $key = mb_convert_encoding($data, $out_charset, $key);
+ if (is_string($value)) {
+ $value = mb_convert_encoding($data, $out_charset, $value);
+ $result[$key] = $value;
+ } elseif (is_array($value)) {
+ $result[$key] = convert($data, $in_charset, $out_charset);
+ }
+ }
+
+ return $result;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Convert data from UTF-8 to Western European.
+ *
+ * @param string|array $data
+ * @return string|array
+ */
+ public static function convertToLatin($data) {
+ return self::convert($data, 'UTF-8', 'ISO-8859-1');
+ }
+
+ /**
+ * Convert data from Western European to UTF-8.
+ *
+ * @param string|array $data
+ * @return string|array
+ */
+ public static function convertToUtf8($data) {
+ return self::convert($data, 'ISO-8859-1', 'UTF-8');
+ }
+}
diff --git a/lib/Ogone/FlexCheckout/Alias.php b/lib/Ogone/FlexCheckout/Alias.php
new file mode 100644
index 0000000..b1bfdee
--- /dev/null
+++ b/lib/Ogone/FlexCheckout/Alias.php
@@ -0,0 +1,34 @@
+alias = $alias;
+ }
+
+ public function getAlias()
+ {
+ return $this->alias;
+ }
+
+ public function setAlias($alias)
+ {
+ $this->alias = $alias;
+ }
+
+ public function __toString()
+ {
+ return $this->alias;
+ }
+}
\ No newline at end of file
diff --git a/lib/Ogone/FlexCheckout/FlexCheckoutPaymentRequest.php b/lib/Ogone/FlexCheckout/FlexCheckoutPaymentRequest.php
new file mode 100644
index 0000000..89e1d33
--- /dev/null
+++ b/lib/Ogone/FlexCheckout/FlexCheckoutPaymentRequest.php
@@ -0,0 +1,138 @@
+shaComposer = $shaComposer;
+ $this->ogoneUri = self::TEST;
+ }
+
+ public function getCheckoutUrl()
+ {
+ return $this->getOgoneUri()."?". http_build_query($this->toArray());
+ }
+
+ public function getRequiredFields()
+ {
+ return array(
+ 'account.pspid',
+ 'alias.orderid',
+ 'card.paymentmethod',
+ 'parameters.accepturl',
+ 'parameters.exceptionurl',
+ );
+ }
+
+ public function getValidOgoneUris()
+ {
+ return array(self::TEST, self::PRODUCTION);
+ }
+
+ public function setPspId($pspid)
+ {
+ $this->parameters['account.pspid'] = $pspid;
+
+ return $this;
+ }
+
+ public function setOrderId($orderid)
+ {
+ $this->parameters['alias.orderid'] = $orderid;
+
+ return $this;
+ }
+
+ public function setAliasId(Alias $alias)
+ {
+ $this->parameters['alias.aliasid'] = $alias->getAlias();
+
+ return $this;
+ }
+
+ /**
+ * It indicates whether you want to store a temporary (N) or indefinite (Y) Alias. The possible values are:
+ * "N": the alias will be deleted after 2 hours.
+ * "Y": the alias will be stored indefinitely, for future use.
+ * @param $value
+ */
+ public function setStorePermanently($value)
+ {
+ $this->parameters['alias.storepermanently'] = $value;
+
+ return $this;
+ }
+
+ public function setPm($payment_method)
+ {
+ //if (!in_array($payment_method, $this->payment_methods)) {
+ // throw new \InvalidArgumentException("Unknown Payment method [$payment_method].");
+ //}
+ $this->parameters['card.paymentmethod'] = $payment_method;
+
+ return $this;
+ }
+
+ public function setAccepturl($accepturl)
+ {
+ $this->validateUri($accepturl);
+ $this->parameters['parameters.accepturl'] = $accepturl;
+
+ return $this;
+ }
+
+ public function setExceptionurl($exceptionurl)
+ {
+ $this->validateUri($exceptionurl);
+ $this->parameters['parameters.exceptionurl'] = $exceptionurl;
+
+ return $this;
+ }
+
+ public function setLanguage($language)
+ {
+ $this->parameters['layout.language'] = $language;
+
+ return $this;
+ }
+
+ public function setShaSign()
+ {
+ $this->parameters['shasignature.shasign'] = parent::getShaSign();
+
+ return $this;
+ }
+
+ public function setTemplate($template)
+ {
+ $this->parameters['layout.templatename'] = $template;
+
+ return $this;
+ }
+
+ public function setPaymentBrand($brand)
+ {
+ $this->parameters['card.brand'] = $brand;
+
+ return $this;
+ }
+
+ protected function getValidOperations()
+ {
+ return [];
+ }
+}
\ No newline at end of file
diff --git a/lib/Ogone/FlexCheckout/FlexCheckoutPaymentResponse.php b/lib/Ogone/FlexCheckout/FlexCheckoutPaymentResponse.php
new file mode 100644
index 0000000..076d3b7
--- /dev/null
+++ b/lib/Ogone/FlexCheckout/FlexCheckoutPaymentResponse.php
@@ -0,0 +1,76 @@
+compose($this->parameters) == $this->shaSign;
+ }
+
+ public function isSuccessful()
+ {
+ return in_array($this->getParam(static::PARAM_ALIAS_STATUS),
+ array(static::STATUS_OK, static::STATUS_ALIAS_UPDATED,));
+ }
+}
\ No newline at end of file
diff --git a/lib/Ogone/FormGenerator/FormGenerator.php b/lib/Ogone/FormGenerator/FormGenerator.php
new file mode 100644
index 0000000..e7ae901
--- /dev/null
+++ b/lib/Ogone/FormGenerator/FormGenerator.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\FormGenerator;
+
+use Ogone\Ecommerce\EcommercePaymentRequest;
+
+interface FormGenerator
+{
+ /**
+ * @param EcommercePaymentRequest $paymentRequest
+ * @return string
+ */
+ public function render(EcommercePaymentRequest $paymentRequest);
+}
diff --git a/lib/Ogone/FormGenerator/SimpleFormGenerator.php b/lib/Ogone/FormGenerator/SimpleFormGenerator.php
new file mode 100644
index 0000000..56ffbd2
--- /dev/null
+++ b/lib/Ogone/FormGenerator/SimpleFormGenerator.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\FormGenerator;
+
+use Ogone\Ecommerce\EcommercePaymentRequest;
+
+class SimpleFormGenerator implements FormGenerator
+{
+ /**
+ * @deprecated
+ * @var null
+ */
+ private $formName = null;
+
+ /**
+ * @deprecated
+ * @var null
+ */
+ private $showSubmitButton = null;
+
+ /**
+ * @param EcommercePaymentRequest $ecommercePaymentRequest
+ * @param string $formName
+ * @param bool $showSubmitButton
+ * @param string $textSubmitButton The text displayed on the submit button of the form. Defaults to "Submit"
+ * @return string HTML
+ */
+ public function render(EcommercePaymentRequest $ecommercePaymentRequest, $formName = 'ogone', $showSubmitButton = true, $textSubmitButton = 'Submit')
+ {
+ $formName = null !== $this->formName?$this->formName:$formName;
+ $showSubmitButton = null !== $this->showSubmitButton?$this->showSubmitButton:$showSubmitButton;
+
+ ob_start();
+ include __DIR__.'/template/simpleForm.php';
+ return ob_get_clean();
+ }
+
+ /**
+ * @deprecated Will be removed in next major released, directly integrated in render method.
+ * @param bool $bool
+ */
+ public function showSubmitButton($bool = true)
+ {
+ $this->showSubmitButton = $bool;
+ }
+
+ /**
+ * @deprecated Will be removed in next major released, directly integrated in render method.
+ * @param $formName
+ */
+ public function setFormName($formName)
+ {
+ $this->formName = $formName;
+ }
+}
diff --git a/lib/Ogone/FormGenerator/UrlGenerator.php b/lib/Ogone/FormGenerator/UrlGenerator.php
new file mode 100644
index 0000000..dd494a9
--- /dev/null
+++ b/lib/Ogone/FormGenerator/UrlGenerator.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\FormGenerator;
+
+use Ogone\Ecommerce\EcommercePaymentRequest;
+use Ogone\PaymentRequest;
+
+/**
+ * Creates an url that can be used to redirect the user to Ogone. It can also be used to show a link to Ogone.
+ *
+ * @author Joris van de Sande
+ */
+class UrlGenerator implements FormGenerator
+{
+
+ /**
+ * @param EcommercePaymentRequest $paymentRequest
+ * @return string url
+ */
+ public function render(EcommercePaymentRequest $paymentRequest)
+ {
+ $parameters = $paymentRequest->toArray();
+
+ $parameters[PaymentRequest::SHASIGN_FIELD] = $paymentRequest->getShaSign();
+
+ return $paymentRequest->getOgoneUri() . '?' . http_build_query($parameters);
+ }
+}
diff --git a/lib/Ogone/FormGenerator/template/simpleForm.php b/lib/Ogone/FormGenerator/template/simpleForm.php
new file mode 100644
index 0000000..1413397
--- /dev/null
+++ b/lib/Ogone/FormGenerator/template/simpleForm.php
@@ -0,0 +1,12 @@
+
diff --git a/lib/Ogone/HashAlgorithm.php b/lib/Ogone/HashAlgorithm.php
new file mode 100644
index 0000000..a2c8fa0
--- /dev/null
+++ b/lib/Ogone/HashAlgorithm.php
@@ -0,0 +1,33 @@
+algorithm = $algorithm;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->algorithm;
+ }
+}
diff --git a/lib/Ogone/Logger/LoggerBuilder.php b/lib/Ogone/Logger/LoggerBuilder.php
new file mode 100644
index 0000000..3a02ebf
--- /dev/null
+++ b/lib/Ogone/Logger/LoggerBuilder.php
@@ -0,0 +1,53 @@
+logger;
+ }
+
+ /**
+ * build logger.
+ *
+ * @param $channel
+ * @param string $path
+ * @param int $level
+ *
+ * @return LoggerBuilder
+ *
+ * @throws \Exception
+ */
+ public function createLogger($channel, $path = '/tmp/ogone_sdk.log', $level = Logger::DEBUG)
+ {
+ $this->logger = new Logger($channel);
+ $this->logger->pushHandler(new StreamHandler($path, $level));
+ $this->logger->pushProcessor(new WebProcessor());
+
+ return $this;
+ }
+}
diff --git a/lib/Ogone/ParameterFilter/AliasShaInParameterFilter.php b/lib/Ogone/ParameterFilter/AliasShaInParameterFilter.php
new file mode 100644
index 0000000..e814d46
--- /dev/null
+++ b/lib/Ogone/ParameterFilter/AliasShaInParameterFilter.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\ParameterFilter;
+
+class AliasShaInParameterFilter implements ParameterFilter
+{
+ private $allowed = array(
+ 'ACCEPTURL', 'ALIAS', 'ALIASPERSISTEDAFTERUSE', 'BRAND', 'EXCEPTIONURL',
+ 'LANGUAGE', 'ORDERID', 'PARAMPLUS', 'PSPID'
+ );
+
+ public function filter(array $parameters)
+ {
+ $parameters = array_change_key_case($parameters, CASE_UPPER);
+ return array_intersect_key($parameters, array_flip($this->allowed));
+ }
+}
diff --git a/lib/Ogone/ParameterFilter/GeneralParameterFilter.php b/lib/Ogone/ParameterFilter/GeneralParameterFilter.php
new file mode 100644
index 0000000..6d898ce
--- /dev/null
+++ b/lib/Ogone/ParameterFilter/GeneralParameterFilter.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\ParameterFilter;
+
+class GeneralParameterFilter implements ParameterFilter
+{
+ public function filter(array $parameters)
+ {
+ $parameters = array_change_key_case($parameters, CASE_UPPER);
+ array_walk($parameters, 'trim');
+ $parameters = array_filter($parameters, function ($value) {
+ return (bool) strlen($value);
+
+ });
+
+ return $parameters;
+ }
+}
diff --git a/lib/Ogone/ParameterFilter/ParameterFilter.php b/lib/Ogone/ParameterFilter/ParameterFilter.php
new file mode 100644
index 0000000..0e3c07e
--- /dev/null
+++ b/lib/Ogone/ParameterFilter/ParameterFilter.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\ParameterFilter;
+
+interface ParameterFilter
+{
+ /** @return array Filtered parameters */
+ function filter(array $parameters);
+}
diff --git a/lib/Ogone/ParameterFilter/ShaInParameterFilter.php b/lib/Ogone/ParameterFilter/ShaInParameterFilter.php
new file mode 100644
index 0000000..31e53eb
--- /dev/null
+++ b/lib/Ogone/ParameterFilter/ShaInParameterFilter.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\ParameterFilter;
+
+/** @todo test this */
+class ShaInParameterFilter implements ParameterFilter
+{
+ private $allowed = array(
+ 'ACCEPTURL', 'ADDMATCH', 'ADDRMATCH', 'ALIAS', 'ALIASOPERATION', 'ALIASPERSISTEDAFTERUSE', 'ALIASUSAGE',
+ 'ALLOWCORRECTION', 'AMOUNT', 'AMOUNTHTVA', 'AMOUNTTVA', 'BACKURL', 'BGCOLOR',
+ 'BRAND', 'BRANDVISUAL', 'BUTTONBGCOLOR', 'BUTTONTXTCOLOR', 'CANCELURL',
+ 'CARDNO', 'CATALOGURL', 'CERTID', 'CHECK_AAV', 'CIVILITY', 'CN', 'COM',
+ 'COMPLUS', 'COSTCENTER', 'CREDITCODE', 'CUID', 'CURRENCY', 'CVC', 'DATA',
+ 'DATATYPE', 'DATEIN', 'DATEOUT', 'DECLINEURL', 'DEVICE', 'DISCOUNTRATE', 'ECI', 'ECOM_BILLTO_POSTAL_CITY',
+ 'ECOM_BILLTO_POSTAL_COUNTRYCODE', 'ECOM_BILLTO_POSTAL_NAME_FIRST', 'ECOM_BILLTO_POSTAL_NAME_LAST',
+ 'ECOM_BILLTO_POSTAL_POSTALCODE', 'ECOM_BILLTO_POSTAL_STREET_LINE1', 'ECOM_BILLTO_POSTAL_STREET_LINE2',
+ 'ECOM_BILLTO_POSTAL_STREET_NUMBER', 'ECOM_CONSUMERID', 'ECOM_CONSUMERORDERID',
+ 'ECOM_CONSUMERUSERALIAS', 'ECOM_PAYMENT_CARD_EXPDATE_MONTH', 'ECOM_PAYMENT_CARD_EXPDATE_YEAR',
+ 'ECOM_PAYMENT_CARD_NAME', 'ECOM_PAYMENT_CARD_VERIFICATION', 'ECOM_SHIPTO_COMPANY',
+ 'ECOM_SHIPTO_DOB', 'ECOM_SHIPTO_ONLINE_EMAIL', 'ECOM_SHIPTO_POSTAL_CITY',
+ 'ECOM_SHIPTO_POSTAL_COUNTRYCODE', 'ECOM_SHIPTO_POSTAL_NAME_FIRST', 'ECOM_SHIPTO_POSTAL_NAME_LAST',
+ 'ECOM_SHIPTO_POSTAL_POSTALCODE', 'ECOM_SHIPTO_POSTAL_STREET_LINE1', 'ECOM_SHIPTO_POSTAL_STREET_LINE2',
+ 'ECOM_SHIPTO_POSTAL_STREET_NUMBER', 'ECOM_SHIPTO_TELECOM_FAX_NUMBER', 'ECOM_SHIPTO_TELECOM_PHONE_NUMBER',
+ 'ECOM_SHIPTO_TVA', 'ED', 'EMAIL', 'EXCEPTIONURL', 'EXCLPMLIST', 'FIRSTCALL',
+ 'FLAG3D', 'FONTTYPE', 'FORCECODE1', 'FORCECODE2', 'FORCECODEHASH', 'FORCETP',
+ 'GENERIC_BL', 'GIROPAY_ACCOUNT_NUMBER', 'GIROPAY_BLZ', 'GIROPAY_OWNER_NAME',
+ 'GLOBORDERID', 'GUID', 'HDFONTTYPE', 'HDTBLBGCOLOR', 'HDTBLTXTCOLOR', 'HEIGHTFRAME',
+ 'HOMEURL', 'HTTP_ACCEPT', 'HTTP_USER_AGENT', 'INCLUDE_BIN', 'INCLUDE_COUNTRIES',
+ 'INVDATE', 'INVDISCOUNT', 'INVLEVEL', 'INVORDERID', 'ISSUERID', 'LANGUAGE',
+ 'LEVEL1AUTHCPC', 'LIMITCLIENTSCRIPTUSAGE', 'LINE_REF', 'LIST_BIN', 'LIST_COUNTRIES',
+ 'LOGO', 'MERCHANTID', 'MODE', 'MTIME', 'MVER', 'OPERATION', 'OR_INVORDERID',
+ 'OR_ORDERID', 'ORDERID', 'ORIG', 'OWNERADDRESS', 'OWNERADDRESS2', 'OWNERCTY',
+ 'OWNERTELNO', 'OWNERTOWN', 'OWNERZIP', 'PAIDAMOUNT', 'PARAMPLUS', 'PARAMVAR',
+ 'PAYID', 'PAYMETHOD', 'PM', 'PMLIST', 'PMLISTPMLISTTYPE', 'PMLISTTYPE',
+ 'PMLISTTYPEPMLIST', 'PMTYPE', 'POPUP', 'POST', 'PSPID', 'PSWD', 'REF', 'REF_CUSTOMERID',
+ 'REF_CUSTOMERREF', 'REFER', 'REFID', 'REFKIND', 'REMOTE_ADDR', 'REQGENFIELDS', 'RTIMEOUT',
+ 'RTIMEOUTREQUESTEDTIMEOUT', 'SCORINGCLIENT', 'SETT_BATCH', 'SID', 'TAAL',
+ 'TBLBGCOLOR', 'TBLTXTCOLOR', 'TID', 'TITLE', 'TOTALAMOUNT', 'TP', 'TRACK2',
+ 'TXTBADDR2', 'TXTCOLOR', 'TXTOKEN', 'TXTOKENTXTOKENPAYPAL', 'TYPE_COUNTRY',
+ 'UCAF_AUTHENTICATION_DATA', 'UCAF_PAYMENT_CARD_CVC2', 'UCAF_PAYMENT_CARD_EXPDATE_MONTH',
+ 'UCAF_PAYMENT_CARD_EXPDATE_YEAR', 'UCAF_PAYMENT_CARD_NUMBER', 'USERID', 'USERTYPE',
+ 'VERSION', 'WBTU_MSISDN', 'WBTU_ORDERID', 'WEIGHTUNIT', 'WIN3DS', 'WITHROOT', 'CARD.PAYMENTMETHOD',
+ 'ACCOUNT.PSPID', 'ALIAS.ALIASID', 'ALIAS.ORDERID', 'ALIAS.STOREPERMANENTLY', 'PARAMETERS.ACCEPTURL',
+ 'PARAMETERS.EXCEPTIONURL', 'LAYOUT.TEMPLATENAME', 'LAYOUT.LANGUAGE',
+ // @see https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/directlink/request-a-new%20order#processing-transactions-with-stored-credentials
+ 'COF_INITIATOR', 'COF_SCHEDULE', 'COF_TRANSACTION',
+ // @see https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/directlink-3-d/3-d%20secure%20v2
+ 'BROWSERACCEPTHEADER', 'BROWSERCOLORDEPTH', 'BROWSERJAVAENABLED', 'BROWSERLANGUAGE', 'BROWSERSCREENHEIGHT',
+ 'BROWSERSCREENWIDTH', 'BROWSERTIMEZONE', 'BROWSERUSERAGENT',
+ 'SHOPPINGCARTEXTENSIONID', 'ORIG'
+ );
+
+ public function filter(array $parameters)
+ {
+ $parameters = array_change_key_case($parameters, CASE_UPPER);
+ return array_intersect_key($parameters, array_flip($this->allowed));
+ }
+}
diff --git a/lib/Ogone/ParameterFilter/ShaOutParameterFilter.php b/lib/Ogone/ParameterFilter/ShaOutParameterFilter.php
new file mode 100644
index 0000000..df36d35
--- /dev/null
+++ b/lib/Ogone/ParameterFilter/ShaOutParameterFilter.php
@@ -0,0 +1,87 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\ParameterFilter;
+
+class ShaOutParameterFilter implements ParameterFilter
+{
+ private $allowed = array(
+ 'AAVADDRESS',
+ 'AAVCHECK',
+ 'AAVMAIL',
+ 'AAVNAME',
+ 'AAVPHONE',
+ 'AAVZIP',
+ 'ACCEPTANCE',
+ 'ALIAS',
+ 'AMOUNT',
+ 'BIC',
+ 'BIN',
+ 'BRAND',
+ 'CARDNO',
+ 'CCCTY',
+ 'CN',
+ 'COLLECTOR_BIC',
+ 'COLLECTOR_IBAN',
+ 'COMPLUS',
+ 'CREATION_STATUS',
+ 'CREDITDEBIT',
+ 'CURRENCY',
+ 'CVCCHECK',
+ 'DCC_COMMPERCENTAGE',
+ 'DCC_CONVAMOUNT',
+ 'DCC_CONVCCY',
+ 'DCC_EXCHRATE',
+ 'DCC_EXCHRATESOURCE',
+ 'DCC_EXCHRATETS',
+ 'DCC_INDICATOR',
+ 'DCC_MARGINPERCENTAGE',
+ 'DCC_VALIDHOURS',
+ 'DEVICEID',
+ 'DIGESTCARDNO',
+ 'ECI',
+ 'ED',
+ 'EMAIL',
+ 'ENCCARDNO',
+ 'FXAMOUNT',
+ 'FXCURRENCY',
+ 'IP',
+ 'IPCTY',
+ 'MANDATEID',
+ 'MOBILEMODE',
+ 'NBREMAILUSAGE',
+ 'NBRIPUSAGE',
+ 'NBRIPUSAGE_ALLTX',
+ 'NBRUSAGE',
+ 'NCERROR',
+ 'ORDERID',
+ 'PAYID',
+ 'PAYIDSUB',
+ 'PAYMENT_REFERENCE',
+ 'PM',
+ 'SCO_CATEGORY',
+ 'SCORING',
+ 'SEQUENCETYPE',
+ 'SIGNDATE',
+ 'STATUS',
+ 'SUBBRAND',
+ 'SUBSCRIPTION_ID',
+ 'TICKET',
+ 'TRXDATE',
+ 'VC',
+ );
+
+ public function filter(array $parameters)
+ {
+ $parameters = array_change_key_case($parameters, CASE_UPPER);
+ return array_intersect_key($parameters, array_flip($this->allowed));
+ }
+}
diff --git a/lib/Ogone/Passphrase.php b/lib/Ogone/Passphrase.php
new file mode 100644
index 0000000..459a450
--- /dev/null
+++ b/lib/Ogone/Passphrase.php
@@ -0,0 +1,40 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone;
+
+/**
+ * Ogone Passphrase Value Object
+ */
+final class Passphrase
+{
+ /**
+ * @var string
+ */
+ private $passphrase;
+
+ /** @@codeCoverageIgnore */
+ public function __construct($passphrase)
+ {
+ if (!is_string($passphrase)) {
+ throw new \InvalidArgumentException("String expected");
+ }
+ $this->passphrase = $passphrase;
+ }
+
+ /**
+ * String representation
+ */
+ public function __toString()
+ {
+ return (string) $this->passphrase;
+ }
+}
diff --git a/lib/Ogone/PaymentRequest.php b/lib/Ogone/PaymentRequest.php
new file mode 100644
index 0000000..216bcaa
--- /dev/null
+++ b/lib/Ogone/PaymentRequest.php
@@ -0,0 +1,9 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone;
+
+interface Request
+{
+
+ public function toArray();
+
+ public function getOgoneUri();
+
+ public function getShaSign();
+
+ public function getRequiredFields();
+
+ public function getValidOgoneUris();
+}
diff --git a/lib/Ogone/Response.php b/lib/Ogone/Response.php
new file mode 100644
index 0000000..4ed24ae
--- /dev/null
+++ b/lib/Ogone/Response.php
@@ -0,0 +1,38 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone;
+
+interface Response
+{
+
+ /** @var string */
+ const SHASIGN_FIELD = 'SHASIGN';
+
+ /**
+ * @deprecated
+ */
+ public function isSuccessful();
+
+ /**
+ * Check if response parameter exists
+ * @param $key
+ * @return bool
+ */
+ public function hasParam($key);
+
+ /**
+ * Retrieves a response parameter
+ * @param string $key
+ * @throws \InvalidArgumentException
+ * @return string
+ */
+ public function getParam($key);
+}
diff --git a/lib/Ogone/ShaComposer/AllParametersShaComposer.php b/lib/Ogone/ShaComposer/AllParametersShaComposer.php
new file mode 100644
index 0000000..06c7c90
--- /dev/null
+++ b/lib/Ogone/ShaComposer/AllParametersShaComposer.php
@@ -0,0 +1,87 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\ShaComposer;
+
+use Ogone\Encoding;
+use Ogone\ParameterFilter\GeneralParameterFilter;
+use Ogone\Passphrase;
+use Ogone\HashAlgorithm;
+use Ogone\ParameterFilter\ParameterFilter;
+
+/**
+ * SHA string composition the "new way", using all parameters in the ogone response
+ */
+class AllParametersShaComposer implements ShaComposer
+{
+ /** @var array of ParameterFilter */
+ private $parameterFilters;
+
+ /**
+ * @var string Passphrase
+ */
+ private $passphrase;
+
+ /**
+ * @var HashAlgorithm
+ */
+ private $hashAlgorithm;
+
+ public function __construct(Passphrase $passphrase, HashAlgorithm $hashAlgorithm = null)
+ {
+ $this->passphrase = $passphrase;
+
+ $this->addParameterFilter(new GeneralParameterFilter);
+
+ $this->hashAlgorithm = $hashAlgorithm ?: new HashAlgorithm(HashAlgorithm::HASH_SHA1);
+ }
+
+ /**
+ * Compose SHA string based on Ingenico response parameters.
+ *
+ * @param array $parameters
+ * @param bool $useLatinCharset Deprecated
+ */
+ public function compose(array $parameters, $useLatinCharset = false)
+ {
+ foreach ($this->parameterFilters as $parameterFilter) {
+ $parameters = $parameterFilter->filter($parameters);
+ }
+
+ // Sort parameters using Collator
+ if (extension_loaded('intl') === true) {
+ $keys = array_keys($parameters);
+ $values = array_values($parameters);
+ collator_asort(collator_create('root'), $keys);
+
+ $parameters = [];
+ foreach ($keys as $index => $key) {
+ $parameters[$key] = $values[$index];
+ }
+ } else {
+ // This function have problem with SCO_CATEGORY and SCORING order
+ ksort($parameters);
+ }
+
+ // compose SHA string
+ $shaString = '';
+ foreach ($parameters as $key => $value) {
+ $shaString .= $key . '=' . $value . $this->passphrase;
+ }
+
+ return strtoupper(hash($this->hashAlgorithm, $shaString));
+ }
+
+ public function addParameterFilter(ParameterFilter $parameterFilter)
+ {
+ $this->parameterFilters[] = $parameterFilter;
+ }
+}
diff --git a/lib/Ogone/ShaComposer/LegacyShaComposer.php b/lib/Ogone/ShaComposer/LegacyShaComposer.php
new file mode 100644
index 0000000..bf877df
--- /dev/null
+++ b/lib/Ogone/ShaComposer/LegacyShaComposer.php
@@ -0,0 +1,65 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\ShaComposer;
+
+use Ogone\HashAlgorithm;
+use Ogone\Passphrase;
+
+/**
+ * SHA string composition the "old way", using only the "main" parameters
+ * @deprecated Use AllParametersShaComposer wherever possible
+ */
+class LegacyShaComposer implements ShaComposer
+{
+ /**
+ * @var string Passphrase
+ */
+ private $passphrase;
+
+ /**
+ * @var HashAlgorithm
+ */
+ private $hashAlgorithm;
+
+ /**
+ * @param Passphrase $passphrase
+ * @param HashAlgorithm $hashAlgorithm
+ */
+ public function __construct(Passphrase $passphrase, HashAlgorithm $hashAlgorithm = null)
+ {
+ $this->passphrase = $passphrase;
+ $this->hashAlgorithm = $hashAlgorithm ?: new HashAlgorithm(HashAlgorithm::HASH_SHA1);
+ }
+
+ /**
+ * @param array $parameters
+ * @return string
+ */
+ public function compose(array $parameters)
+ {
+ $parameters = array_change_key_case($parameters, CASE_LOWER);
+
+ return strtoupper(hash($this->hashAlgorithm, implode('', array(
+ $parameters['orderid'],
+ $parameters['currency'],
+ $parameters['amount'],
+ $parameters['pm'],
+ $parameters['acceptance'],
+ $parameters['status'],
+ $parameters['cardno'],
+ $parameters['payid'],
+ $parameters['ncerror'],
+ $parameters['brand'],
+ $this->passphrase
+ ))));
+ }
+}
diff --git a/lib/Ogone/ShaComposer/ShaComposer.php b/lib/Ogone/ShaComposer/ShaComposer.php
new file mode 100644
index 0000000..2811a9c
--- /dev/null
+++ b/lib/Ogone/ShaComposer/ShaComposer.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\ShaComposer;
+
+/**
+ * SHA Composers interface
+ */
+interface ShaComposer
+{
+ /**
+ * Compose SHA string based on Ingenico response parameters.
+ *
+ * @param array $parameters
+ * @param bool $useLatinCharset
+ */
+ public function compose(array $parameters, $useLatinCharset = false);
+}
diff --git a/lib/Ogone/Subscription/SubscriptionPaymentRequest.php b/lib/Ogone/Subscription/SubscriptionPaymentRequest.php
new file mode 100644
index 0000000..c8d7dbb
--- /dev/null
+++ b/lib/Ogone/Subscription/SubscriptionPaymentRequest.php
@@ -0,0 +1,178 @@
+= 1.0E+15) {
+ throw new InvalidArgumentException("Amount is too high");
+ }
+
+ $this->parameters['amount'] = $amount;
+
+ }
+
+ /**
+ * Unique identifier of the subscription. The subscription id must be assigned dynamically.
+ * @author René de Kat
+ *
+ * @param string $subscriptionId (maxlength 50)
+ */
+ public function setSubscriptionId($subscriptionId)
+ {
+ if (strlen($subscriptionId) > 50) {
+ throw new InvalidArgumentException("Subscription id cannot be longer than 50 characters");
+ }
+ if (preg_match('/[^a-zA-Z0-9_-]/', $subscriptionId)) {
+ throw new InvalidArgumentException("Subscription id cannot contain special characters");
+ }
+ $this->parameters['subscription_id'] = $subscriptionId;
+ }
+
+ /**
+ * Amount of the subscription (can be different from the amount of the original transaction)
+ * multiplied by 100, since the format of the amount must not contain any decimals or other separators.
+ *
+ * @author René de Kat
+ *
+ * @param integer $amount
+ */
+ public function setSubscriptionAmount($amount)
+ {
+ if (!is_int($amount)) {
+ throw new InvalidArgumentException("Integer expected. Amount is always in cents");
+ }
+ if ($amount <= 0) {
+ throw new InvalidArgumentException("Amount must be a positive number");
+ }
+ if ($amount >= 1.0E+15) {
+ throw new InvalidArgumentException("Amount is too high");
+ }
+ $this->parameters['sub_amount'] = $amount;
+ }
+
+ /**
+ * Order description
+ * @author René de Kat
+ *
+ * @param string $description (maxlength 100)
+ */
+ public function setSubscriptionDescription($description)
+ {
+ if (strlen($description) > 100) {
+ throw new InvalidArgumentException("Subscription description cannot be longer than 100 characters");
+ }
+ if (preg_match('/[^a-zA-Z0-9_ -]/', $description)) {
+ throw new InvalidArgumentException("Subscription description cannot contain special characters");
+ }
+ $this->parameters['sub_com'] = $description;
+ }
+
+ /**
+ * OrderID for subscription payments
+ * @author René de Kat
+ *
+ * @param string $orderId (maxlength 40)
+ */
+ public function setSubscriptionOrderId($orderId)
+ {
+ if (strlen($orderId) > 40) {
+ throw new InvalidArgumentException("Subscription order id cannot be longer than 40 characters");
+ }
+ if (preg_match('/[^a-zA-Z0-9_-]/', $orderId)) {
+ throw new InvalidArgumentException("Subscription order id cannot contain special characters");
+ }
+ $this->parameters['sub_orderid'] = $orderId;
+ }
+
+ /**
+ * Set subscription payment interval
+ * @author René de Kat
+ */
+ public function setSubscriptionPeriod(SubscriptionPeriod $period)
+ {
+ $this->parameters['sub_period_unit'] = $period->getUnit();
+ $this->parameters['sub_period_number'] = $period->getInterval();
+ $this->parameters['sub_period_moment'] = $period->getMoment();
+ }
+
+
+ /**
+ * Subscription start date
+ * @author René de Kat
+ *
+ * @param DateTime $date Startdate of the subscription.
+ */
+ public function setSubscriptionStartdate(DateTime $date)
+ {
+ $this->parameters['sub_startdate'] = $date->format('Y-m-d');
+ }
+
+ /**
+ * Subscription end date
+ * @author René de Kat
+ *
+ * @param DateTime $date Enddate of the subscription.
+ */
+ public function setSubscriptionEnddate(DateTime $date)
+ {
+ $this->parameters['sub_enddate'] = $date->format('Y-m-d');
+ }
+
+ /**
+ * Set subscription status
+ * @author René de Kat
+ *
+ * @param integer $status 0 = inactive, 1 = active
+ */
+ public function setSubscriptionStatus($status)
+ {
+ if (!in_array($status, array(0, 1))) {
+ throw new InvalidArgumentException("Invalid status specified for subscription. Possible values: 0 = inactive, 1 = active");
+ }
+ $this->parameters['sub_status'] = $status;
+ }
+
+ /**
+ * Set comment for merchant
+ * @author René de Kat
+ *
+ * @param string $comment
+ */
+ public function setSubscriptionComment($comment)
+ {
+ if (strlen($comment) > 200) {
+ throw new InvalidArgumentException("Subscription comment cannot be longer than 200 characters");
+ }
+ if (preg_match('/[^a-zA-Z0-9_ -]/', $comment)) {
+ throw new InvalidArgumentException("Subscription comment cannot contain special characters");
+ }
+ $this->parameters['sub_comment'] = $comment;
+ }
+
+ public function getRequiredFields()
+ {
+ return array(
+ 'pspid', 'currency', 'orderid',
+ 'subscription_id', 'sub_amount', 'sub_com', 'sub_orderid', 'sub_period_unit',
+ 'sub_period_number', 'sub_period_moment','sub_startdate', 'sub_status'
+ );
+ }
+}
diff --git a/lib/Ogone/Subscription/SubscriptionPeriod.php b/lib/Ogone/Subscription/SubscriptionPeriod.php
new file mode 100644
index 0000000..435bb2b
--- /dev/null
+++ b/lib/Ogone/Subscription/SubscriptionPeriod.php
@@ -0,0 +1,146 @@
+setUnit($unit);
+ $this->setInterval($interval);
+ $this->setMoment($moment);
+ }
+
+ /**
+ * @return string
+ */
+ public function getUnit()
+ {
+ return $this->unit;
+ }
+
+ /**
+ * @param string $unit
+ * @throws InvalidArgumentException
+ */
+ public function setUnit($unit)
+ {
+ if (!in_array($unit, array(self::UNIT_DAILY, self::UNIT_WEEKLY, self::UNIT_MONTHLY))) {
+ throw new InvalidArgumentException("Subscription period unit should be '".self::UNIT_DAILY."' (daily), '".self::UNIT_WEEKLY."' (weekly) or '".self::UNIT_MONTHLY."' (monthly)");
+ }
+
+ if (self::UNIT_WEEKLY === $unit) {
+ if ($this->moment > 7) {
+ throw new InvalidArgumentException('The unit cannot be set to weekly while the moment > 7');
+ }
+ } elseif (self::UNIT_MONTHLY === $unit && $this->moment > 28) {
+ throw new InvalidArgumentException('The unit cannot be set to monthly while the moment > 28');
+ }
+ $this->unit = $unit;
+ }
+
+ /**
+ * @return int
+ */
+ public function getInterval()
+ {
+ return $this->interval;
+ }
+
+ /**
+ * @param int $interval
+ * @throws InvalidArgumentException
+ */
+ public function setInterval($interval)
+ {
+ if (!is_int($interval)) {
+ throw new InvalidArgumentException("Integer expected for interval");
+ }
+ if ($interval < 0) {
+ throw new InvalidArgumentException("Interval must be a positive number > 0");
+ }
+ if ($interval >= 1.0E+15) {
+ throw new InvalidArgumentException("Interval is too high");
+ }
+ $this->interval = $interval;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMoment()
+ {
+ return $this->moment;
+ }
+
+ /**
+ * @param int $moment
+ * @throws InvalidArgumentException
+ */
+ public function setMoment($moment)
+ {
+ if (!is_int($moment)) {
+ throw new InvalidArgumentException("Integer expected for moment");
+ }
+ if ($moment <= 0) {
+ throw new InvalidArgumentException("Moment must be a positive number");
+ }
+ if ($moment >= 1.0E+15) {
+ throw new InvalidArgumentException("Interval is too high");
+ }
+
+ if (self::UNIT_WEEKLY == $this->unit) {
+ // Valid values are 1 to 7
+ if ($moment > 7) {
+ throw new InvalidArgumentException("Moment should be 1 (Sunday), 2, 3 .. 7 (Saturday)");
+ }
+ } elseif (self::UNIT_MONTHLY == $this->unit && $moment > 28) {
+ // We will not allow a day of month > 28
+ throw new InvalidArgumentException("Moment can't be larger than 29. Last day for month allowed is 28.");
+ }
+
+ $this->moment = $moment;
+ }
+}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..c8aaaf0
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tests/Ogone/Tests/
+
+
+
+
+
+ lib
+
+
+
+
+
+
+
+
+
+
+
+
+
+ integration
+
+
+
+
diff --git a/tests/Ogone/Tests/DirectLink/AliasTest.php b/tests/Ogone/Tests/DirectLink/AliasTest.php
new file mode 100644
index 0000000..013218b
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/AliasTest.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\DirectLink\Alias;
+
+class AliasTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function AliasCannotBeNull()
+ {
+ new Alias(null);
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function AliasCannotBeAnEmptyString()
+ {
+ new Alias('');
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function AliasIsMax50Characters()
+ {
+ new Alias(str_repeat('X', 51));
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function AliasIsAlphaNumeric()
+ {
+ new Alias('some alias with spaces, dots (.), etc');
+ }
+
+ /** @test */
+ public function CanBeRepresentedAsString()
+ {
+ $alias = new Alias('test123');
+ $this->assertEquals('test123', (string) new Alias('test123'));
+ $this->assertEquals('test123', $alias->getAlias());
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/CreateAliasRequestTest.php b/tests/Ogone/Tests/DirectLink/CreateAliasRequestTest.php
new file mode 100644
index 0000000..9424ad0
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/CreateAliasRequestTest.php
@@ -0,0 +1,107 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\Tests\ShaComposer\FakeShaComposer;
+use Ogone\DirectLink\CreateAliasRequest;
+use Ogone\DirectLink\Alias;
+
+class CreateAliasRequestTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @test
+ */
+ public function IsValidWhenRequiredFieldsAreFilledIn()
+ {
+ $aliasRequest = $this->provideMinimalAliasRequest();
+ $aliasRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function isInvalidWithNonOgoneUrl()
+ {
+ $aliasRequest = $this->provideMinimalAliasRequest();
+ $aliasRequest->setOgoneUri('http://example.com');
+ $aliasRequest->validate();
+ }
+
+ /**
+ * @test
+ */
+ public function isValidWithOgoneUrl()
+ {
+ $aliasRequest = $this->provideMinimalAliasRequest();
+ $aliasRequest->setOgoneUri(CreateAliasRequest::PRODUCTION);
+ $aliasRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \RuntimeException
+ */
+ public function IsInvalidWhenFieldsAreMissing()
+ {
+ $aliasRequest = new CreateAliasRequest(new FakeShaComposer);
+ $aliasRequest->validate();
+ }
+
+ /**
+ * @test
+ */
+ public function IsValidWithAliasSet()
+ {
+ $alias = new Alias('customer_123');
+
+ $aliasRequest = $this->provideMinimalAliasRequest();
+ $aliasRequest->setAlias($alias);
+ $aliasRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function IsInvalidWithTooLongAlias()
+ {
+ $alias = new Alias(str_repeat('repeat', 10));
+
+ $aliasRequest = $this->provideMinimalAliasRequest();
+ $aliasRequest->setAlias($alias);
+ $aliasRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function IsInvalidWithAliasWrongCharacter()
+ {
+ $alias = new Alias('customer_#!§?');
+
+ $aliasRequest = $this->provideMinimalAliasRequest();
+ $aliasRequest->setAlias($alias);
+ $aliasRequest->validate();
+ }
+
+ /** @return CreateAliasRequest*/
+ private function provideMinimalAliasRequest()
+ {
+ $aliasRequest = new CreateAliasRequest(new FakeShaComposer);
+ $aliasRequest->setPspid('18457454');
+ $aliasRequest->setAccepturl('http://example.com/accept');
+ $aliasRequest->setExceptionurl('http://example.com/exception');
+
+ return $aliasRequest;
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/CreateAliasResponseTest.php b/tests/Ogone/Tests/DirectLink/CreateAliasResponseTest.php
new file mode 100644
index 0000000..eb515f9
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/CreateAliasResponseTest.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\DirectLink\CreateAliasResponse;
+use Ogone\Tests\ShaComposer\FakeShaComposer;
+
+class CreateAliasResponseTest extends \PHPUnit_Framework_TestCase
+{
+
+ /** @test */
+ public function CanBeVerified()
+ {
+ $aRequest = $this->provideRequest();
+
+ $createAliasResponse = new CreateAliasResponse($aRequest);
+ $this->assertTrue($createAliasResponse->isValid(new FakeShaComposer));
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function CannotExistWithoutShaSign()
+ {
+ $createAliasResponse = new CreateAliasResponse(array());
+ }
+
+ /** @test */
+ public function ParametersCanBeRetrieved()
+ {
+ $aRequest = $this->provideRequest();
+
+ $createAliasResponse = new CreateAliasResponse($aRequest);
+ $this->assertEquals($aRequest['orderID'], $createAliasResponse->getParam('orderid'));
+ }
+
+ /** @test */
+ public function ChecksStatus()
+ {
+ $aRequest = $this->provideRequest();
+
+ $createAliasResponse = new CreateAliasResponse($aRequest);
+ $this->assertTrue($createAliasResponse->isSuccessful());
+ }
+
+ /** @test */
+ public function AliasIsEqual()
+ {
+ $aRequest = $this->provideRequest();
+ $createAliasResponse = new CreateAliasResponse($aRequest);
+ $alias = $createAliasResponse->getAlias();
+ $this->assertEquals('customer_123', $alias->__toString());
+ $this->assertEquals($aRequest['CN'], $alias->getCardName());
+ $this->assertEquals($aRequest['CARDNO'], $alias->getCardNumber());
+ $this->assertEquals($aRequest['ED'], $alias->getExpiryDate());
+ }
+
+ /**
+ * Helper method to setup a request array
+ */
+ private function provideRequest()
+ {
+ return array(
+ 'SHASIGN' => FakeShaComposer::FAKESHASTRING,
+ 'UNKNOWN_PARAM' => false, /* unkown parameter, should be filtered out */
+ 'status' => 0,
+ 'orderID' => '48495482424',
+ 'alias' => 'customer_123',
+ 'CN' => 'John Doe',
+ 'CARDNO' => 'xxxxxxxxxxx4848',
+ 'ED' => '1220'
+ );
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/DirectLinkMaintenanceRequestTest.php b/tests/Ogone/Tests/DirectLink/DirectLinkMaintenanceRequestTest.php
new file mode 100644
index 0000000..c0c1de0
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/DirectLinkMaintenanceRequestTest.php
@@ -0,0 +1,96 @@
+
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\DirectLink\MaintenanceOperation;
+use Ogone\Tests\ShaComposer\FakeShaComposer;
+use Ogone\DirectLink\DirectLinkMaintenanceRequest;
+
+class DirectLinkMaintenanceRequestTest extends \PHPUnit_Framework_TestCase
+{
+
+ /** @test */
+ public function IsValidWhenRequiredFieldsAreFilledIn()
+ {
+ $directLinkMaintenanceRequest = $this->provideMinimalDirectLinkMaintenanceRequest();
+ $directLinkMaintenanceRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \RuntimeException
+ */
+ public function IsInvalidWhenFieldsAreMissing()
+ {
+ $directLinkMaintenanceRequest = new DirectLinkMaintenanceRequest(new FakeShaComposer);
+ $directLinkMaintenanceRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function isInvalidWithNonOgoneUrl()
+ {
+ $directLinkMaintenanceRequest = $this->provideMinimalDirectLinkMaintenanceRequest();
+ $directLinkMaintenanceRequest->setOgoneUri('http://example.com');
+ $directLinkMaintenanceRequest->validate();
+ }
+
+ /**
+ * @test
+ */
+ public function isValidWithOgoneUrl()
+ {
+ $directLinkMaintenanceRequest = $this->provideMinimalDirectLinkMaintenanceRequest();
+ $directLinkMaintenanceRequest->setOgoneUri(DirectLinkMaintenanceRequest::PRODUCTION);
+ $directLinkMaintenanceRequest->validate();
+ }
+
+ /**
+ * @test
+ */
+ public function isValidWithIntegerAmount()
+ {
+ $directLinkMaintenanceRequest = $this->provideMinimalDirectLinkMaintenanceRequest();
+ $directLinkMaintenanceRequest->setAmount(232);
+ $directLinkMaintenanceRequest->validate();
+ }
+
+ /**
+ * @test
+ * @dataProvider provideBadParameters
+ * @expectedException \InvalidArgumentException
+ */
+ public function BadParametersCauseExceptions($method, $value)
+ {
+ $directLinkMaintenanceRequest = new DirectLinkMaintenanceRequest(new FakeShaComposer);
+ $directLinkMaintenanceRequest->$method($value);
+ }
+
+ public function provideBadParameters()
+ {
+ return array(
+ array('setPassword', '12'),
+ array('setUserid', '1'),
+ array('setAmount', '232'),
+ array('setAmount', 2.32),
+ );
+ }
+
+ /** @return DirectLinkMaintenanceRequest */
+ private function provideMinimalDirectLinkMaintenanceRequest()
+ {
+ $directLinkRequest = new DirectLinkMaintenanceRequest(new FakeShaComposer());
+ $directLinkRequest->setPspid('123456');
+ $directLinkRequest->setUserId('user_1234');
+ $directLinkRequest->setPassword('abracadabra');
+ $directLinkRequest->setPayId('12345678');
+ $directLinkRequest->setOperation(new MaintenanceOperation(MaintenanceOperation::OPERATION_AUTHORISATION_RENEW));
+
+ return $directLinkRequest;
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/DirectLinkMaintenanceResponseTest.php b/tests/Ogone/Tests/DirectLink/DirectLinkMaintenanceResponseTest.php
new file mode 100644
index 0000000..a5a9aa3
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/DirectLinkMaintenanceResponseTest.php
@@ -0,0 +1,125 @@
+
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\DirectLink\DirectLinkMaintenanceResponse;
+
+class DirectLinkMaintenanceResponseTest extends \PHPUnit_Framework_TestCase
+{
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function CantExistWithoutXmlFile()
+ {
+ $maintenanceResponse = new DirectLinkMaintenanceResponse('');
+ }
+
+ /** @test */
+ public function ParametersCanBeRetrieved()
+ {
+ $xml = $this->provideXML();
+
+ $maintenanceResponse = new DirectLinkMaintenanceResponse($xml);
+ $this->assertEquals('5', $maintenanceResponse->getParam('orderid'));
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function RequestIsFilteredFromNonOgoneParameters()
+ {
+ $xml = $this->provideXML();
+
+ $maintenanceResponse = new DirectLinkMaintenanceResponse($xml);
+ $maintenanceResponse->getParam('unknown_param');
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function ChecksInvalidXml()
+ {
+ $xml = $this->provideInvalidXML();
+
+ $maintenanceResponse = new DirectLinkMaintenanceResponse($xml);
+ }
+
+ /** @test */
+ public function ChecksStatus()
+ {
+ $xml = $this->provideXML();
+
+ $maintenanceResponse = new DirectLinkMaintenanceResponse($xml);
+ $this->assertTrue($maintenanceResponse->isSuccessful());
+ }
+
+ /** @test */
+ public function AmountIsConvertedToCent()
+ {
+ $xml = $this->provideXML();
+
+ $maintenanceResponse = new DirectLinkMaintenanceResponse($xml);
+ $this->assertEquals(100, $maintenanceResponse->getParam('amount'));
+ }
+
+ public function provideFloats()
+ {
+ return array(
+ array('17.89', 1789),
+ array('65.35', 6535),
+ array('12.99', 1299),
+ );
+ }
+
+ /**
+ * @test
+ * @dataProvider provideFloats
+ */
+ public function CorrectlyConvertsFloatAmountsToInteger($string, $integer)
+ {
+ $xml = $this->provideXML($string);
+
+ $maintenanceResponse = new DirectLinkMaintenanceResponse($xml);
+ $this->assertEquals($integer, $maintenanceResponse->getParam('amount'));
+ }
+
+ /**
+ * Helper method to setup an xml-string
+ */
+ private function provideXML($amount = null)
+ {
+
+ $xml = '
+
+ ';
+
+ return $xml;
+ }
+
+ /**
+ * Helper method to setup an invalid xml-string
+ */
+ private function provideInvalidXML()
+ {
+ $xml = '
+ ';
+
+ return $xml;
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/DirectLinkPaymentRequestTest.php b/tests/Ogone/Tests/DirectLink/DirectLinkPaymentRequestTest.php
new file mode 100644
index 0000000..1575ddd
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/DirectLinkPaymentRequestTest.php
@@ -0,0 +1,127 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\DirectLink\PaymentOperation;
+use Ogone\Tests;
+use Ogone\Tests\ShaComposer\FakeShaComposer;
+use Ogone\DirectLink\DirectLinkPaymentRequest;
+use Ogone\DirectLink\Alias;
+
+class DirectLinkPaymentRequestTest extends \PHPUnit_Framework_TestCase
+{
+
+ /** @test */
+ public function IsValidWhenRequiredFieldsAreFilledIn()
+ {
+ $directLinkPaymentRequest = $this->provideMinimalDirectLinkPaymentRequest();
+ $directLinkPaymentRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \RuntimeException
+ */
+ public function IsInvalidWhenFieldsAreMissing()
+ {
+ $directLinkPaymentRequest = new DirectLinkPaymentRequest(new FakeShaComposer);
+ $directLinkPaymentRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function isInvalidWithNonOgoneUrl()
+ {
+ $directLinkPaymentRequest = $this->provideMinimalDirectLinkPaymentRequest();
+ $directLinkPaymentRequest->setOgoneUri('http://example.com');
+ $directLinkPaymentRequest->validate();
+ }
+
+ /**
+ * @test
+ */
+ public function isValidWithOgoneUrl()
+ {
+ $directLinkPaymentRequest = $this->provideMinimalDirectLinkPaymentRequest();
+ $directLinkPaymentRequest->setOgoneUri(DirectLinkPaymentRequest::PRODUCTION);
+ $directLinkPaymentRequest->validate();
+ }
+
+ /**
+ * @test
+ */
+ public function isValidWhenAliasSet()
+ {
+ $alias = new Alias('customer_123');
+
+ $directLinkPaymentRequest = $this->provideMinimalDirectLinkPaymentRequest();
+ $directLinkPaymentRequest->setAlias($alias);
+ $directLinkPaymentRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function IsInvalidWithTooLongAlias()
+ {
+ $alias = new Alias(str_repeat('repeat', 10));
+
+ $directLinkPaymentRequest = $this->provideMinimalDirectLinkPaymentRequest();
+ $directLinkPaymentRequest->setAlias($alias);
+ $directLinkPaymentRequest->validate();
+ }
+
+ /**
+ * @test
+ */
+ public function isValidWhenOperationIsSet()
+ {
+ $directLinkPaymentRequest = $this->provideMinimalDirectLinkPaymentRequest();
+ $directLinkPaymentRequest->setOperation(new PaymentOperation(PaymentOperation::REQUEST_FOR_DIRECT_SALE));
+ $directLinkPaymentRequest->validate();
+ }
+
+ /**
+ * @test
+ * @dataProvider provideBadParameters
+ * @expectedException \InvalidArgumentException
+ */
+ public function BadParametersCauseExceptions($method, $value)
+ {
+ $directLinkPaymentRequest = new DirectLinkPaymentRequest(new FakeShaComposer);
+ $directLinkPaymentRequest->$method($value);
+ }
+
+ public function provideBadParameters()
+ {
+ return array(
+ array('setPswd', '12'),
+ array('setUserid', '1'),
+ );
+ }
+
+ /** @return DirectLinkPaymentRequest */
+ private function provideMinimalDirectLinkPaymentRequest()
+ {
+ $directLinkRequest = new DirectLinkPaymentRequest(new FakeShaComposer());
+ $directLinkRequest->setPspid('123456');
+ $directLinkRequest->setUserId('user_1234');
+ $directLinkRequest->setPassword('abracadabra');
+ $directLinkRequest->setAmount(100);
+ $directLinkRequest->setCurrency('EUR');
+ $directLinkRequest->setOrderid('999');
+
+ return $directLinkRequest;
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/DirectLinkPaymentResponseTest.php b/tests/Ogone/Tests/DirectLink/DirectLinkPaymentResponseTest.php
new file mode 100644
index 0000000..13a494d
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/DirectLinkPaymentResponseTest.php
@@ -0,0 +1,134 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\DirectLink\DirectLinkPaymentResponse;
+
+class DirectLinkPaymentResponseTest extends \PHPUnit_Framework_TestCase
+{
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function CantExistWithoutXmlFile()
+ {
+ $paymentResponse = new DirectLinkPaymentResponse('');
+ }
+
+ /** @test */
+ public function ParametersCanBeRetrieved()
+ {
+ $xml = $this->provideXML();
+
+ $paymentResponse = new DirectLinkPaymentResponse($xml);
+ $this->assertEquals('123', $paymentResponse->getParam('orderid'));
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function RequestIsFilteredFromNonOgoneParameters()
+ {
+ $xml = $this->provideXML();
+
+ $paymentResponse = new DirectLinkPaymentResponse($xml);
+ $paymentResponse->getParam('unknown_param');
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function ChecksInvalidXml()
+ {
+ $xml = $this->provideInvalidXML();
+
+ $paymentResponse = new DirectLinkPaymentResponse($xml);
+ }
+
+ /** @test */
+ public function ChecksStatus()
+ {
+ $xml = $this->provideXML();
+
+ $paymentResponse = new DirectLinkPaymentResponse($xml);
+ $this->assertTrue($paymentResponse->isSuccessful());
+ }
+
+ /** @test */
+ public function AmountIsConvertedToCent()
+ {
+ $xml = $this->provideXML();
+
+ $paymentResponse = new DirectLinkPaymentResponse($xml);
+ $this->assertEquals(100, $paymentResponse->getParam('amount'));
+ }
+
+ public function provideFloats()
+ {
+ return array(
+ array('17.89', 1789),
+ array('65.35', 6535),
+ array('12.99', 1299),
+ );
+ }
+
+ /**
+ * @test
+ * @dataProvider provideFloats
+ */
+ public function CorrectlyConvertsFloatAmountsToInteger($string, $integer)
+ {
+ $xml = $this->provideXML($string);
+
+ $paymentResponse = new DirectLinkPaymentResponse($xml);
+ $this->assertEquals($integer, $paymentResponse->getParam('amount'));
+ }
+
+ /**
+ * Helper method to setup an xml-string
+ */
+ private function provideXML($amount = null)
+ {
+
+ $xml = '
+
+ ';
+
+ return $xml;
+ }
+
+ /**
+ * Helper method to setup an invalid xml-string
+ */
+ private function provideInvalidXML()
+ {
+ $xml = '
+ ';
+
+ return $xml;
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/DirectLinkQueryRequestTest.php b/tests/Ogone/Tests/DirectLink/DirectLinkQueryRequestTest.php
new file mode 100644
index 0000000..b6a18e4
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/DirectLinkQueryRequestTest.php
@@ -0,0 +1,82 @@
+
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\Tests\ShaComposer\FakeShaComposer;
+use Ogone\DirectLink\DirectLinkQueryRequest;
+
+class DirectLinkQueryRequestTest extends \PHPUnit_Framework_TestCase
+{
+
+ /** @test */
+ public function IsValidWhenRequiredFieldsAreFilledIn()
+ {
+ $directLinkQueryRequest = $this->provideMinimalDirectLinkQueryRequest();
+ $directLinkQueryRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \RuntimeException
+ */
+ public function IsInvalidWhenFieldsAreMissing()
+ {
+ $directLinkQueryRequest = new DirectLinkQueryRequest(new FakeShaComposer);
+ $directLinkQueryRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function isInvalidWithNonOgoneUrl()
+ {
+ $directLinkQueryRequest = $this->provideMinimalDirectLinkQueryRequest();
+ $directLinkQueryRequest->setOgoneUri('http://example.com');
+ $directLinkQueryRequest->validate();
+ }
+
+ /**
+ * @test
+ */
+ public function isValidWithOgoneUrl()
+ {
+ $directLinkQueryRequest = $this->provideMinimalDirectLinkQueryRequest();
+ $directLinkQueryRequest->setOgoneUri(DirectLinkQueryRequest::PRODUCTION);
+ $directLinkQueryRequest->validate();
+ }
+
+ /**
+ * @test
+ * @dataProvider provideBadParameters
+ * @expectedException \InvalidArgumentException
+ */
+ public function BadParametersCauseExceptions($method, $value)
+ {
+ $directLinkQueryRequest = new DirectLinkQueryRequest(new FakeShaComposer);
+ $directLinkQueryRequest->$method($value);
+ }
+
+ public function provideBadParameters()
+ {
+ return array(
+ array('setPassword', '12'),
+ array('setUserid', '1'),
+ );
+ }
+
+ /** @return DirectLinkQueryRequest */
+ private function provideMinimalDirectLinkQueryRequest()
+ {
+ $directLinkRequest = new DirectLinkQueryRequest(new FakeShaComposer());
+ $directLinkRequest->setPspid('123456');
+ $directLinkRequest->setUserId('user_1234');
+ $directLinkRequest->setPassword('abracadabra');
+ $directLinkRequest->setPayId('12345678');
+
+ return $directLinkRequest;
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/DirectLinkQueryResponseTest.php b/tests/Ogone/Tests/DirectLink/DirectLinkQueryResponseTest.php
new file mode 100644
index 0000000..ac5e0d6
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/DirectLinkQueryResponseTest.php
@@ -0,0 +1,132 @@
+
+ */
+
+namespace Ogone\Tests\DirectLink;
+
+use Ogone\DirectLink\DirectLinkQueryResponse;
+
+class DirectLinkQueryResponseTest extends \PHPUnit_Framework_TestCase
+{
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function CantExistWithoutXmlFile()
+ {
+ $queryResponse = new DirectLinkQueryResponse('');
+ }
+
+ /** @test */
+ public function ParametersCanBeRetrieved()
+ {
+ $xml = $this->provideXML();
+
+ $queryResponse = new DirectLinkQueryResponse($xml);
+ $this->assertEquals('5', $queryResponse->getParam('orderid'));
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function RequestIsFilteredFromNonOgoneParameters()
+ {
+ $xml = $this->provideXML();
+
+ $queryResponse = new DirectLinkQueryResponse($xml);
+ $queryResponse->getParam('unknown_param');
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function ChecksInvalidXml()
+ {
+ $xml = $this->provideInvalidXML();
+
+ $queryResponse = new DirectLinkQueryResponse($xml);
+ }
+
+ /** @test */
+ public function ChecksStatus()
+ {
+ $xml = $this->provideXML();
+
+ $queryResponse = new DirectLinkQueryResponse($xml);
+ $this->assertTrue($queryResponse->isSuccessful());
+ }
+
+ /** @test */
+ public function AmountIsConvertedToCent()
+ {
+ $xml = $this->provideXML();
+
+ $queryResponse = new DirectLinkQueryResponse($xml);
+ $this->assertEquals(450, $queryResponse->getParam('amount'));
+ }
+
+ public function provideFloats()
+ {
+ return array(
+ array('17.89', 1789),
+ array('65.35', 6535),
+ array('12.99', 1299),
+ );
+ }
+
+ /**
+ * @test
+ * @dataProvider provideFloats
+ */
+ public function CorrectlyConvertsFloatAmountsToInteger($string, $integer)
+ {
+ $xml = $this->provideXML($string);
+
+ $queryResponse = new DirectLinkQueryResponse($xml);
+ $this->assertEquals($integer, $queryResponse->getParam('amount'));
+ }
+
+ /**
+ * Helper method to setup an xml-string
+ */
+ private function provideXML($amount = null)
+ {
+
+ $xml = '
+
+ ';
+
+ return $xml;
+ }
+
+ /**
+ * Helper method to setup an invalid xml-string
+ */
+ private function provideInvalidXML()
+ {
+ $xml = '
+ ';
+
+ return $xml;
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/MaintenanceOperationTest.php b/tests/Ogone/Tests/DirectLink/MaintenanceOperationTest.php
new file mode 100644
index 0000000..5abad1a
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/MaintenanceOperationTest.php
@@ -0,0 +1,41 @@
+assertEquals(MaintenanceOperation::OPERATION_AUTHORISATION_RENEW, (string) new MaintenanceOperation(MaintenanceOperation::OPERATION_AUTHORISATION_RENEW));
+ }
+
+ /** @test */
+ public function itShouldBeComparable()
+ {
+ $operation = new MaintenanceOperation(MaintenanceOperation::OPERATION_AUTHORISATION_RENEW);
+ $this->assertTrue($operation->equals(new MaintenanceOperation(MaintenanceOperation::OPERATION_AUTHORISATION_RENEW)));
+ $this->assertFalse($operation->equals(new MaintenanceOperation(MaintenanceOperation::OPERATION_AUTHORISATION_DELETE)));
+ }
+}
diff --git a/tests/Ogone/Tests/DirectLink/PaymentOperationTest.php b/tests/Ogone/Tests/DirectLink/PaymentOperationTest.php
new file mode 100644
index 0000000..30186c5
--- /dev/null
+++ b/tests/Ogone/Tests/DirectLink/PaymentOperationTest.php
@@ -0,0 +1,41 @@
+assertEquals(PaymentOperation::REQUEST_FOR_AUTHORISATION, (string) new PaymentOperation(PaymentOperation::REQUEST_FOR_AUTHORISATION));
+ }
+
+ /** @test */
+ public function itShouldBeComparable()
+ {
+ $operation = new PaymentOperation(PaymentOperation::REQUEST_FOR_AUTHORISATION);
+ $this->assertTrue($operation->equals(new PaymentOperation(PaymentOperation::REQUEST_FOR_AUTHORISATION)));
+ $this->assertFalse($operation->equals(new PaymentOperation(PaymentOperation::REQUEST_FOR_DIRECT_SALE)));
+ }
+}
diff --git a/tests/Ogone/Tests/Ecommerce/AliasTest.php b/tests/Ogone/Tests/Ecommerce/AliasTest.php
new file mode 100644
index 0000000..ed87827
--- /dev/null
+++ b/tests/Ogone/Tests/Ecommerce/AliasTest.php
@@ -0,0 +1,53 @@
+assertEquals('usage...', $alias->getAliasUsage());
+ }
+
+ /** @test */
+ public function AliasCanHaveOperationByMerchant()
+ {
+ $alias = new Alias('alias123');
+ $this->assertEquals(Alias::OPERATION_BY_MERCHANT, $alias->getAliasOperation());
+ }
+
+ /** @test */
+ public function AliasCanHaveOperationByPsp()
+ {
+ $alias = new Alias('alias123', Alias::OPERATION_BY_PSP);
+ $this->assertEquals(Alias::OPERATION_BY_PSP, $alias->getAliasOperation());
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function AliasIsMax50Characters()
+ {
+ new Alias(str_repeat('X', 51));
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ */
+ public function AliasIsAlphaNumeric()
+ {
+ new Alias('some alias with spaces, dots (.), etc');
+ }
+
+ /** @test */
+ public function CanBeRepresentedAsString()
+ {
+ $this->assertEquals('test123', (string) new Alias('test123'));
+ }
+}
diff --git a/tests/Ogone/Tests/Ecommerce/EcommercePaymentRequestTest.php b/tests/Ogone/Tests/Ecommerce/EcommercePaymentRequestTest.php
new file mode 100644
index 0000000..0a8e4b3
--- /dev/null
+++ b/tests/Ogone/Tests/Ecommerce/EcommercePaymentRequestTest.php
@@ -0,0 +1,141 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\Ecommerce;
+
+use Ogone\DirectLink\PaymentOperation;
+use Ogone\Tests\ShaComposer\FakeShaComposer;
+use Ogone\Ecommerce\EcommercePaymentRequest;
+use Ogone\Tests\TestCase;
+
+class EcommercePaymentRequestTest extends TestCase
+{
+ /** @test */
+ public function IsValidWhenRequiredFieldsAreFilledIn()
+ {
+ $paymentRequest = $this->provideMinimalPaymentRequest();
+ $paymentRequest->validate();
+ }
+
+ /** @test */
+ public function IsValidWhenAllFieldsAreFilledIn()
+ {
+ $paymentRequest = $this->provideCompletePaymentRequest();
+ $paymentRequest->validate();
+ }
+
+ /**
+ * @test
+ * @expectedException \RuntimeException
+ */
+ public function IsInvalidWhenFieldsAreMissing()
+ {
+ $paymentRequest = new EcommercePaymentRequest(new FakeShaComposer);
+ $paymentRequest->validate();
+ }
+
+ /** @test */
+ public function UnimportantParamsUseMagicSetters()
+ {
+ $paymentRequest = new EcommercePaymentRequest(new FakeShaComposer);
+ $paymentRequest->setBgcolor('FFFFFF');
+ $this->assertEquals('FFFFFF', $paymentRequest->getBgcolor());
+ }
+
+ /**
+ * @test
+ * @dataProvider provideBadParameters
+ * @expectedException \InvalidArgumentException
+ */
+ public function BadParametersCauseExceptions($method, $value)
+ {
+ $paymentRequest = new EcommercePaymentRequest(new FakeShaComposer);
+ $paymentRequest->$method($value);
+ }
+
+ /**
+ * @test
+ * @expectedException \BadMethodCallException
+ */
+ public function UnknownMethodFails()
+ {
+ $paymentRequest = new EcommercePaymentRequest(new FakeShaComposer);
+ $paymentRequest->getFoobar();
+ }
+
+ public function provideBadParameters()
+ {
+ $longString = str_repeat('longstring', 100);
+ $notAUri = 'http://not a uri';
+ $longUri = "http://www.example.com/$longString";
+
+ return array(
+ array('setAccepturl', $notAUri),
+ array('setAmount', 10.50),
+ array('setAmount', -1),
+ array('setAmount', 1000000000000000),
+ array('setBrand', 'Oxfam'),
+ array('setCancelurl', $notAUri),
+ array('setCancelurl', $longUri),
+ array('setCurrency', 'Belgische Frank'),
+ //array('setCustomername', ''),
+ array('setDeclineurl', $notAUri),
+ array('setDynamicTemplateUri', $notAUri),
+ array('setEmail', 'foo @ bar'),
+ array('setEmail', "$longString@example.com"),
+ array('setExceptionurl', $notAUri),
+ //array('setFeedbackMessage', ''),
+ //array('setFeedbackParams', ''),
+ array('setLanguage', 'West-Vlaams'),
+ array('setOgoneUri', $notAUri),
+ array('setOrderDescription', $longString),
+ array('setOrderid', "Weird çh@®a©†€rs"),
+ array('setOrderid', $longString),
+ array('setOwnerAddress', $longString),
+ array('setOwnercountry', 'Benidorm'),
+ array('setOwnerPhone', $longString),
+ array('setOwnerTown', $longString),
+ array('setOwnerZip', $longString),
+ array('setParamvar', $longString),
+ array('setPaymentMethod', 'Digital'),
+ array('setPspid', $longString),
+ );
+ }
+
+ /** @return EcommercePaymentRequest */
+ private function provideCompletePaymentRequest()
+ {
+ $paymentRequest = $this->provideMinimalPaymentRequest();
+
+ $paymentRequest->setAccepturl('http://example.com/accept');
+ $paymentRequest->setDeclineurl('http://example.com/decline');
+ $paymentRequest->setExceptionurl('http://example.com/exception');
+ $paymentRequest->setCancelurl('http://example.com/cancel');
+ $paymentRequest->setBackurl('http://example.com/back');
+ $paymentRequest->setDynamicTemplateUri('http://example.com/template');
+
+ $paymentRequest->setCurrency('EUR');
+ $paymentRequest->setLanguage('nl_BE');
+ $paymentRequest->setPaymentMethod('CreditCard');
+ $paymentRequest->setBrand('VISA');
+
+ $paymentRequest->setFeedbackMessage("Thanks for ordering");
+ $paymentRequest->setFeedbackParams(array('amountOfProducts' => '5', 'usedCoupon' => 1));
+ $paymentRequest->setParamvar('aParamVar');
+ $paymentRequest->setOrderDescription("Four horses and a carriage");
+
+ $paymentRequest->setOwnerPhone('123456789');
+
+ $paymentRequest->setOperation(new PaymentOperation(PaymentOperation::REQUEST_FOR_DIRECT_SALE));
+
+ return $paymentRequest;
+ }
+}
diff --git a/tests/Ogone/Tests/Ecommerce/EcommercePaymentResponseTest.php b/tests/Ogone/Tests/Ecommerce/EcommercePaymentResponseTest.php
new file mode 100644
index 0000000..599fc49
--- /dev/null
+++ b/tests/Ogone/Tests/Ecommerce/EcommercePaymentResponseTest.php
@@ -0,0 +1,136 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\Ecommerce;
+
+use Ogone\PaymentResponse;
+use Ogone\Tests\ShaComposer\FakeShaComposer;
+use Ogone\Ecommerce\EcommercePaymentResponse;
+use InvalidArgumentException;
+
+class EcommercePaymentResponseTest extends \PHPUnit_Framework_TestCase
+{
+ /** @test */
+ public function CanBeVerified()
+ {
+ $aRequest = $this->provideRequest();
+
+ $paymentResponse = new EcommercePaymentResponse($aRequest);
+ $this->assertTrue($paymentResponse->isValid(new FakeShaComposer));
+ }
+
+ /** @test */
+ public function CanBeConvertedToArray()
+ {
+ $aRequest = $this->provideRequest();
+
+ $paymentResponse = new EcommercePaymentResponse($aRequest);
+ $paymentResponse->isValid(new FakeShaComposer);
+ $array = $paymentResponse->toArray();
+ $this->assertArrayHasKey('ORDERID', $array);
+ $this->assertArrayHasKey('STATUS', $array);
+ $this->assertArrayHasKey('AMOUNT', $array);
+ $this->assertArrayHasKey('SHASIGN', $array);
+ }
+
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function CannotExistWithoutShaSign()
+ {
+ $paymentResponse = new EcommercePaymentResponse(array());
+ }
+
+ /** @test */
+ public function ParametersCanBeRetrieved()
+ {
+ $aRequest = $this->provideRequest();
+
+ $paymentResponse = new EcommercePaymentResponse($aRequest);
+ $this->assertEquals($aRequest['orderID'], $paymentResponse->getParam('orderid'));
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function RequestIsFilteredFromNonOgoneParameters()
+ {
+ $aRequest = $this->provideRequest();
+
+ $paymentResponse = new EcommercePaymentResponse($aRequest);
+ $paymentResponse->getParam('unknown_param');
+ }
+
+ /** @test */
+ public function ChecksStatus()
+ {
+ $aRequest = $this->provideRequest();
+
+ $paymentResponse = new EcommercePaymentResponse($aRequest);
+ $this->assertTrue($paymentResponse->isSuccessful());
+ }
+
+ /** @test */
+ public function AmountIsConvertedToCent()
+ {
+ $aRequest = $this->provideRequest();
+
+ $paymentResponse = new EcommercePaymentResponse($aRequest);
+ $this->assertEquals(100, $paymentResponse->getParam('amount'));
+ }
+
+ public function provideFloats()
+ {
+ return array(
+ array('17.89', 1789),
+ array('65.35', 6535),
+ array('12.99', 1299),
+ array('1.0', 100)
+ );
+ }
+
+ /**
+ * @test
+ * @expectedException InvalidArgumentException
+ */
+ public function InvalidForInvalidCurrency()
+ {
+ $paymentResponse = new EcommercePaymentResponse(array('amount' => 'NaN', 'shasign' => '123'));
+ $paymentResponse->getParam('amount');
+ }
+
+ /**
+ * @test
+ * @dataProvider provideFloats
+ */
+ public function CorrectlyConvertsFloatAmountsToInteger($string, $integer)
+ {
+ $paymentResponse = new EcommercePaymentResponse(array('amount' => $string, 'shasign' => '123'));
+ $this->assertEquals($integer, $paymentResponse->getParam('amount'));
+ }
+
+ /**
+ * Helper method to setup a request array
+ */
+ private function provideRequest()
+ {
+ return array(
+ 'orderID' => '123',
+ 'SHASIGN' => FakeShaComposer::FAKESHASTRING,
+ 'UNKNOWN_PARAM' => false, /* unkown parameter, should be filtered out */
+ 'status' => PaymentResponse::STATUS_AUTHORISED,
+ 'amount' => 1,
+ );
+ }
+}
diff --git a/tests/Ogone/Tests/FormGenerator/SimpleFormGeneratorTest.php b/tests/Ogone/Tests/FormGenerator/SimpleFormGeneratorTest.php
new file mode 100644
index 0000000..4628009
--- /dev/null
+++ b/tests/Ogone/Tests/FormGenerator/SimpleFormGeneratorTest.php
@@ -0,0 +1,106 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\FormGenerator;
+
+use Ogone\DirectLink\PaymentOperation;
+use Ogone\FormGenerator\SimpleFormGenerator;
+use Ogone\PaymentRequest;
+use Ogone\Tests\TestCase;
+
+class SimpleFormGeneratorTest extends TestCase
+{
+ /** @test */
+ public function GeneratesAForm()
+ {
+ $expected =
+ '';
+
+ $paymentRequest = $this->provideMinimalPaymentRequest();
+
+ $formGenerator = new SimpleFormGenerator();
+
+ $this->assertXmlStringEqualsXmlString($expected, $formGenerator->render($paymentRequest));
+ $this->assertXmlStringEqualsXmlString($expected, $formGenerator->render($paymentRequest, 'ogone', true));
+ }
+
+ /** @test */
+ public function BCCheck()
+ {
+ $expected =
+ '';
+
+ $paymentRequest = $this->provideMinimalPaymentRequest();
+
+ $formGenerator = new SimpleFormGenerator();
+ $formGenerator->setFormName('ogoneform');
+ $formGenerator->showSubmitButton(false);
+ $this->assertXmlStringEqualsXmlString($expected, $formGenerator->render($paymentRequest));
+ $this->assertXmlStringEqualsXmlString($expected, $formGenerator->render($paymentRequest, 'ogoneform', false));
+ }
+
+ /** @test */
+ public function GeneratesAFormWithCustomOperationParameter()
+ {
+ $expected =
+ '';
+
+ $paymentRequest = $this->provideMinimalPaymentRequest();
+ $paymentRequest->setOperation(new PaymentOperation(PaymentOperation::REQUEST_FOR_DIRECT_SALE));
+
+ $formGenerator = new SimpleFormGenerator();
+
+ $this->assertXmlStringEqualsXmlString($expected, $formGenerator->render($paymentRequest));
+ $this->assertXmlStringEqualsXmlString($expected, $formGenerator->render($paymentRequest, 'ogone', true));
+ }
+}
diff --git a/tests/Ogone/Tests/FormGenerator/UrlGeneratorTest.php b/tests/Ogone/Tests/FormGenerator/UrlGeneratorTest.php
new file mode 100644
index 0000000..7291edf
--- /dev/null
+++ b/tests/Ogone/Tests/FormGenerator/UrlGeneratorTest.php
@@ -0,0 +1,38 @@
+provideMinimalPaymentRequest();
+
+ $urlGenerator = new UrlGenerator();
+ $url = $urlGenerator->render($paymentRequest);
+
+ $this->assertEquals(strtolower($expected), strtolower($url));
+ }
+}
diff --git a/tests/Ogone/Tests/HashAlgorithmTest.php b/tests/Ogone/Tests/HashAlgorithmTest.php
new file mode 100644
index 0000000..191ddca
--- /dev/null
+++ b/tests/Ogone/Tests/HashAlgorithmTest.php
@@ -0,0 +1,24 @@
+assertEquals(HashAlgorithm::HASH_SHA1, (string) $sha1);
+ }
+}
diff --git a/tests/Ogone/Tests/OgoneTest.php b/tests/Ogone/Tests/OgoneTest.php
new file mode 100644
index 0000000..0386f81
--- /dev/null
+++ b/tests/Ogone/Tests/OgoneTest.php
@@ -0,0 +1,168 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests;
+
+use Guzzle\Http\Client;
+use Ogone\DirectLink\Eci;
+use Ogone\DirectLink\PaymentOperation;
+use Ogone\Passphrase;
+use Ogone\DirectLink\Alias;
+use Ogone\DirectLink\CreateAliasRequest;
+use Ogone\DirectLink\CreateAliasResponse;
+use Ogone\ShaComposer\AllParametersShaComposer;
+use Ogone\ParameterFilter\ShaOutParameterFilter;
+use Ogone\DirectLink\DirectLinkPaymentRequest;
+use Ogone\DirectLink\DirectLinkPaymentResponse;
+
+/**
+ * @group integration
+ */
+class OgoneTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @test
+ */
+ public function AliasCreationIsSuccessful()
+ {
+ $passphraseOut = new Passphrase(PASSPHRASE_SHA_OUT);
+ $shaOutComposer = new AllParametersShaComposer($passphraseOut);
+ $shaOutComposer->addParameterFilter(new ShaOutParameterFilter());
+
+ $createAliasResponse = $this->provideAliasResponse();
+
+ $this->assertTrue($createAliasResponse->isValid($shaOutComposer));
+ $this->assertTrue($createAliasResponse->isSuccessful());
+
+ return (string) $createAliasResponse->getAlias();
+ }
+
+ /**
+ * @test
+ * @depends AliasCreationIsSuccessful
+ */
+ public function DirectLinkPaymentIsSuccessful($alias)
+ {
+ $passphrase = new Passphrase(PASSPHRASE_SHA_IN);
+ $shaComposer = new AllParametersShaComposer($passphrase);
+ $directLinkRequest = new DirectLinkPaymentRequest($shaComposer);
+
+ $orderId = uniqid('order_'); // create a unique order id
+ $directLinkRequest->setOrderid($orderId);
+
+ $alias = new Alias($alias);
+ $directLinkRequest->setPspid(PSPID);
+ $directLinkRequest->setUserId(USERID);
+ $directLinkRequest->setPassword(PASSWORD);
+ $directLinkRequest->setAlias($alias);
+ $directLinkRequest->setAmount(100);
+ $directLinkRequest->setCurrency('EUR');
+ $directLinkRequest->setEci(new Eci(Eci::ECOMMERCE_RECURRING));
+ $directLinkRequest->setOperation(new PaymentOperation(PaymentOperation::REQUEST_FOR_DIRECT_SALE));
+ $directLinkRequest->validate();
+
+ $body = array();
+ foreach ($directLinkRequest->toArray() as $key => $value) {
+ $body[strtoupper($key)] = $value;
+ }
+
+ $body['SHASIGN'] = $directLinkRequest->getShaSign();
+
+ $client = new Client($directLinkRequest->getOgoneUri());
+ $request = $client->post(null, null, $body);
+ $response = $request->send();
+
+ $directLinkResponse = new DirectLinkPaymentResponse($response->getBody(true));
+
+ $this->assertTrue($directLinkResponse->isSuccessful());
+
+ return $alias;
+ }
+
+ /**
+ * @test
+ */
+ public function AliasIsCreatedByOgone()
+ {
+ $passphraseOut = new Passphrase(PASSPHRASE_SHA_OUT);
+ $shaOutComposer = new AllParametersShaComposer($passphraseOut);
+ $shaOutComposer->addParameterFilter(new ShaOutParameterFilter());
+
+ $createAliasResponse = $this->provideAliasResponse(false);
+
+ $this->assertTrue($createAliasResponse->isValid($shaOutComposer));
+ $this->assertTrue($createAliasResponse->isSuccessful());
+ }
+
+ /**
+ * @test
+ */
+ public function CreateAliasInvalid()
+ {
+ $passphraseOut = new Passphrase(PASSPHRASE_SHA_OUT);
+ $shaOutComposer = new AllParametersShaComposer($passphraseOut);
+ $shaOutComposer->addParameterFilter(new ShaOutParameterFilter());
+
+ $createAliasResponse = $this->provideAliasResponse(true, true);
+
+ $this->assertTrue($createAliasResponse->isValid($shaOutComposer));
+ $this->assertFalse($createAliasResponse->isSuccessful());
+ }
+
+
+ public function provideAliasResponse($createAlias = true, $noValidCardnumber = false)
+ {
+ /*
+ * Create an alias request to Ogone
+ */
+ $passphrase = new Passphrase(PASSPHRASE_SHA_IN);
+ $shaComposer = new AllParametersShaComposer($passphrase);
+
+ $createAliasRequest = new CreateAliasRequest($shaComposer);
+ $createAliasRequest->setPspid(PSPID);
+ $createAliasRequest->setAccepturl('http://www.example.com');
+ $createAliasRequest->setExceptionurl('http://www.example.com');
+
+ if ($createAlias == true) {
+ $unique_alias = uniqid('customer_'); // create a unique alias
+ $alias = new Alias($unique_alias);
+ $createAliasRequest->setAlias($alias);
+ }
+
+ $createAliasRequest->validate();
+
+ $body = array();
+ foreach ($createAliasRequest->toArray() as $key => $value) {
+ $body[strtoupper($key)] = $value;
+ }
+
+ $body['SHASIGN'] = $createAliasRequest->getShaSign();
+ $body['CN'] = 'Don Corleone';
+ $body['CARDNO'] = ($noValidCardnumber) ? '' : '4111111111111111'; // Ogone Visa test cardnumber
+ $body['CVC'] = '777';
+ $body['ED'] = date('my', strtotime('+1 year')); // test-date should be in the future
+
+ $client = new Client($createAliasRequest->getOgoneUri());
+ $request = $client->post(null, null, $body);
+ $response = $request->send();
+
+ $url = parse_url($response->getInfo('url'));
+ $params = array();
+ parse_str($url['query'], $params);
+
+ /*
+ * Validate alias response from Ogone
+ */
+
+ $createAliasResponse = new CreateAliasResponse($params);
+
+ return $createAliasResponse;
+ }
+}
diff --git a/tests/Ogone/Tests/ParameterFilter/ShaInParameterFilterTest.php b/tests/Ogone/Tests/ParameterFilter/ShaInParameterFilterTest.php
new file mode 100644
index 0000000..8772948
--- /dev/null
+++ b/tests/Ogone/Tests/ParameterFilter/ShaInParameterFilterTest.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\ShaComposer;
+
+use Ogone\ParameterFilter\ShaInParameterFilter;
+
+class ShaInParameterFilterTest extends \PHPUnit_Framework_TestCase
+{
+ /** @test */
+ public function RemovesUnwantedParameters()
+ {
+ $filter = new ShaInParameterFilter;
+ $result = $filter->filter(array('foo' => 'bar', 'orderId' => 123));
+ $this->assertEquals(array('ORDERID' => 123), $result);
+ }
+}
diff --git a/tests/Ogone/Tests/ShaComposer/AllParametersShaComposerTest.php b/tests/Ogone/Tests/ShaComposer/AllParametersShaComposerTest.php
new file mode 100644
index 0000000..0f9ecdc
--- /dev/null
+++ b/tests/Ogone/Tests/ShaComposer/AllParametersShaComposerTest.php
@@ -0,0 +1,142 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\ShaComposer;
+
+use Ogone\HashAlgorithm;
+use Ogone\ParameterFilter\ShaOutParameterFilter;
+use Ogone\Passphrase;
+use Ogone\ShaComposer\AllParametersShaComposer;
+
+class AllParametersShaComposerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @test
+ * @dataProvider provideSha1Request
+ */
+ public function Sha1StringIsComposedCorrectly(Passphrase $passphrase, array $request, $expectedSha)
+ {
+ $composer = new AllParametersShaComposer($passphrase, new HashAlgorithm(HashAlgorithm::HASH_SHA1));
+ $composer->addParameterFilter(new ShaOutParameterFilter);
+ $this->assertEquals($expectedSha, $composer->compose($request));
+ }
+
+ /**
+ * @test
+ * @dataProvider provideSha256Request
+ */
+ public function Sha256StringIsComposedCorrectly(Passphrase $passphrase, array $request, $expectedSha)
+ {
+ $composer = new AllParametersShaComposer($passphrase, new HashAlgorithm(HashAlgorithm::HASH_SHA256));
+ $composer->addParameterFilter(new ShaOutParameterFilter);
+ $this->assertEquals($expectedSha, $composer->compose($request));
+ }
+
+ /**
+ * @test
+ * @dataProvider provideSha512Request
+ */
+ public function Sha512StringIsComposedCorrectly(Passphrase $passphrase, array $request, $expectedSha)
+ {
+ $composer = new AllParametersShaComposer($passphrase, new HashAlgorithm(HashAlgorithm::HASH_SHA512));
+ $composer->addParameterFilter(new ShaOutParameterFilter);
+ $this->assertEquals($expectedSha, $composer->compose($request));
+ }
+
+ public function provideSha1Request()
+ {
+ $passphrase = new Passphrase('Mysecretsig1875!?');
+
+ $expectedSha1 = 'B209960D5703DD1047F95A0F97655FFE5AC8BD52';
+ $request1 = $this->createMinimalParameterSet();
+
+ $expectedSha2 = 'D58400479DCEDD6B6C7E67D61FDC0CC9E6ED65CB';
+ $request2 = $this->createExtensiveParameterSet();
+
+
+
+ return array(
+ array($passphrase, $request1, $expectedSha1),
+ array($passphrase, $request2, $expectedSha2),
+ );
+ }
+
+ public function provideSha256Request()
+ {
+ $passphrase = new Passphrase('Mysecretsig1875!?');
+
+ $expectedSha1 = 'FD15F9371F2B42E3CAEC53BF2576AC89AAEBF53FD8FBA8F0B2EA13EAA823189D';
+ $request1 = $this->createMinimalParameterSet();
+
+ $expectedSha2 = 'A06D4534724885350BA5350731B02F4083370F8C9EED59D1F1C5E2B78EC3C257';
+ $request2 = $this->createExtensiveParameterSet();
+
+ return array(
+ array($passphrase, $request1, $expectedSha1),
+ array($passphrase, $request2, $expectedSha2),
+ );
+ }
+
+ public function provideSha512Request()
+ {
+ $passphrase = new Passphrase('Mysecretsig1875!?');
+
+ $expectedSha1 = '5377F95D498947BECC23E02C2C7DDE182EE1221F1A6629B091110DF653FE0C32FCACF5F9B87B4C5168FC12B7183095623750004355DE938A2B8DECC6DB6D9F62';
+ $request1 = $this->createMinimalParameterSet();
+
+ $expectedSha2 = '31B74E4E0C7BCE4DED9DEAA97D4D3FB419EF6E2FDBD98C18D340B276A9F751E747972A0469A74B73E4C41F38F0F3F58BAD8D7107CA54DF936569852887EB6BE4';
+ $request2 = $this->createExtensiveParameterSet();
+
+ return array(
+ array($passphrase, $request1, $expectedSha1),
+ array($passphrase, $request2, $expectedSha2),
+ );
+ }
+
+ protected function createMinimalParameterSet()
+ {
+ return array(
+ 'currency' => 'EUR',
+ 'ACCEPTANCE' => 1234,
+ 'amount' => 15,
+ 'BRAND' => 'VISA',
+ 'CARDNO' => 'xxxxxxxxxxxx1111',
+ 'NCERROR' => 0,
+ 'PAYID' => 32100123,
+ 'PM' => 'CreditCard',
+ 'STATUS' => 9,
+ 'orderID' => 12,
+ 'unknownparam' => 'some value',
+ );
+ }
+
+ protected function createExtensiveParameterSet()
+ {
+ return array (
+ 'orderID' => 'myorderid1678834094',
+ 'currency' => 'EUR',
+ 'amount' => '99',
+ 'PM' => 'CreditCard',
+ 'ACCEPTANCE' => 'test123',
+ 'STATUS' => '9',
+ 'CARDNO' => 'XXXXXXXXXXXX1111',
+ 'ED' => '0312',
+ 'CN' => 'Some Name',
+ 'TRXDATE' => '01/10/11',
+ 'PAYID' => '9126297',
+ 'NCERROR' => '0',
+ 'BRAND' => 'VISA',
+ 'COMPLUS' => 'my feedbackmessage',
+ 'IP' => '12.123.12.123',
+ 'foo' => 'bar',
+ );
+ }
+}
diff --git a/tests/Ogone/Tests/ShaComposer/FakeShaComposer.php b/tests/Ogone/Tests/ShaComposer/FakeShaComposer.php
new file mode 100644
index 0000000..4a53802
--- /dev/null
+++ b/tests/Ogone/Tests/ShaComposer/FakeShaComposer.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\ShaComposer;
+
+use Ogone\ShaComposer\ShaComposer;
+
+/**
+ * Fake SHA Composer to decouple test from actual SHA composers
+ */
+class FakeShaComposer implements ShaComposer
+{
+ const FAKESHASTRING = 'foo';
+
+ public function compose(array $responseParameters)
+ {
+ return self::FAKESHASTRING;
+ }
+}
diff --git a/tests/Ogone/Tests/ShaComposer/LegacyShaComposerTest.php b/tests/Ogone/Tests/ShaComposer/LegacyShaComposerTest.php
new file mode 100644
index 0000000..1508095
--- /dev/null
+++ b/tests/Ogone/Tests/ShaComposer/LegacyShaComposerTest.php
@@ -0,0 +1,87 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests\ShaComposer;
+
+use Ogone\HashAlgorithm;
+use Ogone\Passphrase;
+use Ogone\PaymentResponse;
+use Ogone\ShaComposer\LegacyShaComposer;
+
+class LegacyShaComposerTest extends \PHPUnit_Framework_TestCase
+{
+ const PASSPHRASE = 'passphrase-set-in-ogone-interface';
+ const SHA1STRING = '66BF34D8B3EF2136E0C267BDBC1F708B8D75A8AA';
+ const SHA256STRING = '882D85FCCC6112A33D3B8A571C11723CAA6B642EED70843B35B15ABA0C2AD637';
+ const SHA512STRING = '8552200DD108CB5633A27D6D0A1FAB54378CB2385BFCEB27487992D16F5A7565E5DD4D38C0F2DB294213CD02E434F311021749E6DAB187357F786E3F199781CA';
+
+ /** @test */
+ public function defaultParameters()
+ {
+ $aRequest = $this->provideRequest();
+ $composer = new LegacyShaComposer(new Passphrase(self::PASSPHRASE));
+ $shaString = $composer->compose($aRequest);
+ $this->assertEquals(self::SHA1STRING, $shaString);
+ }
+
+ /** @test */
+ public function Sha1StringCanBeComposed()
+ {
+ $aRequest = $this->provideRequest();
+
+ $composer = new LegacyShaComposer(new Passphrase(self::PASSPHRASE), new HashAlgorithm(HashAlgorithm::HASH_SHA1));
+ $shaString = $composer->compose($aRequest);
+
+ $this->assertEquals(self::SHA1STRING, $shaString);
+ }
+
+ /** @test */
+ public function Sha256StringCanBeComposed()
+ {
+ $aRequest = $this->provideRequest();
+
+ $composer = new LegacyShaComposer(new Passphrase(self::PASSPHRASE), new HashAlgorithm(HashAlgorithm::HASH_SHA256));
+ $shaString = $composer->compose($aRequest);
+
+ $this->assertEquals(self::SHA256STRING, $shaString);
+ }
+
+ /** @test */
+ public function Sha512StringCanBeComposed()
+ {
+ $aRequest = $this->provideRequest();
+
+ $composer = new LegacyShaComposer(new Passphrase(self::PASSPHRASE), new HashAlgorithm(HashAlgorithm::HASH_SHA512));
+ $shaString = $composer->compose($aRequest);
+
+ $this->assertEquals(self::SHA512STRING, $shaString);
+ }
+
+ private function provideRequest()
+ {
+ return array(
+ 'ACCEPTANCE' => 'test123',
+ 'AMOUNT' => '19.08',
+ 'BRAND' => 'VISA',
+ 'CARDNO' => 'XXXXXXXXXXXX1111',
+ 'CN' => 'Marlon',
+ 'CURRENCY' => 'EUR',
+ 'ED' => '0113',
+ 'IP' => '81.82.214.142',
+ 'NCERROR' => 0,
+ 'ORDERID' => 2101947639,
+ 'PAYID' => 10673859,
+ 'PM' => 'CreditCard',
+ 'STATUS' => PaymentResponse::STATUS_AUTHORISED,
+ 'TRXDATE' => '07/05/11'
+ );
+ }
+}
diff --git a/tests/Ogone/Tests/Subscription/SubscriptionPaymentRequestTest.php b/tests/Ogone/Tests/Subscription/SubscriptionPaymentRequestTest.php
new file mode 100644
index 0000000..16850ab
--- /dev/null
+++ b/tests/Ogone/Tests/Subscription/SubscriptionPaymentRequestTest.php
@@ -0,0 +1,98 @@
+createSubscriptionRequest();
+ $paymentRequest->setAmount(0);
+ $this->assertEquals(0, $paymentRequest->getAmount());
+ }
+
+ /**
+ * @test
+ * @dataProvider provideBadParameters
+ * @expectedException \InvalidArgumentException
+ */
+ public function BadParametersCauseExceptions($method, $value)
+ {
+ $paymentRequest = $this->createSubscriptionRequest();
+ $paymentRequest->$method($value);
+ }
+
+ /**
+ * @test
+ * @expectedException \RuntimeException
+ */
+ public function IsInvalidIfSubscriptionParametersAreMissing()
+ {
+ $paymentRequest = $this->createSubscriptionRequest();
+ $paymentRequest->setPspid('12');
+ $paymentRequest->setCurrency('EUR');
+ $paymentRequest->setAmount(0);
+ $paymentRequest->setOrderId('10');
+ $paymentRequest->validate();
+ }
+
+ /** @test */
+ public function RequestCanBeValid()
+ {
+ $paymentRequest = $this->createSubscriptionRequest();
+ $paymentRequest->setPspid('12');
+ $paymentRequest->setCurrency('EUR');
+ $paymentRequest->setAmount(0);
+ $paymentRequest->setOrderId('10');
+ $paymentRequest->setSubscriptionId('12');
+ $paymentRequest->setSubscriptionAmount(13);
+ $paymentRequest->setSubscriptionComment('test');
+ $paymentRequest->setSubscriptionDescription('description');
+ $paymentRequest->setSubscriptionOrderId('13');
+ $paymentRequest->setSubscriptionPeriod($this->createSubscriptionPeriod());
+ $paymentRequest->setSubscriptionStartdate(new \DateTime());
+ $paymentRequest->setSubscriptionEnddate(new \DateTime());
+ $paymentRequest->setSubscriptionStatus(1);
+ $paymentRequest->validate();
+ $this->assertTrue(true);
+ }
+
+ public function provideBadParameters()
+ {
+
+ return array(
+ array('setAmount', 10.50),
+ array('setAmount', -1),
+ array('setAmount', 150000000000000000),
+ array('setSubscriptionId', 'this is a little more than 50 characters, which is truly the max amount'),
+ array('setSubscriptionId', '$e©ial Ch@r@cters'),
+ array('setSubscriptionAmount', 10.50),
+ array('setSubscriptionAmount', 0),
+ array('setSubscriptionAmount', -1),
+ array('setSubscriptionAmount', 150000000000000000),
+ array('setSubscriptionDescription', 'this is a little more than 100 characters- which is truly the maximum amount of characters one can pass as a parameter to this particular function'),
+ array('setSubscriptionDescription', 'special, characters!'),
+ array('setSubscriptionOrderId', 'this is a little more than 40 characters- which is truly the max amount'),
+ array('setSubscriptionOrderId', 'special, characters!'),
+ array('setSubscriptionStatus', 5),
+ array('setSubscriptionComment', 'this particular string is supposed to be longer than 200 characters- which will require me to type for quite a while longer than the string that needed to exceed 50 chars- which is- in fact- significantly lower than 200'),
+ array('setSubscriptionComment', 'special, characters!')
+ );
+ }
+
+ protected function createSubscriptionRequest()
+ {
+ return new SubscriptionPaymentRequest(new FakeShaComposer());
+ }
+
+ protected function createSubscriptionPeriod()
+ {
+ return new SubscriptionPeriod(SubscriptionPeriod::UNIT_DAILY, 12, 7);
+ }
+}
diff --git a/tests/Ogone/Tests/Subscription/SubscriptionPeriodTest.php b/tests/Ogone/Tests/Subscription/SubscriptionPeriodTest.php
new file mode 100644
index 0000000..16fa630
--- /dev/null
+++ b/tests/Ogone/Tests/Subscription/SubscriptionPeriodTest.php
@@ -0,0 +1,146 @@
+setExpectedException('InvalidArgumentException');
+ $this->createPeriod('not an actual unit');
+ }
+
+ /** @test */
+ public function SettingUnitToWeeklyChecksMoment()
+ {
+ $period = $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, 12, 8);
+ $this->setExpectedException('InvalidArgumentException');
+ $period->setUnit(SubscriptionPeriod::UNIT_WEEKLY);
+ }
+
+ /** @test */
+ public function SettingUnitToMonthlyChecksMoment()
+ {
+ $period = $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, 12, 29);
+ $this->setExpectedException('InvalidArgumentException');
+ $period->setUnit(SubscriptionPeriod::UNIT_MONTHLY);
+ }
+
+ /**
+ * @test
+ * @dataProvider unitProvider
+ */
+ public function UnitCanBeSetRight($unit)
+ {
+ $period = $this->createPeriod($unit);
+ $this->assertEquals($unit, $period->getUnit());
+ }
+
+ /** @test */
+ public function IntervalMustBeInteger()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, 'not an int');
+ }
+
+ /** @test */
+ public function IntervalMustBePositive()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, -12);
+ }
+
+ /** @test */
+ public function IntervalMustNotBeTooBig()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, 150000000000000000);
+ }
+
+ /**
+ * @test
+ * @dataProvider intProvider
+ */
+ public function IntervalCanBeSetRight($interval)
+ {
+ $period = $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, $interval);
+ $this->assertEquals($interval, $period->getInterval());
+ }
+
+ /** @test */
+ public function MomentMustBeInt()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, 12, 'not an int');
+ }
+
+ /** @test */
+ public function MomentMustBePositive()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, 12, -12);
+ }
+
+ /** @test */
+ public function MomentMustNotBeTooBig()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, 12, 150000000000000000);
+ }
+
+ /**
+ * @test
+ * @dataProvider badUnitMomentComboProvider
+ */
+ public function MomentChecksUnit($unit, $interval)
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ $this->createPeriod($unit, 12, $interval);
+ }
+
+ /**
+ * @test
+ * @dataProvider intProvider
+ */
+ public function MomentCanBeSetRight($moment)
+ {
+ $period = $this->createPeriod(SubscriptionPeriod::UNIT_DAILY, 12, $moment);
+ $this->assertEquals($moment, $period->getMoment());
+ }
+
+ public function unitProvider()
+ {
+ return array(
+ array(SubscriptionPeriod::UNIT_DAILY),
+ array(SubscriptionPeriod::UNIT_WEEKLY),
+ array(SubscriptionPeriod::UNIT_MONTHLY)
+ );
+ }
+
+ public function intProvider()
+ {
+ return array(
+ array(1),
+ array(5),
+ array(32),
+ array(123546)
+ );
+ }
+
+ public function badUnitMomentComboProvider()
+ {
+ return array(
+ array(SubscriptionPeriod::UNIT_WEEKLY, 8),
+ array(SubscriptionPeriod::UNIT_MONTHLY, 29)
+ );
+ }
+
+ protected function createPeriod($unit = SubscriptionPeriod::UNIT_DAILY, $interval = 12, $moment = 6)
+ {
+ return new SubscriptionPeriod($unit, $interval, $moment);
+ }
+}
diff --git a/tests/Ogone/Tests/TestCase.php b/tests/Ogone/Tests/TestCase.php
new file mode 100644
index 0000000..f3977aa
--- /dev/null
+++ b/tests/Ogone/Tests/TestCase.php
@@ -0,0 +1,43 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Ogone\Tests;
+
+use Ogone\Tests\ShaComposer\FakeShaComposer;
+use Ogone\Ecommerce\EcommercePaymentRequest;
+
+abstract class TestCase extends \PHPUnit_Framework_TestCase
+{
+ /** @return EcommercePaymentRequest */
+ protected function provideMinimalPaymentRequest()
+ {
+ $paymentRequest = new EcommercePaymentRequest(new FakeShaComposer);
+ $paymentRequest->setPspid('123456789');
+ $paymentRequest->setOrderid('987654321');
+ $paymentRequest->setOgoneUri(EcommercePaymentRequest::TEST);
+
+ // minimal required fields for ogone (together with pspid and orderid)
+ $paymentRequest->setCurrency("EUR");
+ $paymentRequest->setAmount(100);
+
+ // these fields are actually optional but are good practice to be included
+ $paymentRequest->setCustomername("Louis XIV");
+ $paymentRequest->setOwnerAddress("1, Rue du Palais");
+ $paymentRequest->setOwnerTown("Versailles");
+ $paymentRequest->setOwnerZip('2300');
+ $paymentRequest->setOwnerCountry("FR");
+ $paymentRequest->setEmail("louis.xiv@versailles.fr");
+
+ // this field is mandatory in some european countries
+ $paymentRequest->setSecure();
+
+ return $paymentRequest;
+ }
+}