├── .gitignore ├── tests ├── Mock │ ├── CompletePurchaseItnSuccess.txt │ ├── CompletePurchasePdtFailure.txt │ ├── CompletePurchaseItnFailure.txt │ └── CompletePurchasePdtSuccess.txt ├── Message │ ├── PurchaseResponseTest.php │ ├── PurchaseRequestTest.php │ └── CompletePurchaseRequestTest.php └── GatewayTest.php ├── CONTRIBUTING.md ├── .travis.yml ├── phpunit.xml.dist ├── LICENSE ├── src ├── Message │ ├── CompletePurchaseItnResponse.php │ ├── PurchaseResponse.php │ ├── CompletePurchasePdtResponse.php │ ├── CompletePurchaseRequest.php │ └── PurchaseRequest.php └── Gateway.php ├── composer.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | composer.phar 4 | phpunit.xml 5 | -------------------------------------------------------------------------------- /tests/Mock/CompletePurchaseItnSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Date: Thu, 07 Mar 2013 05:30:11 GMT 3 | Server: Apache/2.2.3 (CentOS) 4 | Expires: Thu, 19 Nov 1981 08:52:00 GMT 5 | Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 6 | Pragma: no-cache 7 | Vary: Accept-Encoding,User-Agent 8 | Content-Length: 5 9 | Connection: close 10 | Content-Type: text/html; charset=UTF-8 11 | 12 | VALID -------------------------------------------------------------------------------- /tests/Mock/CompletePurchasePdtFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Date: Thu, 07 Mar 2013 05:07:38 GMT 3 | Server: Apache/2.2.3 (CentOS) 4 | Expires: Thu, 19 Nov 1981 08:52:00 GMT 5 | Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 6 | Pragma: no-cache 7 | Vary: Accept-Encoding,User-Agent 8 | Content-Length: 4 9 | Connection: close 10 | Content-Type: text/html; charset=UTF-8 11 | 12 | FAIL -------------------------------------------------------------------------------- /tests/Mock/CompletePurchaseItnFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Date: Thu, 07 Mar 2013 04:57:24 GMT 3 | Server: Apache/2.2.3 (CentOS) 4 | Set-Cookie: refer_session=Direct; path=/; domain=.payfast.co.za, refer_first=Direct; expires=Fri, 07-Mar-2014 04:57:24 GMT; path=/; domain=.payfast.co.za 5 | Expires: Thu, 19 Nov 1981 08:52:00 GMT 6 | Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 7 | Pragma: no-cache 8 | Vary: Accept-Encoding,User-Agent 9 | Content-Length: 7 10 | Connection: close 11 | Content-Type: text/html; charset=UTF-8 12 | 13 | INVALID -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | * Fork the project. 4 | * Make your feature addition or bug fix. 5 | * Add tests for it. This is important so I don't break it in a future version unintentionally. 6 | * Commit just the modifications, do not mess with the composer.json or CHANGELOG.md files. 7 | * Ensure your code is nicely formatted in the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) 8 | style and that all tests pass. 9 | * Send the pull request. 10 | * Check that the Travis CI build passed. If not, rinse and repeat. 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | - 7.0 6 | - 7.1 7 | - 7.2 8 | - 7.3 9 | - 7.4snapshot 10 | 11 | # This triggers builds to run on the new TravisCI infrastructure. 12 | # See: http://docs.travis-ci.com/user/workers/container-based-infrastructure/ 13 | sudo: false 14 | 15 | matrix: 16 | allow_failures: 17 | - php: 7.4snapshot 18 | 19 | ## Cache composer 20 | cache: 21 | directories: 22 | - $HOME/.composer/cache 23 | 24 | install: 25 | - composer install --prefer-dist --no-interaction 26 | 27 | script: 28 | - vendor/bin/phpcs --standard=PSR2 src 29 | - vendor/bin/phpunit --coverage-text 30 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | ./src 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/Mock/CompletePurchasePdtSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Date: Thu, 07 Mar 2013 04:50:36 GMT 3 | Server: Apache/2.2.3 (CentOS) 4 | Expires: Thu, 19 Nov 1981 08:52:00 GMT 5 | Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 6 | Pragma: no-cache 7 | Vary: Accept-Encoding,User-Agent 8 | Content-Length: 397 9 | Connection: close 10 | Content-Type: text/html; charset=UTF-8 11 | 12 | SUCCESS 13 | m_payment_id= 14 | pf_payment_id=61484 15 | payment_status=COMPLETE 16 | item_name=fjdksl 17 | item_description= 18 | amount_gross=12.00 19 | amount_fee=-0.27 20 | amount_net=11.73 21 | custom_str1= 22 | custom_str2= 23 | custom_str3= 24 | custom_str4= 25 | custom_str5= 26 | custom_int1= 27 | custom_int2= 28 | custom_int3= 29 | custom_int4= 30 | custom_int5= 31 | name_first=Test 32 | name_last=User+01 33 | email_address=sbtu01%40payfast.co.za 34 | merchant_id=10000103 -------------------------------------------------------------------------------- /tests/Message/PurchaseResponseTest.php: -------------------------------------------------------------------------------- 1 | '123'); 12 | $response = new PurchaseResponse($this->getMockRequest(), $data, 'https://example.com/'); 13 | 14 | $this->assertFalse($response->isSuccessful()); 15 | $this->assertTrue($response->isRedirect()); 16 | $this->assertNull($response->getTransactionReference()); 17 | $this->assertNull($response->getMessage()); 18 | $this->assertSame($data, $response->getData()); 19 | 20 | $this->assertSame('https://example.com/', $response->getRedirectUrl()); 21 | $this->assertSame('POST', $response->getRedirectMethod()); 22 | $this->assertSame($data, $response->getRedirectData()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/GatewayTest.php: -------------------------------------------------------------------------------- 1 | gateway = new Gateway($this->getHttpClient(), $this->getHttpRequest()); 14 | } 15 | 16 | public function testPurchase() 17 | { 18 | $request = $this->gateway->purchase(array('amount' => '12.00')); 19 | 20 | $this->assertInstanceOf('\Omnipay\PayFast\Message\PurchaseRequest', $request); 21 | $this->assertSame('12.00', $request->getAmount()); 22 | } 23 | 24 | public function testCompletePurchase() 25 | { 26 | $request = $this->gateway->completePurchase(array('amount' => '12.00')); 27 | 28 | $this->assertInstanceOf('\Omnipay\PayFast\Message\CompletePurchaseRequest', $request); 29 | $this->assertSame('12.00', $request->getAmount()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2013 Adrian Macneil 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/Message/CompletePurchaseItnResponse.php: -------------------------------------------------------------------------------- 1 | status = $status; 17 | } 18 | 19 | public function isSuccessful() 20 | { 21 | return 'VALID' === $this->status; 22 | } 23 | 24 | public function getTransactionReference() 25 | { 26 | if ($this->isSuccessful() && isset($this->data['pf_payment_id'])) { 27 | return $this->data['pf_payment_id']; 28 | } 29 | } 30 | 31 | public function getMessage() 32 | { 33 | if ($this->isSuccessful() && isset($this->data['payment_status'])) { 34 | return $this->data['payment_status']; 35 | } else { 36 | return $this->status; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Message/PurchaseResponse.php: -------------------------------------------------------------------------------- 1 | redirectUrl = $redirectUrl; 20 | } 21 | 22 | public function isSuccessful() 23 | { 24 | return false; 25 | } 26 | 27 | public function isRedirect() 28 | { 29 | return true; 30 | } 31 | 32 | public function getRedirectUrl() 33 | { 34 | return $this->redirectUrl; 35 | } 36 | 37 | public function getRedirectMethod() 38 | { 39 | return 'POST'; 40 | } 41 | 42 | public function getRedirectData() 43 | { 44 | return $this->getData(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Message/CompletePurchasePdtResponse.php: -------------------------------------------------------------------------------- 1 | request = $request; 18 | $this->data = array(); 19 | 20 | // parse ridiculous response format 21 | $lines = explode("\n", $data); 22 | $this->status = $lines[0]; 23 | 24 | foreach ($lines as $line) { 25 | $parts = explode('=', $line, 2); 26 | $this->data[$parts[0]] = isset($parts[1]) ? urldecode($parts[1]) : null; 27 | } 28 | } 29 | 30 | public function isSuccessful() 31 | { 32 | return 'SUCCESS' === $this->status; 33 | } 34 | 35 | public function getMessage() 36 | { 37 | return $this->isSuccessful() ? $this->data['payment_status'] : $this->status; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "omnipay/payfast", 3 | "type": "library", 4 | "description": "PayFast driver for the Omnipay payment processing library", 5 | "keywords": [ 6 | "gateway", 7 | "merchant", 8 | "omnipay", 9 | "pay", 10 | "payfast", 11 | "payment" 12 | ], 13 | "homepage": "https://github.com/thephpleague/omnipay-payfast", 14 | "license": "MIT", 15 | "authors": [ 16 | { 17 | "name": "Adrian Macneil", 18 | "email": "adrian@adrianmacneil.com" 19 | }, 20 | { 21 | "name": "Omnipay Contributors", 22 | "homepage": "https://github.com/thephpleague/omnipay-payfast/contributors" 23 | } 24 | ], 25 | "autoload": { 26 | "psr-4": { "Omnipay\\PayFast\\" : "src/" } 27 | }, 28 | "require": { 29 | "omnipay/common": "^3.0", 30 | "guzzlehttp/guzzle": "^6.3|^7.0", 31 | "league/omnipay": "^3" 32 | }, 33 | "require-dev": { 34 | "omnipay/tests": "^3.1", 35 | "squizlabs/php_codesniffer": "^3" 36 | }, 37 | "extra": { 38 | "branch-alias": { 39 | "dev-master": "3.0.x-dev" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Omnipay: PayFast 2 | 3 | **PayFast driver for the Omnipay PHP payment processing library** 4 | 5 | [![Build Status](https://travis-ci.org/thephpleague/omnipay-payfast.png?branch=master)](https://travis-ci.org/thephpleague/omnipay-payfast) 6 | [![Latest Stable Version](https://poser.pugx.org/omnipay/payfast/version.png)](https://packagist.org/packages/omnipay/payfast) 7 | [![Total Downloads](https://poser.pugx.org/omnipay/payfast/d/total.png)](https://packagist.org/packages/omnipay/payfast) 8 | 9 | [Omnipay](https://github.com/thephpleague/omnipay) is a framework agnostic, multi-gateway payment 10 | processing library for PHP 5.3+. This package implements PayFast support for Omnipay. 11 | 12 | ## Installation 13 | 14 | Omnipay is installed via [Composer](http://getcomposer.org/). To install, simply add it 15 | to your `composer.json` file: 16 | 17 | ```json 18 | { 19 | "require": { 20 | "omnipay/payfast": "~2.0" 21 | } 22 | } 23 | ``` 24 | 25 | And run composer to update your dependencies: 26 | 27 | $ curl -s http://getcomposer.org/installer | php 28 | $ php composer.phar update 29 | 30 | ## Basic Usage 31 | 32 | The following gateways are provided by this package: 33 | 34 | * PayFast 35 | 36 | For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay) 37 | repository. 38 | 39 | ## Support 40 | 41 | If you are having general issues with Omnipay, we suggest posting on 42 | [Stack Overflow](http://stackoverflow.com/). Be sure to add the 43 | [omnipay tag](http://stackoverflow.com/questions/tagged/omnipay) so it can be easily found. 44 | 45 | If you want to keep up to date with release anouncements, discuss ideas for the project, 46 | or ask more detailed questions, there is also a [mailing list](https://groups.google.com/forum/#!forum/omnipay) which 47 | you can subscribe to. 48 | 49 | If you believe you have found a bug, please report it using the [GitHub issue tracker](https://github.com/thephpleague/omnipay-payfast/issues), 50 | or better yet, fork the library and submit a pull request. 51 | -------------------------------------------------------------------------------- /src/Gateway.php: -------------------------------------------------------------------------------- 1 | '', 25 | 'merchantKey' => '', 26 | 'pdtKey' => '', 27 | 'passphrase' => '', 28 | 'testMode' => false, 29 | ); 30 | } 31 | 32 | public function getMerchantId() 33 | { 34 | return $this->getParameter('merchantId'); 35 | } 36 | 37 | public function setMerchantId($value) 38 | { 39 | return $this->setParameter('merchantId', $value); 40 | } 41 | 42 | public function getMerchantKey() 43 | { 44 | return $this->getParameter('merchantKey'); 45 | } 46 | 47 | public function setMerchantKey($value) 48 | { 49 | return $this->setParameter('merchantKey', $value); 50 | } 51 | 52 | public function getPassphrase() 53 | { 54 | return $this->getParameter('passphrase'); 55 | } 56 | 57 | public function setPassphrase($value) 58 | { 59 | return $this->setParameter('passphrase', $value); 60 | } 61 | 62 | public function getPdtKey() 63 | { 64 | return $this->getParameter('pdtKey'); 65 | } 66 | 67 | public function setPdtKey($value) 68 | { 69 | return $this->setParameter('pdtKey', $value); 70 | } 71 | 72 | public function purchase(array $parameters = array()) 73 | { 74 | return $this->createRequest('\Omnipay\PayFast\Message\PurchaseRequest', $parameters); 75 | } 76 | 77 | public function completePurchase(array $parameters = array()) 78 | { 79 | return $this->createRequest('\Omnipay\PayFast\Message\CompletePurchaseRequest', $parameters); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Message/CompletePurchaseRequest.php: -------------------------------------------------------------------------------- 1 | httpRequest->query->get('pt')) { 18 | // this is a Payment Data Transfer request 19 | $data = array(); 20 | $data['pt'] = $this->httpRequest->query->get('pt'); 21 | $data['at'] = $this->getPdtKey(); 22 | 23 | return $data; 24 | } elseif ($signature = $this->httpRequest->request->get('signature')) { 25 | // this is an Instant Transaction Notification request 26 | $data = $this->httpRequest->request->all(); 27 | 28 | // signature is completely useless since it has no shared secret 29 | // signature must not be posted back to the validate URL, so we unset it 30 | unset($data['signature']); 31 | 32 | return $data; 33 | } 34 | 35 | throw new InvalidRequestException('Missing PDT or ITN variables'); 36 | } 37 | 38 | public function sendData($data) 39 | { 40 | if (isset($data['pt'])) { 41 | // validate PDT 42 | $url = $this->getEndpoint().'/query/fetch'; 43 | $httpResponse = $this->httpClient->request('post', $url, [], http_build_query($data)); 44 | return $this->response = new CompletePurchasePdtResponse($this, $httpResponse->getBody()->getContents()); 45 | } else { 46 | // validate ITN 47 | $url = $this->getEndpoint().'/query/validate'; 48 | $httpResponse = $this->httpClient->request('post', $url, [], http_build_query($data)); 49 | $status = $httpResponse->getBody()->getContents(); 50 | return $this->response = new CompletePurchaseItnResponse($this, $data, $status); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/Message/PurchaseRequestTest.php: -------------------------------------------------------------------------------- 1 | request = new PurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); 12 | } 13 | 14 | public function testSignature() 15 | { 16 | $this->request->initialize( 17 | array( 18 | 'amount' => '12.00', 19 | 'description' => 'Test Product', 20 | 'transactionId' => 123, 21 | 'merchantId' => 'foo', 22 | 'merchantKey' => 'bar', 23 | 'returnUrl' => 'https://www.example.com/return', 24 | 'cancelUrl' => 'https://www.example.com/cancel', 25 | ) 26 | ); 27 | 28 | $data = $this->request->getData(); 29 | $this->assertSame('812a071d77d0120073fd53ee7e45aa9b', $data['signature']); 30 | } 31 | 32 | public function testSignatureWithPassphrase() 33 | { 34 | $this->request->initialize( 35 | array( 36 | 'amount' => '12.00', 37 | 'description' => 'Test Product', 38 | 'transactionId' => 123, 39 | 'merchantId' => '10004554', 40 | 'merchantKey' => '93zkeljp6j9ao', 41 | 'returnUrl' => 'https://www.example.com/return', 42 | 'notifyUrl' => 'https://www.example.com/notify', 43 | 'cancelUrl' => 'https://www.example.com/cancel', 44 | ) 45 | ); 46 | $this->request->setPassphrase('ihnKRspB5IZ5bpOzLKbVArpQfiGVuWh'); 47 | 48 | $data = $this->request->getData(); 49 | $this->assertSame('c98b49c6d0914fa8bd13cc8974e2d29e', $data['signature']); 50 | } 51 | 52 | public function testPurchase() 53 | { 54 | $this->request->setAmount('12.00')->setDescription('Test Product'); 55 | 56 | $response = $this->request->send(); 57 | 58 | $this->assertInstanceOf('Omnipay\PayFast\Message\PurchaseResponse', $response); 59 | $this->assertFalse($response->isSuccessful()); 60 | $this->assertTrue($response->isRedirect()); 61 | $this->assertNull($response->getTransactionReference()); 62 | $this->assertNull($response->getMessage()); 63 | $this->assertNull($response->getCode()); 64 | 65 | $this->assertSame('https://www.payfast.co.za/eng/process', $response->getRedirectUrl()); 66 | $this->assertSame('POST', $response->getRedirectMethod()); 67 | $this->assertArrayHasKey('signature', $response->getData()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/Message/CompletePurchaseRequestTest.php: -------------------------------------------------------------------------------- 1 | request = new CompletePurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); 17 | } 18 | 19 | public function getItnPostData() 20 | { 21 | return array( 22 | 'm_payment_id' => '', 23 | 'pf_payment_id' => '61493', 24 | 'payment_status' => 'COMPLETE', 25 | 'item_name' => 'fjdksl', 26 | 'item_description' => '', 27 | 'amount_gross' => '12.00', 28 | 'amount_fee' => '-0.27', 29 | 'amount_net' => '11.73', 30 | 'custom_str1' => '', 31 | 'custom_str2' => '', 32 | 'custom_str3' => '', 33 | 'custom_str4' => '', 34 | 'custom_str5' => '', 35 | 'custom_int1' => '', 36 | 'custom_int2' => '', 37 | 'custom_int3' => '', 38 | 'custom_int4' => '', 39 | 'custom_int5' => '', 40 | 'name_first' => 'Test', 41 | 'name_last' => 'User 01', 42 | 'email_address' => 'sbtu01@payfast.co.za', 43 | 'merchant_id' => '10000103', 44 | 'signature' => '92ac916145511e9050383b008729e162', 45 | ); 46 | } 47 | 48 | public function testCompletePurchaseItnSuccess() 49 | { 50 | $this->getHttpRequest()->request->replace($this->getItnPostData()); 51 | $this->setMockHttpResponse('CompletePurchaseItnSuccess.txt'); 52 | 53 | $response = $this->request->send(); 54 | 55 | $this->assertInstanceOf('Omnipay\PayFast\Message\CompletePurchaseItnResponse', $response); 56 | $this->assertTrue($response->isSuccessful()); 57 | $this->assertFalse($response->isRedirect()); 58 | $this->assertSame('61493', $response->getTransactionReference()); 59 | $this->assertSame('COMPLETE', $response->getMessage()); 60 | $this->assertNull($response->getCode()); 61 | } 62 | 63 | public function testCompletePurchaseItnInvalid() 64 | { 65 | $this->getHttpRequest()->request->replace($this->getItnPostData()); 66 | $this->setMockHttpResponse('CompletePurchaseItnFailure.txt'); 67 | 68 | $response = $this->request->send(); 69 | 70 | $this->assertFalse($response->isSuccessful()); 71 | $this->assertFalse($response->isRedirect()); 72 | $this->assertNull($response->getTransactionReference()); 73 | $this->assertSame('INVALID', $response->getMessage()); 74 | $this->assertNull($response->getCode()); 75 | } 76 | 77 | public function testCompletePurchasePdtSuccess() 78 | { 79 | $this->getHttpRequest()->query->replace(array('pt' => 'abc')); 80 | $this->setMockHttpResponse('CompletePurchasePdtFailure.txt'); 81 | 82 | $response = $this->request->send(); 83 | 84 | $this->assertInstanceOf('Omnipay\PayFast\Message\CompletePurchasePdtResponse', $response); 85 | $this->assertFalse($response->isSuccessful()); 86 | $this->assertFalse($response->isRedirect()); 87 | $this->assertNull($response->getTransactionReference()); 88 | $this->assertSame('FAIL', $response->getMessage()); 89 | $this->assertNull($response->getCode()); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Message/PurchaseRequest.php: -------------------------------------------------------------------------------- 1 | getParameter('merchantId'); 18 | } 19 | 20 | public function setMerchantId($value) 21 | { 22 | return $this->setParameter('merchantId', $value); 23 | } 24 | 25 | public function getMerchantKey() 26 | { 27 | return $this->getParameter('merchantKey'); 28 | } 29 | 30 | public function setMerchantKey($value) 31 | { 32 | return $this->setParameter('merchantKey', $value); 33 | } 34 | 35 | public function getPassphrase() 36 | { 37 | return $this->getParameter('passphrase'); 38 | } 39 | 40 | public function setPassphrase($value) 41 | { 42 | return $this->setParameter('passphrase', $value); 43 | } 44 | 45 | public function getPdtKey() 46 | { 47 | return $this->getParameter('pdtKey'); 48 | } 49 | 50 | public function setPdtKey($value) 51 | { 52 | return $this->setParameter('pdtKey', $value); 53 | } 54 | 55 | public function getCustomStr1() 56 | { 57 | return $this->getParameter('customStr1'); 58 | } 59 | 60 | public function setCustomStr1($value) 61 | { 62 | return $this->setParameter('customStr1', $value); 63 | } 64 | 65 | public function getCustomStr2() 66 | { 67 | return $this->getParameter('customStr2'); 68 | } 69 | 70 | public function setCustomStr2($value) 71 | { 72 | return $this->setParameter('customStr2', $value); 73 | } 74 | 75 | public function getCustomStr3() 76 | { 77 | return $this->getParameter('customStr3'); 78 | } 79 | 80 | public function setCustomStr3($value) 81 | { 82 | return $this->setParameter('customStr3', $value); 83 | } 84 | public function getCustomStr4() 85 | { 86 | return $this->getParameter('customStr4'); 87 | } 88 | 89 | public function setCustomStr4($value) 90 | { 91 | return $this->setParameter('customStr4', $value); 92 | } 93 | 94 | public function getCustomStr5() 95 | { 96 | return $this->getParameter('customStr5'); 97 | } 98 | 99 | public function setCustomStr5($value) 100 | { 101 | return $this->setParameter('customStr5', $value); 102 | } 103 | 104 | public function getCustomInt1() 105 | { 106 | return $this->getParameter('customInt1'); 107 | } 108 | 109 | public function setCustomInt1($value) 110 | { 111 | return $this->setParameter('customInt1', $value); 112 | } 113 | 114 | public function getCustomInt2() 115 | { 116 | return $this->getParameter('customInt2'); 117 | } 118 | 119 | public function setCustomInt2($value) 120 | { 121 | return $this->setParameter('customInt2', $value); 122 | } 123 | 124 | public function getCustomInt3() 125 | { 126 | return $this->getParameter('customInt3'); 127 | } 128 | 129 | public function setCustomInt3($value) 130 | { 131 | return $this->setParameter('customInt3', $value); 132 | } 133 | 134 | public function getCustomInt4() 135 | { 136 | return $this->getParameter('customInt4'); 137 | } 138 | 139 | public function setCustomInt4($value) 140 | { 141 | return $this->setParameter('customInt4', $value); 142 | } 143 | 144 | public function getCustomInt5() 145 | { 146 | return $this->getParameter('customInt5'); 147 | } 148 | 149 | public function setCustomInt5($value) 150 | { 151 | return $this->setParameter('customInt5', $value); 152 | } 153 | 154 | public function getPaymentMethod() 155 | { 156 | return $this->getParameter('paymentMethod'); 157 | } 158 | 159 | public function setPaymentMethod($value) 160 | { 161 | return $this->setParameter('paymentMethod', $value); 162 | } 163 | 164 | public function getSubscriptionType() 165 | { 166 | return $this->getParameter('subscriptionType'); 167 | } 168 | 169 | public function getBillingDate() 170 | { 171 | return $this->getParameter('billingDate'); 172 | } 173 | 174 | public function getRecurringAmount() 175 | { 176 | return $this->getParameter('recurringAmount'); 177 | } 178 | 179 | public function getFrequency() 180 | { 181 | return $this->getParameter('frequency'); 182 | } 183 | 184 | public function getCycles() 185 | { 186 | return $this->getParameter('cycles'); 187 | } 188 | 189 | public function setSubscriptionType($value) 190 | { 191 | return $this->setParameter('subscriptionType', $value); 192 | } 193 | 194 | public function setBillingDate($value) 195 | { 196 | return $this->setParameter('billingDate', $value); 197 | } 198 | 199 | public function setRecurringAmount($value) 200 | { 201 | return $this->setParameter('recurringAmount', $value); 202 | } 203 | 204 | public function setFrequency($value) 205 | { 206 | return $this->setParameter('frequency', $value); 207 | } 208 | 209 | public function setCycles($value) 210 | { 211 | return $this->setParameter('cycles', $value); 212 | } 213 | 214 | public function getData() 215 | { 216 | $this->validate('amount', 'description'); 217 | 218 | $data = array(); 219 | $data['merchant_id'] = $this->getMerchantId(); 220 | $data['merchant_key'] = $this->getMerchantKey(); 221 | $data['return_url'] = $this->getReturnUrl(); 222 | $data['cancel_url'] = $this->getCancelUrl(); 223 | $data['notify_url'] = $this->getNotifyUrl(); 224 | 225 | if ($this->getCard()) { 226 | $data['name_first'] = $this->getCard()->getFirstName(); 227 | $data['name_last'] = $this->getCard()->getLastName(); 228 | $data['email_address'] = $this->getCard()->getEmail(); 229 | } 230 | 231 | $data['m_payment_id'] = $this->getTransactionId(); 232 | $data['amount'] = $this->getAmount(); 233 | $data['item_name'] = $this->getDescription(); 234 | $data['custom_int1'] = $this->getCustomInt1(); 235 | $data['custom_int2'] = $this->getCustomInt2(); 236 | $data['custom_int3'] = $this->getCustomInt3(); 237 | $data['custom_int4'] = $this->getCustomInt4(); 238 | $data['custom_int5'] = $this->getCustomInt5(); 239 | $data['custom_str1'] = $this->getCustomStr1(); 240 | $data['custom_str2'] = $this->getCustomStr2(); 241 | $data['custom_str3'] = $this->getCustomStr3(); 242 | $data['custom_str4'] = $this->getCustomStr4(); 243 | $data['custom_str5'] = $this->getCustomStr5(); 244 | 245 | /** 246 | * Allow overriding the Payment Method 247 | */ 248 | if ($this->getPaymentMethod()) { 249 | $data['payment_method'] = $this->getPaymentMethod(); 250 | } 251 | 252 | /** 253 | * Subscription billing options. 254 | */ 255 | if (1 == $this->getSubscriptionType()) { 256 | $data['subscription_type'] = $this->getSubscriptionType(); 257 | $data['billing_date'] = $this->getBillingDate(); 258 | $data['recurring_amount'] = $this->getRecurringAmount(); 259 | $data['frequency'] = $this->getFrequency(); 260 | $data['cycles'] = $this->getCycles(); 261 | } 262 | if (2 == $this->getSubscriptionType()) { 263 | $data['subscription_type'] = $this->getSubscriptionType(); 264 | } 265 | 266 | $data['passphrase'] = $this->getParameter('passphrase'); 267 | $data['signature'] = $this->generateSignature($data); 268 | unset($data['passphrase']); 269 | 270 | return $data; 271 | } 272 | 273 | protected function generateSignature($data) 274 | { 275 | $fields = array(); 276 | 277 | // specific order required by PayFast 278 | // @see https://developers.payfast.co.za/documentation/#checkout-page 279 | foreach (array('merchant_id', 'merchant_key', 'return_url', 'cancel_url', 'notify_url', 'name_first', 280 | 'name_last', 'email_address', 'cell_number', 281 | /** 282 | * Transaction Details 283 | */ 284 | 'm_payment_id', 'amount', 'item_name', 'item_description', 285 | /** 286 | * Custom return data 287 | */ 288 | 'custom_int1', 'custom_int2', 'custom_int3', 'custom_int4', 'custom_int5', 289 | 'custom_str1', 'custom_str2', 'custom_str3', 'custom_str4', 'custom_str5', 290 | /** 291 | * Email confirmation 292 | */ 293 | 'email_confirmation', 'confirmation_address', 294 | /** 295 | * Payment Method 296 | */ 297 | 'payment_method', 298 | /** 299 | * Subscriptions 300 | */ 301 | 'subscription_type', 'billing_date', 'recurring_amount', 'frequency', 'cycles', 302 | /** 303 | * Passphrase for md5 signature generation 304 | */ 305 | 'passphrase') as $key) { 306 | if (!empty($data[$key])) { 307 | $fields[$key] = $data[$key]; 308 | } 309 | } 310 | 311 | return md5(http_build_query($fields)); 312 | } 313 | 314 | public function sendData($data) 315 | { 316 | return $this->response = new PurchaseResponse($this, $data, $this->getEndpoint().'/process'); 317 | } 318 | 319 | public function getEndpoint() 320 | { 321 | return $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint; 322 | } 323 | } 324 | --------------------------------------------------------------------------------