├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src ├── Gateway.php └── Message │ ├── AbstractRequest.php │ ├── PurchaseRequest.php │ ├── PurchaseResponse.php │ ├── PurchaseStatusRequest.php │ └── PurchaseStatusResponse.php └── tests ├── GatewayTest.php ├── Message ├── PurchaseRequestTest.php └── PurchaseResponseTest.php └── Mock ├── PurchaseFailure.txt └── PurchaseSuccess.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | composer.phar 4 | phpunit.xml 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - hhvm 9 | 10 | before_script: 11 | - composer install -n --dev --prefer-source 12 | 13 | script: vendor/bin/phpcs --standard=PSR2 src && vendor/bin/phpunit --coverage-text 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Omnipay: BitPay 2 | 3 | **BitPay driver for the Omnipay PHP payment processing library** 4 | 5 | [![Build Status](https://travis-ci.org/thephpleague/omnipay-bitpay.png?branch=master)](https://travis-ci.org/thephpleague/omnipay-bitpay) 6 | [![Latest Stable Version](https://poser.pugx.org/omnipay/bitpay/version.png)](https://packagist.org/packages/omnipay/bitpay) 7 | [![Total Downloads](https://poser.pugx.org/omnipay/bitpay/d/total.png)](https://packagist.org/packages/omnipay/bitpay) 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 BitPay 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/bitpay": "dev-master" 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 | * BitPay 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-bitpay/issues), 50 | or better yet, fork the library and submit a pull request. 51 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "omnipay/bitpay", 3 | "type": "library", 4 | "description": "BitPay driver for the Omnipay payment processing library", 5 | "keywords": [ 6 | "bitcoin", 7 | "bitpay", 8 | "gateway", 9 | "merchant", 10 | "omnipay", 11 | "pay", 12 | "payment" 13 | ], 14 | "homepage": "https://github.com/thephpleague/omnipay-bitpay", 15 | "license": "MIT", 16 | "authors": [ 17 | { 18 | "name": "Adrian Macneil", 19 | "email": "adrian@adrianmacneil.com" 20 | }, 21 | { 22 | "name": "Omnipay Contributors", 23 | "homepage": "https://github.com/thephpleague/omnipay-bitpay/contributors" 24 | } 25 | ], 26 | "autoload": { 27 | "psr-4": { "Omnipay\\BitPay\\" : "src/" } 28 | }, 29 | "require": { 30 | "omnipay/common": "~2.0" 31 | }, 32 | "require-dev": { 33 | "omnipay/tests": "~2.0" 34 | }, 35 | "extra": { 36 | "branch-alias": { 37 | "dev-master": "2.0.x-dev" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ./src 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Gateway.php: -------------------------------------------------------------------------------- 1 | '', 23 | 'testMode' => false, 24 | ); 25 | } 26 | 27 | public function getApiKey() 28 | { 29 | return $this->getParameter('apiKey'); 30 | } 31 | 32 | public function setApiKey($value) 33 | { 34 | return $this->setParameter('apiKey', $value); 35 | } 36 | 37 | public function purchase(array $parameters = array()) 38 | { 39 | return $this->createRequest('\Omnipay\BitPay\Message\PurchaseRequest', $parameters); 40 | } 41 | 42 | public function getPurchaseStatus(array $parameters = array()) 43 | { 44 | return $this->createRequest('\Omnipay\BitPay\Message\PurchaseStatusRequest', $parameters); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Message/AbstractRequest.php: -------------------------------------------------------------------------------- 1 | getParameter('apiKey'); 13 | } 14 | 15 | public function setApiKey($value) 16 | { 17 | return $this->setParameter('apiKey', $value); 18 | } 19 | 20 | protected function getHttpMethod() 21 | { 22 | return 'POST'; 23 | } 24 | 25 | public function getEndpoint() 26 | { 27 | return $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint; 28 | } 29 | 30 | public function sendData($data) 31 | { 32 | $httpRequest = $this->httpClient->createRequest( 33 | $this->getHttpMethod(), 34 | $this->getEndpoint(), 35 | array('Authorization' => 'Basic '.base64_encode($this->getApiKey().':')), 36 | $data 37 | ); 38 | 39 | $httpResponse = $httpRequest->send(); 40 | 41 | return $this->response = $this->createResponse($httpResponse->json(), $httpResponse->getStatusCode()); 42 | } 43 | 44 | protected function createResponse($data, $statusCode) 45 | { 46 | return $this->response = new PurchaseResponse($this, $data, $statusCode); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Message/PurchaseRequest.php: -------------------------------------------------------------------------------- 1 | validate('amount', 'currency'); 13 | 14 | $data = array(); 15 | $data['price'] = $this->getAmount(); 16 | $data['currency'] = $this->getCurrency(); 17 | $data['posData'] = $this->getTransactionId(); 18 | $data['itemDesc'] = $this->getDescription(); 19 | $data['notificationURL'] = $this->getNotifyUrl(); 20 | $data['redirectURL'] = $this->getReturnUrl(); 21 | 22 | return $data; 23 | } 24 | 25 | public function getEndpoint() 26 | { 27 | return parent::getEndpoint() . '/invoice'; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Message/PurchaseResponse.php: -------------------------------------------------------------------------------- 1 | data['error']); 21 | } 22 | 23 | public function getMessage() 24 | { 25 | if (isset($this->data['error'])) { 26 | return $this->data['error']['type'] . ': ' . $this->data['error']['message']; 27 | } 28 | } 29 | 30 | public function getTransactionReference() 31 | { 32 | if (isset($this->data['id'])) { 33 | return $this->data['id']; 34 | } 35 | } 36 | 37 | public function getRedirectUrl() 38 | { 39 | if (isset($this->data['url'])) { 40 | return $this->data['url']; 41 | } 42 | } 43 | 44 | public function getRedirectMethod() 45 | { 46 | return 'GET'; 47 | } 48 | 49 | public function getRedirectData() 50 | { 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Message/PurchaseStatusRequest.php: -------------------------------------------------------------------------------- 1 | validate('transactionReference'); 13 | } 14 | 15 | public function getEndpoint() 16 | { 17 | return parent::getEndpoint() . '/' . $this->getTransactionReference(); 18 | } 19 | 20 | protected function getHttpMethod() 21 | { 22 | return 'GET'; 23 | } 24 | 25 | protected function createResponse($data, $statusCode) 26 | { 27 | return $this->response = new PurchaseStatusResponse($this, $data, $statusCode); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Message/PurchaseStatusResponse.php: -------------------------------------------------------------------------------- 1 | getMessage(); 13 | } 14 | 15 | public function isRedirect() 16 | { 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /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' => '10.00')); 19 | 20 | $this->assertInstanceOf('Omnipay\BitPay\Message\PurchaseRequest', $request); 21 | $this->assertSame('10.00', $request->getAmount()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Message/PurchaseRequestTest.php: -------------------------------------------------------------------------------- 1 | request = new PurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); 12 | $this->request->initialize( 13 | array( 14 | 'amount' => '12.00', 15 | 'currency' => 'AUD', 16 | 'transactionId' => '5', 17 | 'description' => 'thing', 18 | 'notifyUrl' => 'https://www.example.com/notify', 19 | 'returnUrl' => 'https://www.example.com/return', 20 | ) 21 | ); 22 | } 23 | 24 | public function testGetData() 25 | { 26 | $data = $this->request->getData(); 27 | 28 | $this->assertSame('12.00', $data['price']); 29 | $this->assertSame('AUD', $data['currency']); 30 | $this->assertSame('5', $data['posData']); 31 | $this->assertSame('thing', $data['itemDesc']); 32 | $this->assertSame('https://www.example.com/notify', $data['notificationURL']); 33 | $this->assertSame('https://www.example.com/return', $data['redirectURL']); 34 | } 35 | 36 | public function testSend() 37 | { 38 | $this->setMockHttpResponse('PurchaseSuccess.txt'); 39 | $response = $this->request->send(); 40 | 41 | $this->assertFalse($response->isSuccessful()); 42 | $this->assertTrue($response->isRedirect()); 43 | } 44 | 45 | public function testGetEndpoint() 46 | { 47 | $this->request->setTestMode(false); 48 | $this->assertSame('https://bitpay.com/api/invoice', $this->request->getEndpoint()); 49 | $this->request->setTestMode(true); 50 | $this->assertSame('https://test.bitpay.com/api/invoice', $this->request->getEndpoint()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/Message/PurchaseResponseTest.php: -------------------------------------------------------------------------------- 1 | getMockHttpResponse('PurchaseSuccess.txt'); 12 | $response = new PurchaseResponse($this->getMockRequest(), $httpResponse->json()); 13 | 14 | $this->assertFalse($response->isSuccessful()); 15 | $this->assertTrue($response->isRedirect()); 16 | $this->assertNull($response->getMessage()); 17 | $this->assertSame('3kTrcSY8gXaSKnYGcYJCcz', $response->getTransactionReference()); 18 | $this->assertSame('https://bitpay.com/invoice?id=3kTrcSY8gXaSKnYGcYJCcz', $response->getRedirectUrl()); 19 | $this->assertSame('GET', $response->getRedirectMethod()); 20 | $this->assertNull($response->getRedirectData()); 21 | } 22 | 23 | public function testPurchaseFailure() 24 | { 25 | $httpResponse = $this->getMockHttpResponse('PurchaseFailure.txt'); 26 | $response = new PurchaseResponse($this->getMockRequest(), $httpResponse->json()); 27 | 28 | $this->assertFalse($response->isSuccessful()); 29 | $this->assertFalse($response->isRedirect()); 30 | $this->assertSame('limitExceeded: Invoice not created due to account limits, please check your approval levels', $response->getMessage()); 31 | $this->assertNull($response->getTransactionReference()); 32 | $this->assertNull($response->getRedirectUrl()); 33 | $this->assertNull($response->getRedirectData()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/Mock/PurchaseFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: cloudflare-nginx 3 | Date: Wed, 22 Jan 2014 05:51:41 GMT 4 | Content-Type: application/json 5 | Transfer-Encoding: chunked 6 | Connection: keep-alive 7 | Set-Cookie: __cfduid=d348c68db92d5d2687232670daf4c62891390369901287; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.bitpay.com; HttpOnly, connect.sid=s%3Ad2AFFeEiSMlvMbAbYZ3I2BVc.3EUN0JFDu5iTQ8%2BszLDrun%2B%2FrGwtpRlrGA9oq5Y20eM; Path=/; HttpOnly 8 | X-Powered-By: Express 9 | CF-RAY: f09f94b08f104b6 10 | 11 | {"error":{"type":"limitExceeded","message":"Invoice not created due to account limits, please check your approval levels"}} 12 | -------------------------------------------------------------------------------- /tests/Mock/PurchaseSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: cloudflare-nginx 3 | Date: Wed, 22 Jan 2014 05:50:22 GMT 4 | Content-Type: application/json 5 | Transfer-Encoding: chunked 6 | Connection: keep-alive 7 | Set-Cookie: __cfduid=d9d05d8d3ebfb59fd01a5b242ff5370db1390369821317; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.bitpay.com; HttpOnly, connect.sid=s%3ABG9aPcAcMbjCd9mU0sQ7xnFw.jA9fJ2UbKpHRr5h5qhQBKZoRFOkQsB%2Fvbiy3QKsobJ8; Path=/; HttpOnly 8 | X-Powered-By: Express 9 | CF-RAY: f09f757386504b6 10 | 11 | {"id":"3kTrcSY8gXaSKnYGcYJCcz","url":"https://bitpay.com/invoice?id=3kTrcSY8gXaSKnYGcYJCcz","status":"new","btcPrice":"0.0130","price":12,"currency":"AUD","invoiceTime":1390369822115,"expirationTime":1390370722115,"currentTime":1390369822186} 12 | --------------------------------------------------------------------------------