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 @@ +
+toArray() as $key => $value) : ?> + + + + + + + + + +
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; + } +}