Add Bitcoin and Credit Card donations to the donations page. Also tweak some styles and improve some JS

This commit is contained in:
Raoul Snyman 2017-06-20 22:34:56 -07:00
parent 0ede37f008
commit 3d0a116d18
140 changed files with 13655 additions and 41 deletions

View File

@ -3,3 +3,4 @@
cache
output
nikola
stripe.ini

29
conf.py
View File

@ -681,29 +681,6 @@ RSS_TEASERS = False
#"""
EXTRA_HEAD_DATA = """
<link href="/assets/css/ekko-lightbox.css" rel="stylesheet">
<script src="//www.google.com/recaptcha/api.js"></script>
<script type="text/javascript">
var Countly = Countly || {};
Countly.q = Countly.q || [];
Countly.app_key = "53ec944e2cab9356d3577dd1e260dc113fbf210f";
Countly.url = "https://stats.openlp.io";
Countly.q.push(["track_sessions"]);
Countly.q.push(["track_pageview"]);
Countly.q.push(["track_links", document.getElementById("download-section")]);
//load countly script asynchronously
(function() {
var cly = document.createElement("script");
cly.type = "text/javascript";
cly.async = true;
cly.src = "https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js";
cly.onload = function() { Countly.init() };
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(cly, s);
})();
</script>
<script type="text/javascript">window.liveSettings={api_key:"2c307f8400684f0595b35e8101f9fc8a"};</script>
<script type="text/javascript" src="//cdn.transifex.com/live.js"></script>
"""
# Google Analytics or whatever else you use. Added to the bottom of <body>
@ -718,7 +695,13 @@ EXTRA_HEAD_DATA = """
#<script type="text/javascript" src="js/custom.js"></script>
#"""
BODY_END = """
<script type="text/javascript">window.liveSettings={api_key:"2c307f8400684f0595b35e8101f9fc8a"};</script>
<script type="text/javascript" src="https://checkout.stripe.com/checkout.js"></script>
<script type="text/javascript" src="//www.google.com/recaptcha/api.js"></script>
<script type="text/javascript" src="//cdn.transifex.com/live.js"></script>
<script tyle="text/javascript" src="//cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js"></script>
<script type="text/javascript" src="/assets/js/ekko-lightbox.js"></script>
<script type="text/javascript" src="/scripts/openlp.js"></script>
"""
# The possibility to extract metadata from the filename by using a

60
files/donate-cc.php Normal file
View File

@ -0,0 +1,60 @@
<?php
require_once('stripe/init.php');
// Read the config file to get our secret key
$config = parse_ini_file('../stripe.ini')
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey($config['api_key']);
// Token is created using Stripe.js or Checkout!
// Get the payment token submitted by the form:
$token = $_POST['token'];
$amount = $_POST['amount'] * 100;
$return_url = $_POST['return-url'];
$message = '?';
try {
// Charge the user's card:
$charge = \Stripe\Charge::create(array(
"amount" => $amount,
"currency" => "usd",
"description" => "Donation to OpenLP",
"source" => $token,
));
$message .= 'success=' . rawurlencode('Thank you for your donation!');
}
catch(\Stripe\Error\Card $e) {
// Since it's a decline, \Stripe\Error\Card will be caught
$body = $e->getJsonBody();
$err = $body['error'];
$message .= 'error=' . rawurlencode($err['message']);
}
catch (\Stripe\Error\RateLimit $e) {
// Too many requests made to the API too quickly
$message .= 'error=' . rawurlencode('Woah, hold up there, it seems like you\'re clicking the donate button a bit too much. Try again in about 10 minutes');
}
catch (\Stripe\Error\InvalidRequest $e) {
// Invalid parameters were supplied to Stripe's API
$message .= 'error=' . rawurlencode('Oops, there was a problem processing your card. Don\'t worry, you should not have been charged.');
}
catch (\Stripe\Error\Authentication $e) {
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
$message .= 'error=' . rawurlencode('Oops, there was a glitch when processing your card. Don\'t worry, you should not have been charged.');
}
catch (\Stripe\Error\ApiConnection $e) {
// Network communication with Stripe failed
$message .= 'error=' . rawurlencode('Oops, we were unable to process your card. Don\'t worry, you should not have been charged.');
}
catch (\Stripe\Error\Base $e) {
// Display a very generic error to the user, and maybe send
// yourself an email
$message .= 'error=' . rawurlencode('Oh dear, something went wrong. Don\'t worry, you should not have been charged.');
}
catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
$message .= 'error=' . rawurlencode('Oh dear, something went wrong. Don\'t worry, you should not have been charged.');
}
header("Location: " . $return_url . $message);

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

68
files/scripts/openlp.js Normal file
View File

@ -0,0 +1,68 @@
$.urlParam = function(name) {
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
return !!results ? decodeURIComponent(results[1]) : null;
};
function displayErrors() {
if (!!$.urlParam("error")) {
$("#error-message").text($.urlParam("error"));
$("#error-alert").removeClass("hidden");
}
}
function displaySuccess() {
if (!!$.urlParam("success")) {
$("#success-message").text($.urlParam("success"));
$("#success-alert").removeClass("hidden");
}
}
function setUpCountly() {
Countly.init({
app_key: "53ec944e2cab9356d3577dd1e260dc113fbf210f",
url: "https://stats.openlp.io"
});
Countly.track_sessions();
Countly.track_pageview();
Countly.track_errors();
console.log("Countly set up");
}
function setUpStripe() {
var handler = StripeCheckout.configure({
key: "pk_live_GWIWaLW8W53LNTthomxAyO5w",
image: "https://openlp.org/assets/images/logo.png",
locale: "auto",
token: function(token) {
$("#token").val(token.id);
$("#donate").submit();
}
});
$("#donate-button").on("click", function(event) {
console.log("click!");
// Open Checkout with further options:
var amount = parseInt($("#amount").val()) * 100;
handler.open({
name: "OpenLP",
description: "Donate to OpenLP",
amount: amount,
panelLabel: "Donate {{amount}}"
});
event.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener("popstate", function() {
handler.close();
});
$("#return-url").val(location.protocol + "//" + location.host + location.pathname);
}
$(document).ready(function () {
setUpCountly();
if (location.pathname.substr(0, 7) == "/donate") {
// Online set these up on the donate page
displayErrors();
displaySuccess();
setUpStripe();
}
});

View File

@ -0,0 +1,4 @@
service_name: travis-ci
src_dir: .
coverage_clover: clover.xml
json_path: coveralls-upload.json

View File

@ -0,0 +1,5 @@
Please only file issues here that you believe represent actual bugs or feature requests for the Stripe PHP library.
If you're having general trouble with your Stripe integration, please reach out to support using the form at https://support.stripe.com/ (preferred) or via email to support@stripe.com.
If you are reporting a bug, please include your PHP version and the version of the Stripe PHP library you're using, as well as any other details that may be helpful in reproducing the problem.

14
files/stripe/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# Mac OS X dumps these all over the place.
.DS_Store
# Ignore the SimpleTest library if it is installed to /test/.
/test/simpletest/
# Ignore the /vendor/ directory for people using composer
/vendor/
# If the vendor directory isn't being commited the composer.lock file should also be ignored
composer.lock
# Ignore PHPUnit coverage file
clover.xml

38
files/stripe/.travis.yml Normal file
View File

@ -0,0 +1,38 @@
language: php
sudo: false
matrix:
include:
- php: 5.3
env: AUTOLOAD=1
- php: 5.3
env: AUTOLOAD=0
- php: 5.4
env: AUTOLOAD=1
- php: 5.4
env: AUTOLOAD=0
- php: 5.5
env: AUTOLOAD=1
- php: 5.5
env: AUTOLOAD=0
- php: 5.6
env: AUTOLOAD=1
- php: 5.6
env: AUTOLOAD=0
- php: 7.0
env: AUTOLOAD=1
- php: 7.0
env: AUTOLOAD=0
- php: 7.1
env: AUTOLOAD=1
- php: 7.1
env: AUTOLOAD=0
- php: hhvm
dist: trusty
env: AUTOLOAD=1
- php: hhvm
dist: trusty
env: AUTOLOAD=0
script: ./build.php ${AUTOLOAD}
after_script: ./vendor/bin/coveralls -v

462
files/stripe/CHANGELOG.md Normal file
View File

@ -0,0 +1,462 @@
### 4.13.0 2017-06-19
* Add support for ephemeral keys
### 4.12.0 2017-06-05
* Clients can implement `getUserAgentInfo()` to add additional user agent information
### 4.11.0 2017-06-05
* Implement `Countable` for `AttachedObject` (`metadata` and `additional_owners`)
### 4.10.0 2017-05-25
* Add support for login links
### 4.9.1 2017-05-10
* Fix docs to include arrays on `$id` parameter for retrieve methods
### 4.9.0 2017-04-28
* Support for checking webhook signatures
### 4.8.1 2017-04-24
* Allow nested field `payout_schedule` to be updated
### 4.8.0 2017-04-20
* Add `\Stripe\Stripe::setLogger()` to support an external PSR-3 compatible logger
### 4.7.0 2017-04-10
* Add support for payouts and recipient transfers
### 4.6.0 2017-04-06
* Please see 4.7.0 instead (no-op release)
### 4.5.1 2017-03-22
* Remove hard dependency on cURL
### 4.5.0 2017-03-20
* Support for detaching sources from customers
### 4.4.2 2017-02-27
* Correct handling of `owner` parameter when updating sources
### 4.4.1 2017-02-24
* Correct the error check on a bad JSON decoding
### 4.4.0 2017-01-18
* Add support for updating sources
### 4.3.0 2016-11-30
* Add support for verifying sources
### 4.2.0 2016-11-21
* Add retrieve method for 3-D Secure resources
### 4.1.1 2016-10-21
* Add docblock with model properties for `Plan`
### 4.1.0 2016-10-18
* Support for 403 status codes (permission denied)
### 4.0.1 2016-10-17
* Fix transfer reversal materialization
* Fixes for some property definitions in docblocks
### 4.0.0 2016-09-28
* Support for subscription items
* Drop attempt to force TLS 1.2: please note that this could be breaking if you're using old OS distributions or packages and upgraded recently (so please make sure to test your integration!)
### 3.23.0 2016-09-15
* Add support for Apple Pay domains
### 3.22.0 2016-09-13
* Add `Stripe::setAppInfo` to allow plugins to register user agent information
### 3.21.0 2016-08-25
* Add `Source` model for generic payment sources
### 3.20.0 2016-08-08
* Add `getDeclineCode` to card errors
### 3.19.0 2016-07-29
* Opt requests directly into TLS 1.2 where OpenSSL >= 1.0.1 (see #277 for context)
### 3.18.0 2016-07-28
* Add new `STATUS_` constants for subscriptions
### 3.17.1 2016-07-28
* Fix auto-paging iterator so that it plays nicely with `iterator_to_array`
### 3.17.0 2016-07-14
* Add field annotations to model classes for better editor hinting
### 3.16.0 2016-07-12
* Add `ThreeDSecure` model for 3-D secure payments
### 3.15.0 2016-06-29
* Add static `update` method to all resources that can be changed.
### 3.14.3 2016-06-20
* Make sure that cURL never sends `Expects: 100-continue`, even on large request bodies
### 3.14.2 2016-06-03
* Add `inventory` under `SKU` to list of keys that have nested data and can be updated
### 3.14.1 2016-05-27
* Fix some inconsistencies in PHPDoc
### 3.14.0 2016-05-25
* Add support for returning Relay orders
### 3.13.0 2016-05-04
* Add `list`, `create`, `update`, `retrieve`, and `delete` methods to the Subscription class
### 3.12.1 2016-04-07
* Additional check on value arrays for some extra safety
### 3.12.0 2016-03-31
* Fix bug `refreshFrom` on `StripeObject` would not take an `$opts` array
* Fix bug where `$opts` not passed to parent `save` method in `Account`
* Fix bug where non-existent variable was referenced in `reverse` in `Transfer`
* Update CA cert bundle for compatibility with OpenSSL versions below 1.0.1
### 3.11.0 2016-03-22
* Allow `CurlClient` to be initialized with default `CURLOPT_*` options
### 3.10.1 2016-03-22
* Fix bug where request params and options were ignored in `ApplicationFee`'s `refund.`
### 3.10.0 2016-03-15
* Add `reject` on `Account` to support the new API feature
### 3.9.2 2016-03-04
* Fix error when an object's metadata is set more than once
### 3.9.1 2016-02-24
* Fix encoding behavior of nested arrays for requests (see #227)
### 3.9.0 2016-02-09
* Add automatic pagination mechanism with `autoPagingIterator()`
* Allow global account ID to be set with `Stripe::setAccountId()`
### 3.8.0 2016-02-08
* Add `CountrySpec` model for looking up country payment information
### 3.7.1 2016-02-01
* Update bundled CA certs
### 3.7.0 2016-01-27
* Support deleting Relay products and SKUs
### 3.6.0 2016-01-05
* Allow configuration of HTTP client timeouts
### 3.5.0 2015-12-01
* Add a verification routine for external accounts
### 3.4.0 2015-09-14
* Products, SKUs, and Orders -- https://stripe.com/relay
### 3.3.0 2015-09-11
* Add support for 429 Rate Limit response
### 3.2.0 2015-08-17
* Add refund listing and retrieval without an associated charge
### 3.1.0 2015-08-03
* Add dispute listing and retrieval
* Add support for manage account deletion
### 3.0.0 2015-07-28
* Rename `\Stripe\Object` to `\Stripe\StripeObject` (PHP 7 compatibility)
* Rename `getCode` and `getParam` in exceptions to `getStripeCode` and `getStripeParam`
* Add support for calling `json_encode` on Stripe objects in PHP 5.4+
* Start supporting/testing PHP 7
### 2.3.0 2015-07-06
* Add request ID to all Stripe exceptions
### 2.2.0 2015-06-01
* Add support for Alipay accounts as sources
* Add support for bank accounts as sources (private beta)
* Add support for bank accounts and cards as external_accounts on Account objects
### 2.1.4 2015-05-13
* Fix CA certificate file path (thanks @lphilps & @matthewarkin)
### 2.1.3 2015-05-12
* Fix to account updating to permit `tos_acceptance` and `personal_address` to be set properly
* Fix to Transfer reversal creation (thanks @neatness!)
* Network requests are now done through a swappable class for easier mocking
### 2.1.2 2015-04-10
* Remove SSL cert revokation checking (all pre-Heartbleed certs have expired)
* Bug fixes to account updating
### 2.1.1 2015-02-27
* Support transfer reversals
### 2.1.0 2015-02-19
* Support new API version (2015-02-18)
* Added Bitcoin Receiever update and delete actions
* Edited tests to prefer "source" over "card" as per new API version
### 2.0.1 2015-02-16
* Fix to fetching endpoints that use a non-default baseUrl (`FileUpload`)
### 2.0.0 2015-02-14
* Bumped minimum version to 5.3.3
* Switched to Stripe namespace instead of Stripe_ class name prefiexes (thanks @chadicus!)
* Switched tests to PHPUnit (thanks @chadicus!)
* Switched style guide to PSR2 (thanks @chadicus!)
* Added $opts hash to the end of most methods: this permits passing 'idempotency_key', 'stripe_account', or 'stripe_version'. The last 2 will persist across multiple object loads.
* Added support for retrieving Account by ID
### 1.18.0 2015-01-21
* Support making bitcoin charges through BitcoinReceiver source object
### 1.17.5 2014-12-23
* Adding support for creating file uploads.
### 1.17.4 2014-12-15
* Saving objects fetched with a custom key now works (thanks @JustinHook & @jpasilan)
* Added methods for reporting charges as safe or fraudulent and for specifying the reason for refunds
### 1.17.3 2014-11-06
* Better handling of HHVM support for SSL certificate blacklist checking.
### 1.17.2 2014-09-23
* Coupons now are backed by a `Stripe_Coupon` instead of `Stripe_Object`, and support updating metadata
* Running operations (`create`, `retrieve`, `all`) on upcoming invoice items now works
### 1.17.1 2014-07-31
* Requests now send Content-Type header
### 1.17.0 2014-07-29
* Application Fee refunds now a list instead of array
* HHVM now works
* Small bug fixes (thanks @bencromwell & @fastest963)
* __toString now returns the name of the object in addition to its JSON representation
### 1.16.0 2014-06-17
* Add metadata for refunds and disputes
### 1.15.0 2014-05-28
* Support canceling transfers
### 1.14.1 2014-05-21
* Support cards for recipients.
### 1.13.1 2014-05-15
* Fix bug in account resource where `id` wasn't in the result
### 1.13.0 2014-04-10
* Add support for certificate blacklisting
* Update ca bundle
* Drop support for HHVM (Temporarily)
### 1.12.0 2014-04-01
* Add Stripe_RateLimitError for catching rate limit errors.
* Update to Zend coding style (thanks, @jpiasetz)
### 1.11.0 2014-01-29
* Add support for multiple subscriptions per customer
### 1.10.1 2013-12-02
* Add new ApplicationFee
### 1.9.1 2013-11-08
* Fix a bug where a null nestable object causes warnings to fire.
### 1.9.0 2013-10-16
* Add support for metadata API.
### 1.8.4 2013-09-18
* Add support for closing disputes.
### 1.8.3 2013-08-13
* Add new Balance and BalanceTransaction
### 1.8.2 2013-08-12
* Add support for unsetting attributes by updating to NULL.
Setting properties to a blank string is now an error.
### 1.8.1 2013-07-12
* Add support for multiple cards API (Stripe API version 2013-07-12: https://stripe.com/docs/upgrades#2013-07-05)
### 1.8.0 2013-04-11
* Allow Transfers to be creatable
* Add new Recipient resource
### 1.7.15 2013-02-21
* Add 'id' to the list of permanent object attributes
### 1.7.14 2013-02-20
* Don't re-encode strings that are already encoded in UTF-8. If you
were previously using plan or coupon objects with UTF-8 IDs, they
may have been treated as ISO-8859-1 (Latin-1) and encoded to UTF-8 a
2nd time. You may now need to pass the IDs to utf8_encode before
passing them to Stripe_Plan::retrieve or Stripe_Coupon::retrieve.
* Ensure that all input is encoded in UTF-8 before submitting it to
Stripe's servers. (github issue #27)
### 1.7.13 2013-02-01
* Add support for passing options when retrieving Stripe objects
e.g., Stripe_Charge::retrieve(array("id"=>"foo", "expand" => array("customer")))
Stripe_Charge::retrieve("foo") will continue to work
### 1.7.12 2013-01-15
* Add support for setting a Stripe API version override
### 1.7.11 2012-12-30
* Version bump to cleanup constants and such (github issue #26)
### 1.7.10 2012-11-08
* Add support for updating charge disputes.
* Fix bug preventing retrieval of null attributes
### 1.7.9 2012-11-08
* Fix usage under autoloaders such as the one generated by composer
(github issue #22)
### 1.7.8 2012-10-30
* Add support for creating invoices.
* Add support for new invoice lines return format
* Add support for new list objects
### 1.7.7 2012-09-14
* Get all of the various version numbers in the repo in sync (no other
changes)
### 1.7.6 2012-08-31
* Add update and pay methods to Invoice resource
### 1.7.5 2012-08-23
* Change internal function names so that Stripe_SingletonApiRequest is
E_STRICT-clean (github issue #16)
### 1.7.4 2012-08-21
* Bugfix so that Stripe objects (e.g. Customer, Charge objects) used
in API calls are transparently converted to their object IDs
### 1.7.3 2012-08-15
* Add new Account resource
### 1.7.2 2012-06-26
* Make clearer that you should be including lib/Stripe.php, not
test/Stripe.php (github issue #14)
### 1.7.1 2012-05-24
* Add missing argument to Stripe_InvalidRequestError constructor in
Stripe_ApiResource::instanceUrl. Fixes a warning when
Stripe_ApiResource::instanceUrl is called on a resource with no ID
(github issue #12)
### 1.7.0 2012-05-17
* Support Composer and Packagist (github issue #9)
* Add new deleteDiscount method to Stripe_Customer
* Add new Transfer resource
* Switch from using HTTP Basic auth to Bearer auth. (Note: Stripe will
support Basic auth for the indefinite future, but recommends Bearer
auth when possible going forward)
* Numerous test suite improvements

21
files/stripe/LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2010-2015 Stripe
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.

164
files/stripe/README.md Normal file
View File

@ -0,0 +1,164 @@
# Stripe PHP bindings
[![Build Status](https://travis-ci.org/stripe/stripe-php.svg?branch=master)](https://travis-ci.org/stripe/stripe-php)
[![Latest Stable Version](https://poser.pugx.org/stripe/stripe-php/v/stable.svg)](https://packagist.org/packages/stripe/stripe-php)
[![Total Downloads](https://poser.pugx.org/stripe/stripe-php/downloads.svg)](https://packagist.org/packages/stripe/stripe-php)
[![License](https://poser.pugx.org/stripe/stripe-php/license.svg)](https://packagist.org/packages/stripe/stripe-php)
[![Code Coverage](https://coveralls.io/repos/stripe/stripe-php/badge.svg?branch=master)](https://coveralls.io/r/stripe/stripe-php?branch=master)
You can sign up for a Stripe account at https://stripe.com.
## Requirements
PHP 5.3.3 and later.
## Composer
You can install the bindings via [Composer](http://getcomposer.org/). Run the following command:
```bash
composer require stripe/stripe-php
```
To use the bindings, use Composer's [autoload](https://getcomposer.org/doc/00-intro.md#autoloading):
```php
require_once('vendor/autoload.php');
```
## Manual Installation
If you do not wish to use Composer, you can download the [latest release](https://github.com/stripe/stripe-php/releases). Then, to use the bindings, include the `init.php` file.
```php
require_once('/path/to/stripe-php/init.php');
```
## Dependencies
The bindings require the following extension in order to work properly:
- [`curl`](https://secure.php.net/manual/en/book.curl.php), although you can use your own non-cURL client if you prefer
- [`json`](https://secure.php.net/manual/en/book.json.php)
- [`mbstring`](https://secure.php.net/manual/en/book.mbstring.php) (Multibyte String)
If you use Composer, these dependencies should be handled automatically. If you install manually, you'll want to make sure that these extensions are available.
## Getting Started
Simple usage looks like:
```php
\Stripe\Stripe::setApiKey('sk_test_BQokikJOvBiI2HlWgH4olfQ2');
$charge = \Stripe\Charge::create(array('amount' => 2000, 'currency' => 'usd', 'source' => 'tok_189fqt2eZvKYlo2CTGBeg6Uq' ));
echo $charge;
```
## Documentation
Please see https://stripe.com/docs/api for up-to-date documentation.
## Legacy Version Support
If you are using PHP 5.2, you can download v1.18.0 ([zip](https://github.com/stripe/stripe-php/archive/v1.18.0.zip), [tar.gz](https://github.com/stripe/stripe-php/archive/v1.18.0.tar.gz)) from our [releases page](https://github.com/stripe/stripe-php/releases). This version will continue to work with new versions of the Stripe API for all common uses.
This legacy version may be included via `require_once("/path/to/stripe-php/lib/Stripe.php");`, and used like:
```php
Stripe::setApiKey('d8e8fca2dc0f896fd7cb4cb0031ba249');
$charge = Stripe_Charge::create(array('source' => 'tok_XXXXXXXX', 'amount' => 2000, 'currency' => 'usd'));
echo $charge;
```
## Custom Request Timeouts
*NOTE:* We do not recommend decreasing the timeout for non-read-only calls (e.g. charge creation), since even if you locally timeout, the request on Stripe's side can still complete. If you are decreasing timeouts on these calls, make sure to use [idempotency tokens](https://stripe.com/docs/api/php#idempotent_requests) to avoid executing the same transaction twice as a result of timeout retry logic.
To modify request timeouts (connect or total, in seconds) you'll need to tell the API client to use a CurlClient other than its default. You'll set the timeouts in that CurlClient.
```php
// set up your tweaked Curl client
$curl = new \Stripe\HttpClient\CurlClient();
$curl->setTimeout(10); // default is \Stripe\HttpClient\CurlClient::DEFAULT_TIMEOUT
$curl->setConnectTimeout(5); // default is \Stripe\HttpClient\CurlClient::DEFAULT_CONNECT_TIMEOUT
echo $curl->getTimeout(); // 10
echo $curl->getConnectTimeout(); // 5
// tell Stripe to use the tweaked client
\Stripe\ApiRequestor::setHttpClient($curl);
// use the Stripe API client as you normally would
```
## Custom cURL Options (e.g. proxies)
Need to set a proxy for your requests? Pass in the requisite `CURLOPT_*` array to the CurlClient constructor, using the same syntax as `curl_stopt_array()`. This will set the default cURL options for each HTTP request made by the SDK, though many more common options (e.g. timeouts; see above on how to set those) will be overridden by the client even if set here.
```php
// set up your tweaked Curl client
$curl = new \Stripe\HttpClient\CurlClient(array(CURLOPT_PROXY => 'proxy.local:80'));
// tell Stripe to use the tweaked client
\Stripe\ApiRequestor::setHttpClient($curl);
```
Alternately, a callable can be passed to the CurlClient constructor that returns the above array based on request inputs. See `testDefaultOptions()` in `tests/CurlClientTest.php` for an example of this behavior. Note that the callable is called at the beginning of every API request, before the request is sent.
### Configuring a Logger
The library does minimal logging, but it can be configured
with a [`PSR-3` compatible logger][psr3] so that messages
end up there instead of `error_log`:
```php
\Stripe\Stripe::setLogger($logger);
```
### SSL / TLS compatibility issues
Stripe's API now requires that [all connections use TLS 1.2](https://stripe.com/blog/upgrading-tls). Some systems (most notably some older CentOS and RHEL versions) are capable of using TLS 1.2 but will use TLS 1.0 or 1.1 by default. In this case, you'd get an `invalid_request_error` with the following error message: "Stripe no longer supports API requests made with TLS 1.0. Please initiate HTTPS connections with TLS 1.2 or later. You can learn more about this at [https://stripe.com/blog/upgrading-tls](https://stripe.com/blog/upgrading-tls).".
The recommended course of action is to [upgrade your cURL and OpenSSL packages](https://support.stripe.com/questions/how-do-i-upgrade-my-stripe-integration-from-tls-1-0-to-tls-1-2#php) so that TLS 1.2 is used by default, but if that is not possible, you might be able to solve the issue by setting the `CURLOPT_SSLVERSION` option to either `CURL_SSLVERSION_TLSv1` or `CURL_SSLVERSION_TLSv1_2`:
```php
$curl = new \Stripe\HttpClient\CurlClient(array(CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1));
\Stripe\ApiRequestor::setHttpClient($curl);
```
## Development
Install dependencies:
``` bash
composer install
```
## Tests
Install dependencies as mentioned above (which will resolve [PHPUnit](http://packagist.org/packages/phpunit/phpunit)), then you can run the test suite:
```bash
./vendor/bin/phpunit
```
Or to run an individual test file:
```bash
./vendor/bin/phpunit tests/UtilTest.php
```
## Attention plugin developers
Are you writing a plugin that integrates Stripe and embeds our library? Then please use the `setAppInfo` function to identify your plugin. For example:
```php
\Stripe\Stripe::setAppInfo("MyAwesomePlugin", "1.2.34", "https://myawesomeplugin.info");
```
The method should be called once, before any request is sent to the API. The second and third parameters are optional.
### SSL / TLS configuration option
See the "SSL / TLS compatibility issues" paragraph above for full context. If you want to ensure that your plugin can be used on all systems, you should add a configuration option to let your users choose between different values for `CURLOPT_SSLVERSION`: none (default), `CURL_SSLVERSION_TLSv1` and `CURL_SSLVERSION_TLSv1_2`.
[psr3]: http://www.php-fig.org/psr/psr-3/

1
files/stripe/VERSION Normal file
View File

@ -0,0 +1 @@
4.13.0

36
files/stripe/build.php Executable file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env php
<?php
chdir(dirname(__FILE__));
$autoload = (int)$argv[1];
$returnStatus = null;
if (!$autoload) {
// Modify composer to not autoload Stripe
$composer = json_decode(file_get_contents('composer.json'), true);
unset($composer['autoload']);
unset($composer['require-dev']['squizlabs/php_codesniffer']);
file_put_contents('composer.json', json_encode($composer));
}
passthru('composer install', $returnStatus);
if ($returnStatus !== 0) {
exit(1);
}
if ($autoload) {
// Only run CS on 1 of the 2 environments
passthru(
'./vendor/bin/phpcs --standard=PSR2 -n lib tests *.php',
$returnStatus
);
if ($returnStatus !== 0) {
exit(1);
}
}
$config = $autoload ? 'phpunit.xml' : 'phpunit.no_autoload.xml';
passthru("./vendor/bin/phpunit -c $config", $returnStatus);
if ($returnStatus !== 0) {
exit(1);
}

View File

@ -0,0 +1,36 @@
{
"name": "stripe/stripe-php",
"description": "Stripe PHP Library",
"keywords": [
"stripe",
"payment processing",
"api"
],
"homepage": "https://stripe.com/",
"license": "MIT",
"authors": [
{
"name": "Stripe and contributors",
"homepage": "https://github.com/stripe/stripe-php/contributors"
}
],
"require": {
"php": ">=5.3.3",
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
"satooshi/php-coveralls": "~0.6.1",
"squizlabs/php_codesniffer": "~2.0"
},
"autoload": {
"psr-4": { "Stripe\\" : "lib/" }
},
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
}
}

File diff suppressed because it is too large Load Diff

BIN
files/stripe/data/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

80
files/stripe/init.php Normal file
View File

@ -0,0 +1,80 @@
<?php
// Stripe singleton
require(dirname(__FILE__) . '/lib/Stripe.php');
// Utilities
require(dirname(__FILE__) . '/lib/Util/AutoPagingIterator.php');
require(dirname(__FILE__) . '/lib/Util/LoggerInterface.php');
require(dirname(__FILE__) . '/lib/Util/DefaultLogger.php');
require(dirname(__FILE__) . '/lib/Util/RequestOptions.php');
require(dirname(__FILE__) . '/lib/Util/Set.php');
require(dirname(__FILE__) . '/lib/Util/Util.php');
// HttpClient
require(dirname(__FILE__) . '/lib/HttpClient/ClientInterface.php');
require(dirname(__FILE__) . '/lib/HttpClient/CurlClient.php');
// Errors
require(dirname(__FILE__) . '/lib/Error/Base.php');
require(dirname(__FILE__) . '/lib/Error/Api.php');
require(dirname(__FILE__) . '/lib/Error/ApiConnection.php');
require(dirname(__FILE__) . '/lib/Error/Authentication.php');
require(dirname(__FILE__) . '/lib/Error/Card.php');
require(dirname(__FILE__) . '/lib/Error/InvalidRequest.php');
require(dirname(__FILE__) . '/lib/Error/Permission.php');
require(dirname(__FILE__) . '/lib/Error/RateLimit.php');
require(dirname(__FILE__) . '/lib/Error/SignatureVerification.php');
// Plumbing
require(dirname(__FILE__) . '/lib/ApiResponse.php');
require(dirname(__FILE__) . '/lib/JsonSerializable.php');
require(dirname(__FILE__) . '/lib/StripeObject.php');
require(dirname(__FILE__) . '/lib/ApiRequestor.php');
require(dirname(__FILE__) . '/lib/ApiResource.php');
require(dirname(__FILE__) . '/lib/SingletonApiResource.php');
require(dirname(__FILE__) . '/lib/AttachedObject.php');
require(dirname(__FILE__) . '/lib/ExternalAccount.php');
// Stripe API Resources
require(dirname(__FILE__) . '/lib/Account.php');
require(dirname(__FILE__) . '/lib/AlipayAccount.php');
require(dirname(__FILE__) . '/lib/ApplePayDomain.php');
require(dirname(__FILE__) . '/lib/ApplicationFee.php');
require(dirname(__FILE__) . '/lib/ApplicationFeeRefund.php');
require(dirname(__FILE__) . '/lib/Balance.php');
require(dirname(__FILE__) . '/lib/BalanceTransaction.php');
require(dirname(__FILE__) . '/lib/BankAccount.php');
require(dirname(__FILE__) . '/lib/BitcoinReceiver.php');
require(dirname(__FILE__) . '/lib/BitcoinTransaction.php');
require(dirname(__FILE__) . '/lib/Card.php');
require(dirname(__FILE__) . '/lib/Charge.php');
require(dirname(__FILE__) . '/lib/Collection.php');
require(dirname(__FILE__) . '/lib/CountrySpec.php');
require(dirname(__FILE__) . '/lib/Coupon.php');
require(dirname(__FILE__) . '/lib/Customer.php');
require(dirname(__FILE__) . '/lib/Dispute.php');
require(dirname(__FILE__) . '/lib/EphemeralKey.php');
require(dirname(__FILE__) . '/lib/Event.php');
require(dirname(__FILE__) . '/lib/FileUpload.php');
require(dirname(__FILE__) . '/lib/Invoice.php');
require(dirname(__FILE__) . '/lib/InvoiceItem.php');
require(dirname(__FILE__) . '/lib/LoginLink.php');
require(dirname(__FILE__) . '/lib/Order.php');
require(dirname(__FILE__) . '/lib/OrderReturn.php');
require(dirname(__FILE__) . '/lib/Payout.php');
require(dirname(__FILE__) . '/lib/Plan.php');
require(dirname(__FILE__) . '/lib/Product.php');
require(dirname(__FILE__) . '/lib/Recipient.php');
require(dirname(__FILE__) . '/lib/RecipientTransfer.php');
require(dirname(__FILE__) . '/lib/Refund.php');
require(dirname(__FILE__) . '/lib/SKU.php');
require(dirname(__FILE__) . '/lib/Source.php');
require(dirname(__FILE__) . '/lib/Subscription.php');
require(dirname(__FILE__) . '/lib/SubscriptionItem.php');
require(dirname(__FILE__) . '/lib/ThreeDSecure.php');
require(dirname(__FILE__) . '/lib/Token.php');
require(dirname(__FILE__) . '/lib/Transfer.php');
require(dirname(__FILE__) . '/lib/TransferReversal.php');
require(dirname(__FILE__) . '/lib/Webhook.php');
require(dirname(__FILE__) . '/lib/WebhookSignature.php');

View File

@ -0,0 +1,133 @@
<?php
namespace Stripe;
/**
* Class Account
*
* @property string $id
* @property string $object
* @property mixed $business_logo
* @property string $business_name
* @property mixed $business_url
* @property bool $charges_enabled
* @property string $country
* @property bool $debit_negative_balances
* @property mixed $decline_charge_on
* @property string $default_currency
* @property bool $details_submitted
* @property string $display_name
* @property string $email
* @property mixed $external_accounts
* @property mixed $legal_entity
* @property bool $managed
* @property mixed $payout_schedule
* @property mixed $payout_statement_descriptor
* @property bool $payouts_enabled
* @property mixed $product_description
* @property mixed $statement_descriptor
* @property mixed $support_email
* @property mixed $support_phone
* @property string $timezone
* @property mixed $tos_acceptance
* @property mixed $verification
* @property mixed $keys
*
* @package Stripe
*/
class Account extends ApiResource
{
public function instanceUrl()
{
if ($this['id'] === null) {
return '/v1/account';
} else {
return parent::instanceUrl();
}
}
/**
* @param array|string|null $id The ID of the account to retrieve, or an
* options array containing an `id` key.
* @param array|string|null $opts
*
* @return Account
*/
public static function retrieve($id = null, $opts = null)
{
if (!$opts && is_string($id) && substr($id, 0, 3) === 'sk_') {
$opts = $id;
$id = null;
}
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Account
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the account to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Account The updated account.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return Account
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Account The deleted account.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Account The rejected account.
*/
public function reject($params = null, $opts = null)
{
$url = $this->instanceUrl() . '/reject';
list($response, $opts) = $this->_request('post', $url, $params, $opts);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Accounts
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Stripe;
/**
* Class AlipayAccount
*
* @package Stripe
*/
class AlipayAccount extends ExternalAccount
{
}

View File

@ -0,0 +1,290 @@
<?php
namespace Stripe;
/**
* Class ApiRequestor
*
* @package Stripe
*/
class ApiRequestor
{
private $_apiKey;
private $_apiBase;
private static $_httpClient;
public function __construct($apiKey = null, $apiBase = null)
{
$this->_apiKey = $apiKey;
if (!$apiBase) {
$apiBase = Stripe::$apiBase;
}
$this->_apiBase = $apiBase;
}
private static function _encodeObjects($d)
{
if ($d instanceof ApiResource) {
return Util\Util::utf8($d->id);
} elseif ($d === true) {
return 'true';
} elseif ($d === false) {
return 'false';
} elseif (is_array($d)) {
$res = array();
foreach ($d as $k => $v) {
$res[$k] = self::_encodeObjects($v);
}
return $res;
} else {
return Util\Util::utf8($d);
}
}
/**
* @param string $method
* @param string $url
* @param array|null $params
* @param array|null $headers
*
* @return array An array whose first element is an API response and second
* element is the API key used to make the request.
*/
public function request($method, $url, $params = null, $headers = null)
{
if (!$params) {
$params = array();
}
if (!$headers) {
$headers = array();
}
list($rbody, $rcode, $rheaders, $myApiKey) =
$this->_requestRaw($method, $url, $params, $headers);
$json = $this->_interpretResponse($rbody, $rcode, $rheaders);
$resp = new ApiResponse($rbody, $rcode, $rheaders, $json);
return array($resp, $myApiKey);
}
/**
* @param string $rbody A JSON string.
* @param int $rcode
* @param array $rheaders
* @param array $resp
*
* @throws Error\InvalidRequest if the error is caused by the user.
* @throws Error\Authentication if the error is caused by a lack of
* permissions.
* @throws Error\Permission if the error is caused by insufficient
* permissions.
* @throws Error\Card if the error is the error code is 402 (payment
* required)
* @throws Error\RateLimit if the error is caused by too many requests
* hitting the API.
* @throws Error\Api otherwise.
*/
public function handleApiError($rbody, $rcode, $rheaders, $resp)
{
if (!is_array($resp) || !isset($resp['error'])) {
$msg = "Invalid response object from API: $rbody "
. "(HTTP response code was $rcode)";
throw new Error\Api($msg, $rcode, $rbody, $resp, $rheaders);
}
$error = $resp['error'];
$msg = isset($error['message']) ? $error['message'] : null;
$param = isset($error['param']) ? $error['param'] : null;
$code = isset($error['code']) ? $error['code'] : null;
switch ($rcode) {
case 400:
// 'rate_limit' code is deprecated, but left here for backwards compatibility
// for API versions earlier than 2015-09-08
if ($code == 'rate_limit') {
throw new Error\RateLimit($msg, $param, $rcode, $rbody, $resp, $rheaders);
}
// intentional fall-through
case 404:
throw new Error\InvalidRequest($msg, $param, $rcode, $rbody, $resp, $rheaders);
case 401:
throw new Error\Authentication($msg, $rcode, $rbody, $resp, $rheaders);
case 402:
throw new Error\Card($msg, $param, $code, $rcode, $rbody, $resp, $rheaders);
case 403:
throw new Error\Permission($msg, $rcode, $rbody, $resp, $rheaders);
case 429:
throw new Error\RateLimit($msg, $param, $rcode, $rbody, $resp, $rheaders);
default:
throw new Error\Api($msg, $rcode, $rbody, $resp, $rheaders);
}
}
private static function _formatAppInfo($appInfo)
{
if ($appInfo !== null) {
$string = $appInfo['name'];
if ($appInfo['version'] !== null) {
$string .= '/' . $appInfo['version'];
}
if ($appInfo['url'] !== null) {
$string .= ' (' . $appInfo['url'] . ')';
}
return $string;
} else {
return null;
}
}
private static function _defaultHeaders($apiKey, $clientInfo = null)
{
$uaString = 'Stripe/v1 PhpBindings/' . Stripe::VERSION;
$langVersion = phpversion();
$uname = php_uname();
$appInfo = Stripe::getAppInfo();
$ua = array(
'bindings_version' => Stripe::VERSION,
'lang' => 'php',
'lang_version' => $langVersion,
'publisher' => 'stripe',
'uname' => $uname,
);
if ($clientInfo) {
$ua = array_merge($clientInfo, $ua);
}
if ($appInfo !== null) {
$uaString .= ' ' . self::_formatAppInfo($appInfo);
$ua['application'] = $appInfo;
}
$defaultHeaders = array(
'X-Stripe-Client-User-Agent' => json_encode($ua),
'User-Agent' => $uaString,
'Authorization' => 'Bearer ' . $apiKey,
);
return $defaultHeaders;
}
private function _requestRaw($method, $url, $params, $headers)
{
$myApiKey = $this->_apiKey;
if (!$myApiKey) {
$myApiKey = Stripe::$apiKey;
}
if (!$myApiKey) {
$msg = 'No API key provided. (HINT: set your API key using '
. '"Stripe::setApiKey(<API-KEY>)". You can generate API keys from '
. 'the Stripe web interface. See https://stripe.com/api for '
. 'details, or email support@stripe.com if you have any questions.';
throw new Error\Authentication($msg);
}
// Clients can supply arbitrary additional keys to be included in the
// X-Stripe-Client-User-Agent header via the optional getUserAgentInfo()
// method
$clientUAInfo = null;
if (method_exists($this->httpClient(), 'getUserAgentInfo')) {
$clientUAInfo = $this->httpClient()->getUserAgentInfo();
}
$absUrl = $this->_apiBase.$url;
$params = self::_encodeObjects($params);
$defaultHeaders = $this->_defaultHeaders($myApiKey, $clientUAInfo);
if (Stripe::$apiVersion) {
$defaultHeaders['Stripe-Version'] = Stripe::$apiVersion;
}
if (Stripe::$accountId) {
$defaultHeaders['Stripe-Account'] = Stripe::$accountId;
}
$hasFile = false;
$hasCurlFile = class_exists('\CURLFile', false);
foreach ($params as $k => $v) {
if (is_resource($v)) {
$hasFile = true;
$params[$k] = self::_processResourceParam($v, $hasCurlFile);
} elseif ($hasCurlFile && $v instanceof \CURLFile) {
$hasFile = true;
}
}
if ($hasFile) {
$defaultHeaders['Content-Type'] = 'multipart/form-data';
} else {
$defaultHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
}
$combinedHeaders = array_merge($defaultHeaders, $headers);
$rawHeaders = array();
foreach ($combinedHeaders as $header => $value) {
$rawHeaders[] = $header . ': ' . $value;
}
list($rbody, $rcode, $rheaders) = $this->httpClient()->request(
$method,
$absUrl,
$rawHeaders,
$params,
$hasFile
);
return array($rbody, $rcode, $rheaders, $myApiKey);
}
private function _processResourceParam($resource, $hasCurlFile)
{
if (get_resource_type($resource) !== 'stream') {
throw new Error\Api(
'Attempted to upload a resource that is not a stream'
);
}
$metaData = stream_get_meta_data($resource);
if ($metaData['wrapper_type'] !== 'plainfile') {
throw new Error\Api(
'Only plainfile resource streams are supported'
);
}
if ($hasCurlFile) {
// We don't have the filename or mimetype, but the API doesn't care
return new \CURLFile($metaData['uri']);
} else {
return '@'.$metaData['uri'];
}
}
private function _interpretResponse($rbody, $rcode, $rheaders)
{
$resp = json_decode($rbody, true);
$jsonError = json_last_error();
if ($resp === null && $jsonError !== JSON_ERROR_NONE) {
$msg = "Invalid response body from API: $rbody "
. "(HTTP response code was $rcode, json_last_error() was $jsonError)";
throw new Error\Api($msg, $rcode, $rbody);
}
if ($rcode < 200 || $rcode >= 300) {
$this->handleApiError($rbody, $rcode, $rheaders, $resp);
}
return $resp;
}
public static function setHttpClient($client)
{
self::$_httpClient = $client;
}
private function httpClient()
{
if (!self::$_httpClient) {
self::$_httpClient = HttpClient\CurlClient::instance();
}
return self::$_httpClient;
}
}

View File

@ -0,0 +1,202 @@
<?php
namespace Stripe;
/**
* Class ApiResource
*
* @package Stripe
*/
abstract class ApiResource extends StripeObject
{
private static $HEADERS_TO_PERSIST = array('Stripe-Account' => true, 'Stripe-Version' => true);
public static function baseUrl()
{
return Stripe::$apiBase;
}
/**
* @return ApiResource The refreshed resource.
*/
public function refresh()
{
$requestor = new ApiRequestor($this->_opts->apiKey, static::baseUrl());
$url = $this->instanceUrl();
list($response, $this->_opts->apiKey) = $requestor->request(
'get',
$url,
$this->_retrieveOptions,
$this->_opts->headers
);
$this->setLastResponse($response);
$this->refreshFrom($response->json, $this->_opts);
return $this;
}
/**
* @return string The name of the class, with namespacing and underscores
* stripped.
*/
public static function className()
{
$class = get_called_class();
// Useful for namespaces: Foo\Charge
if ($postfixNamespaces = strrchr($class, '\\')) {
$class = substr($postfixNamespaces, 1);
}
// Useful for underscored 'namespaces': Foo_Charge
if ($postfixFakeNamespaces = strrchr($class, '')) {
$class = $postfixFakeNamespaces;
}
if (substr($class, 0, strlen('Stripe')) == 'Stripe') {
$class = substr($class, strlen('Stripe'));
}
$class = str_replace('_', '', $class);
$name = urlencode($class);
$name = strtolower($name);
return $name;
}
/**
* @return string The endpoint URL for the given class.
*/
public static function classUrl()
{
$base = static::className();
return "/v1/${base}s";
}
/**
* @return string The instance endpoint URL for the given class.
*/
public static function resourceUrl($id)
{
if ($id === null) {
$class = get_called_class();
$message = "Could not determine which URL to request: "
. "$class instance has invalid ID: $id";
throw new Error\InvalidRequest($message, null);
}
$id = Util\Util::utf8($id);
$base = static::classUrl();
$extn = urlencode($id);
return "$base/$extn";
}
/**
* @return string The full API URL for this API resource.
*/
public function instanceUrl()
{
return static::resourceUrl($this['id']);
}
protected static function _validateParams($params = null)
{
if ($params && !is_array($params)) {
$message = "You must pass an array as the first argument to Stripe API "
. "method calls. (HINT: an example call to create a charge "
. "would be: \"Stripe\\Charge::create(array('amount' => 100, "
. "'currency' => 'usd', 'source' => 'tok_1234'))\")";
throw new Error\Api($message);
}
}
protected function _request($method, $url, $params = array(), $options = null)
{
$opts = $this->_opts->merge($options);
list($resp, $options) = static::_staticRequest($method, $url, $params, $opts);
$this->setLastResponse($resp);
return array($resp->json, $options);
}
protected static function _staticRequest($method, $url, $params, $options)
{
$opts = Util\RequestOptions::parse($options);
$requestor = new ApiRequestor($opts->apiKey, static::baseUrl());
list($response, $opts->apiKey) = $requestor->request($method, $url, $params, $opts->headers);
foreach ($opts->headers as $k => $v) {
if (!array_key_exists($k, self::$HEADERS_TO_PERSIST)) {
unset($opts->headers[$k]);
}
}
return array($response, $opts);
}
protected static function _retrieve($id, $options = null)
{
$opts = Util\RequestOptions::parse($options);
$instance = new static($id, $opts);
$instance->refresh();
return $instance;
}
protected static function _all($params = null, $options = null)
{
self::_validateParams($params);
$url = static::classUrl();
list($response, $opts) = static::_staticRequest('get', $url, $params, $options);
$obj = Util\Util::convertToStripeObject($response->json, $opts);
if (!is_a($obj, 'Stripe\\Collection')) {
$class = get_class($obj);
$message = "Expected type \"Stripe\\Collection\", got \"$class\" instead";
throw new Error\Api($message);
}
$obj->setLastResponse($response);
$obj->setRequestParams($params);
return $obj;
}
protected static function _create($params = null, $options = null)
{
self::_validateParams($params);
$url = static::classUrl();
list($response, $opts) = static::_staticRequest('post', $url, $params, $options);
$obj = Util\Util::convertToStripeObject($response->json, $opts);
$obj->setLastResponse($response);
return $obj;
}
/**
* @param string $id The ID of the API resource to update.
* @param array|null $params
* @param array|string|null $opts
*
* @return ApiResource the updated API resource
*/
protected static function _update($id, $params = null, $options = null)
{
self::_validateParams($params);
$url = static::resourceUrl($id);
list($response, $opts) = static::_staticRequest('post', $url, $params, $options);
$obj = Util\Util::convertToStripeObject($response->json, $opts);
$obj->setLastResponse($response);
return $obj;
}
protected function _save($options = null)
{
$params = $this->serializeParameters();
if (count($params) > 0) {
$url = $this->instanceUrl();
list($response, $opts) = $this->_request('post', $url, $params, $options);
$this->refreshFrom($response, $opts);
}
return $this;
}
protected function _delete($params = null, $options = null)
{
self::_validateParams($params);
$url = $this->instanceUrl();
list($response, $opts) = $this->_request('delete', $url, $params, $options);
$this->refreshFrom($response, $opts);
return $this;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Stripe;
/**
* Class ApiResponse
*
* @package Stripe
*/
class ApiResponse
{
public $headers;
public $body;
public $json;
public $code;
/**
* @param string $body
* @param integer $code
* @param array|null $headers
* @param array|null $json
*
* @return obj An APIResponse
*/
public function __construct($body, $code, $headers, $json)
{
$this->body = $body;
$this->code = $code;
$this->headers = $headers;
$this->json = $json;
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Stripe;
/**
* Class ApplePayDomain
*
* @package Stripe
*/
class ApplePayDomain extends ApiResource
{
/**
* @return string The class URL for this resource. It needs to be special
* cased because it doesn't fit into the standard resource pattern.
*/
public static function classUrl()
{
return '/v1/apple_pay/domains';
}
/**
* @param array|string $id The ID of the domain to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return ApplePayDomain
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return ApplePayDomain The created domain.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return ApplePayDomain The deleted domain.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of ApplePayDomains
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace Stripe;
/**
* Class ApplicationFee
*
* @package Stripe
*/
class ApplicationFee extends ApiResource
{
/**
* This is a special case because the application fee endpoint has an
* underscore in it. The parent `className` function strips underscores.
*
* @return string The name of the class.
*/
public static function className()
{
return 'application_fee';
}
/**
* @param array|string $id The ID of the application fee to retrieve, or an
* options array containing an `id` key.
* @param array|string|null $opts
*
* @return ApplicationFee
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param string $id The ID of the application fee to update.
* @param array|null $params
* @param array|string|null $options
*
* @return ApplicationFee The updated application fee.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of ApplicationFees
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return ApplicationFee The refunded application fee.
*/
public function refund($params = null, $opts = null)
{
$this->refunds->create($params, $opts);
$this->refresh();
return $this;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Stripe;
/**
* Class ApplicationFeeRefund
*
* @package Stripe
*/
class ApplicationFeeRefund extends ApiResource
{
/**
* @return string The API URL for this Stripe refund.
*/
public function instanceUrl()
{
$id = $this['id'];
$fee = $this['fee'];
if (!$id) {
throw new Error\InvalidRequest(
"Could not determine which URL to request: " .
"class instance has invalid ID: $id",
null
);
}
$id = Util\Util::utf8($id);
$fee = Util\Util::utf8($fee);
$base = ApplicationFee::classUrl();
$feeExtn = urlencode($fee);
$extn = urlencode($id);
return "$base/$feeExtn/refunds/$extn";
}
/**
* @param array|string|null $opts
*
* @return ApplicationFeeRefund The saved refund.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Stripe;
use Countable;
/**
* Class AttachedObject
*
* e.g. metadata on Stripe objects.
*
* @package Stripe
*/
class AttachedObject extends StripeObject implements Countable
{
/**
* Updates this object.
*
* @param array $properties A mapping of properties to update on this object.
*/
public function replaceWith($properties)
{
$removed = array_diff(array_keys($this->_values), array_keys($properties));
// Don't unset, but rather set to null so we send up '' for deletion.
foreach ($removed as $k) {
$this->$k = null;
}
foreach ($properties as $k => $v) {
$this->$k = $v;
}
}
/**
* Counts the number of elements in the AttachedObject instance.
*
* @return int the number of elements
*/
public function count()
{
return count($this->_values);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Stripe;
/**
* Class Balance
*
* @property string $object
* @property mixed $available
* @property bool $livedmode
* @property mixed $pending
*
* @package Stripe
*/
class Balance extends SingletonApiResource
{
/**
* @param array|string|null $opts
*
* @return Balance
*/
public static function retrieve($opts = null)
{
return self::_singletonRetrieve($opts);
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace Stripe;
/**
* Class BalanceTransaction
*
* @property string $id
* @property string $object
* @property int $amount
* @property int $available_on
* @property int $created
* @property string $currency
* @property string $description
* @property int $fee
* @property mixed $fee_details
* @property int $net
* @property string $source
* @property mixed $sourced_transfers
* @property string $status
* @property string $type
*
* @package Stripe
*/
class BalanceTransaction extends ApiResource
{
/**
* @return string The class URL for this resource. It needs to be special
* cased because it doesn't fit into the standard resource pattern.
*/
public static function classUrl()
{
return "/v1/balance/history";
}
/**
* @param array|string $id The ID of the balance transaction to retrieve,
* or an options array containing an `id` key.
* @param array|string|null $opts
*
* @return BalanceTransaction
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of BalanceTransactions
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Stripe;
/**
* Class BankAccount
*
* @package Stripe
*/
class BankAccount extends ExternalAccount
{
/**
* @param array|null $params
* @param array|string|null $options
*
* @return BankAccount The verified bank account.
*/
public function verify($params = null, $options = null)
{
$url = $this->instanceUrl() . '/verify';
list($response, $opts) = $this->_request('post', $url, $params, $options);
$this->refreshFrom($response, $opts);
return $this;
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace Stripe;
/**
* Class BitcoinReceiver
*
* @package Stripe
*/
class BitcoinReceiver extends ExternalAccount
{
/**
* @return string The class URL for this resource. It needs to be special
* cased because it doesn't fit into the standard resource pattern.
*/
public static function classUrl()
{
return "/v1/bitcoin/receivers";
}
/**
* @return string The instance URL for this resource. It needs to be special
* cased because it doesn't fit into the standard resource pattern.
*/
public function instanceUrl()
{
$result = parent::instanceUrl();
if ($result) {
return $result;
} else {
$id = $this['id'];
$id = Util\Util::utf8($id);
$extn = urlencode($id);
$base = BitcoinReceiver::classUrl();
return "$base/$extn";
}
}
/**
* @param array|string $id The ID of the bitcoin receiver to retrieve, or
* an options array containing an `id` key.
* @param array|string|null $opts
*
* @return BitcoinReceiver
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of BitcoinReceivers
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return BitcoinReceiver The created Bitcoin Receiver item.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return BitcoinReceiver The refunded Bitcoin Receiver item.
*/
public function refund($params = null, $options = null)
{
$url = $this->instanceUrl() . '/refund';
list($response, $opts) = $this->_request('post', $url, $params, $options);
$this->refreshFrom($response, $opts);
return $this;
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Stripe;
/**
* Class BitcoinTransaction
*
* @package Stripe
*/
class BitcoinTransaction extends ApiResource
{
}

13
files/stripe/lib/Card.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace Stripe;
/**
* Class Card
*
* @package Stripe
*/
class Card extends ExternalAccount
{
}

185
files/stripe/lib/Charge.php Normal file
View File

@ -0,0 +1,185 @@
<?php
namespace Stripe;
/**
* Class Charge
*
* @property string $id
* @property string $object
* @property int $amount
* @property int $amount_refunded
* @property mixed $application_fee
* @property string $balance_transaction
* @property bool $captured
* @property int $created
* @property string $currency
* @property string $customer
* @property mixed $description
* @property mixed $destination
* @property string|null $dispute
* @property mixed $failure_code
* @property mixed $failure_message
* @property mixed $fraud_details
* @property mixed $invoice
* @property bool $livemode
* @property mixed $metadata
* @property mixed $order
* @property bool $paid
* @property mixed $receipt_email
* @property mixed $receipt_number
* @property bool $refunded
* @property mixed $refunds
* @property mixed $shipping
* @property mixed $source
* @property mixed $source_transfer
* @property mixed $statement_descriptor
* @property string $status
*
* @package Stripe
*/
class Charge extends ApiResource
{
/**
* @param array|string $id The ID of the charge to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $options
*
* @return Charge
*/
public static function retrieve($id, $options = null)
{
return self::_retrieve($id, $options);
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return Collection of Charges
*/
public static function all($params = null, $options = null)
{
return self::_all($params, $options);
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return Charge The created charge.
*/
public static function create($params = null, $options = null)
{
return self::_create($params, $options);
}
/**
* @param string $id The ID of the charge to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Charge The updated charge.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $options
*
* @return Charge The saved charge.
*/
public function save($options = null)
{
return $this->_save($options);
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return Charge The refunded charge.
*/
public function refund($params = null, $options = null)
{
$url = $this->instanceUrl() . '/refund';
list($response, $opts) = $this->_request('post', $url, $params, $options);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return Charge The captured charge.
*/
public function capture($params = null, $options = null)
{
$url = $this->instanceUrl() . '/capture';
list($response, $opts) = $this->_request('post', $url, $params, $options);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @deprecated Use the `save` method on the Dispute object
*
* @return array The updated dispute.
*/
public function updateDispute($params = null, $options = null)
{
$url = $this->instanceUrl() . '/dispute';
list($response, $opts) = $this->_request('post', $url, $params, $options);
$this->refreshFrom(array('dispute' => $response), $opts, true);
return $this->dispute;
}
/**
* @param array|string|null $options
*
* @deprecated Use the `close` method on the Dispute object
*
* @return Charge The updated charge.
*/
public function closeDispute($options = null)
{
$url = $this->instanceUrl() . '/dispute/close';
list($response, $opts) = $this->_request('post', $url, null, $options);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @param array|string|null $opts
*
* @return Charge The updated charge.
*/
public function markAsFraudulent($opts = null)
{
$params = array('fraud_details' => array('user_report' => 'fraudulent'));
$url = $this->instanceUrl();
list($response, $opts) = $this->_request('post', $url, $params, $opts);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @param array|string|null $opts
*
* @return Charge The updated charge.
*/
public function markAsSafe($opts = null)
{
$params = array('fraud_details' => array('user_report' => 'safe'));
$url = $this->instanceUrl();
list($response, $opts) = $this->_request('post', $url, $params, $opts);
$this->refreshFrom($response, $opts);
return $this;
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace Stripe;
/**
* Class Collection
*
* @property string $object
* @property string $url
* @property bool $has_more
* @property mixed $data
*
* @package Stripe
*/
class Collection extends ApiResource
{
protected $_requestParams = array();
public function setRequestParams($params)
{
$this->_requestParams = $params;
}
public function all($params = null, $opts = null)
{
list($url, $params) = $this->extractPathAndUpdateParams($params);
list($response, $opts) = $this->_request('get', $url, $params, $opts);
$this->_requestParams = $params;
return Util\Util::convertToStripeObject($response, $opts);
}
public function create($params = null, $opts = null)
{
list($url, $params) = $this->extractPathAndUpdateParams($params);
list($response, $opts) = $this->_request('post', $url, $params, $opts);
$this->_requestParams = $params;
return Util\Util::convertToStripeObject($response, $opts);
}
public function retrieve($id, $params = null, $opts = null)
{
list($url, $params) = $this->extractPathAndUpdateParams($params);
$id = Util\Util::utf8($id);
$extn = urlencode($id);
list($response, $opts) = $this->_request(
'get',
"$url/$extn",
$params,
$opts
);
$this->_requestParams = $params;
return Util\Util::convertToStripeObject($response, $opts);
}
/**
* @return AutoPagingIterator An iterator that can be used to iterate
* across all objects across all pages. As page boundaries are
* encountered, the next page will be fetched automatically for
* continued iteration.
*/
public function autoPagingIterator()
{
return new Util\AutoPagingIterator($this, $this->_requestParams);
}
private function extractPathAndUpdateParams($params)
{
$url = parse_url($this->url);
if (!isset($url['path'])) {
throw new Error\Api("Could not parse list url into parts: $url");
}
if (isset($url['query'])) {
// If the URL contains a query param, parse it out into $params so they
// don't interact weirdly with each other.
$query = array();
parse_str($url['query'], $query);
// PHP 5.2 doesn't support the ?: operator :(
$params = array_merge($params ? $params : array(), $query);
}
return array($url['path'], $params);
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Stripe;
/**
* Class CountrySpec
*
* @package Stripe
*/
class CountrySpec extends ApiResource
{
/**
* This is a special case because the country specs endpoint has an
* underscore in it. The parent `className` function strips underscores.
*
* @return string The name of the class.
*/
public static function className()
{
return 'country_spec';
}
/**
* @param array|string $country The ISO country code of the country we
* retrieve the country specfication for, or an options array
* containing an `id` containing that code.
* @param array|string|null $opts
*
* @return CountrySpec
*/
public static function retrieve($country, $opts = null)
{
return self::_retrieve($country, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of CountrySpecs
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Stripe;
/**
* Class Coupon
*
* @package Stripe
*/
class Coupon extends ApiResource
{
/**
* @param array|string $id The ID of the coupon to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return Coupon
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Coupon The created coupon.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the coupon to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Coupon The updated coupon.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Coupon The deleted coupon.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
/**
* @param array|string|null $opts
*
* @return Coupon The saved coupon.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Coupons
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,191 @@
<?php
namespace Stripe;
/**
* Class Customer
*
* @property string $id
* @property string $object
* @property int $account_balance
* @property string $business_vat_id
* @property string $created
* @property string $currency
* @property string $default_source
* @property bool $delinquent
* @property string $description
* @property mixed $discount
* @property string $email
* @property bool $livemode
* @property array $metadata
* @property mixed $shipping
* @property Collection $sources
* @property Collection $subscriptions
*
* @package Stripe
*/
class Customer extends ApiResource
{
/**
* @param array|string $id The ID of the customer to retrieve, or an
* options array containing an `id` key.
* @param array|string|null $opts
*
* @return Customer
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Customers
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Customer The created customer.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the customer to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Customer The updated customer.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return Customer The saved customer.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Customer The deleted customer.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
/**
* @param array|null $params
*
* @return InvoiceItem The resulting invoice item.
*/
public function addInvoiceItem($params = null)
{
if (!$params) {
$params = array();
}
$params['customer'] = $this->id;
$ii = InvoiceItem::create($params, $this->_opts);
return $ii;
}
/**
* @param array|null $params
*
* @return array An array of the customer's Invoices.
*/
public function invoices($params = null)
{
if (!$params) {
$params = array();
}
$params['customer'] = $this->id;
$invoices = Invoice::all($params, $this->_opts);
return $invoices;
}
/**
* @param array|null $params
*
* @return array An array of the customer's InvoiceItems.
*/
public function invoiceItems($params = null)
{
if (!$params) {
$params = array();
}
$params['customer'] = $this->id;
$iis = InvoiceItem::all($params, $this->_opts);
return $iis;
}
/**
* @param array|null $params
*
* @return array An array of the customer's Charges.
*/
public function charges($params = null)
{
if (!$params) {
$params = array();
}
$params['customer'] = $this->id;
$charges = Charge::all($params, $this->_opts);
return $charges;
}
/**
* @param array|null $params
*
* @return Subscription The updated subscription.
*/
public function updateSubscription($params = null)
{
$url = $this->instanceUrl() . '/subscription';
list($response, $opts) = $this->_request('post', $url, $params);
$this->refreshFrom(array('subscription' => $response), $opts, true);
return $this->subscription;
}
/**
* @param array|null $params
*
* @return Subscription The cancelled subscription.
*/
public function cancelSubscription($params = null)
{
$url = $this->instanceUrl() . '/subscription';
list($response, $opts) = $this->_request('delete', $url, $params);
$this->refreshFrom(array('subscription' => $response), $opts, true);
return $this->subscription;
}
/**
* @return Customer The updated customer.
*/
public function deleteDiscount()
{
$url = $this->instanceUrl() . '/discount';
list($response, $opts) = $this->_request('delete', $url);
$this->refreshFrom(array('discount' => null), $opts, true);
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace Stripe;
/**
* Class Dispute
*
* @property string $id
* @property string $object
* @property int $amount
* @property mixed $balance_transactions
* @property string $charge
* @property int $created
* @property string $currency
* @property mixed $evidence
* @property mixed $evidence_details
* @property bool $is_charge_refundable
* @property bool $livemode
* @property mixed $metadata
* @property string $reason
* @property string $status
*
* @package Stripe
*/
class Dispute extends ApiResource
{
/**
* @param array|string $id The ID of the dispute to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $options
*
* @return Dispute
*/
public static function retrieve($id, $options = null)
{
return self::_retrieve($id, $options);
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return array An array of Disputes.
*/
public static function all($params = null, $options = null)
{
return self::_all($params, $options);
}
/**
* @param string $id The ID of the dispute to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Dispute The updated dispute.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $options
*
* @return Dispute The saved charge.
*/
public function save($options = null)
{
return $this->_save($options);
}
/**
* @param array|string|null $options
*
* @return Dispute The closed dispute.
*/
public function close($options = null)
{
$url = $this->instanceUrl() . '/close';
list($response, $opts) = $this->_request('post', $url, null, $options);
$this->refreshFrom($response, $opts);
return $this;
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace Stripe;
/**
* Class EphemeralKey
*
* @property string $id
* @property string $object
* @property int $created
* @property int $expires
* @property bool $livemode
* @property string $secret
* @property array $associated_objects
*
* @package Stripe
*/
class EphemeralKey extends ApiResource
{
/**
* This is a special case because the ephemeral key endpoint has an
* underscore in it. The parent `className` function strips underscores.
*
* @return string The name of the class.
*/
public static function className()
{
return 'ephemeral_key';
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return EphemeralKey The created key.
*/
public static function create($params = null, $opts = null)
{
if (!$opts['stripe_version']) {
throw new \InvalidArgumentException('stripe_version must be specified to create an ephemeral key');
}
return self::_create($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return EphemeralKey The deleted key.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace Stripe\Error;
class Api extends Base
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace Stripe\Error;
class ApiConnection extends Base
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace Stripe\Error;
class Authentication extends Base
{
}

View File

@ -0,0 +1,60 @@
<?php
namespace Stripe\Error;
use Exception;
abstract class Base extends Exception
{
public function __construct(
$message,
$httpStatus = null,
$httpBody = null,
$jsonBody = null,
$httpHeaders = null
) {
parent::__construct($message);
$this->httpStatus = $httpStatus;
$this->httpBody = $httpBody;
$this->jsonBody = $jsonBody;
$this->httpHeaders = $httpHeaders;
$this->requestId = null;
if ($httpHeaders && isset($httpHeaders['Request-Id'])) {
$this->requestId = $httpHeaders['Request-Id'];
}
}
public function getHttpStatus()
{
return $this->httpStatus;
}
public function getHttpBody()
{
return $this->httpBody;
}
public function getJsonBody()
{
return $this->jsonBody;
}
public function getHttpHeaders()
{
return $this->httpHeaders;
}
public function getRequestId()
{
return $this->requestId;
}
public function __toString()
{
$id = $this->requestId ? " from API request '{$this->requestId}'": "";
$message = explode("\n", parent::__toString());
$message[0] .= $id;
return implode("\n", $message);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Stripe\Error;
class Card extends Base
{
public function __construct(
$message,
$stripeParam,
$stripeCode,
$httpStatus,
$httpBody,
$jsonBody,
$httpHeaders = null
) {
parent::__construct($message, $httpStatus, $httpBody, $jsonBody, $httpHeaders);
$this->stripeParam = $stripeParam;
$this->stripeCode = $stripeCode;
// This one is not like the others because it was added later and we're
// trying to do our best not to change the public interface of this class'
// constructor. We should consider changing its implementation on the
// next major version bump of this library.
$this->declineCode = isset($jsonBody["error"]["decline_code"]) ? $jsonBody["error"]["decline_code"] : null;
}
public function getDeclineCode()
{
return $this->declineCode;
}
public function getStripeCode()
{
return $this->stripeCode;
}
public function getStripeParam()
{
return $this->stripeParam;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Stripe\Error;
class InvalidRequest extends Base
{
public function __construct(
$message,
$stripeParam,
$httpStatus = null,
$httpBody = null,
$jsonBody = null,
$httpHeaders = null
) {
parent::__construct($message, $httpStatus, $httpBody, $jsonBody, $httpHeaders);
$this->stripeParam = $stripeParam;
}
public function getStripeParam()
{
return $this->stripeParam;
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace Stripe\Error;
class Permission extends Base
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace Stripe\Error;
class RateLimit extends InvalidRequest
{
}

View File

@ -0,0 +1,20 @@
<?php
namespace Stripe\Error;
class SignatureVerification extends Base
{
public function __construct(
$message,
$sigHeader,
$httpBody = null
) {
parent::__construct($message, null, $httpBody, null, null);
$this->sigHeader = $sigHeader;
}
public function getSigHeader()
{
return $this->sigHeader;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Stripe;
/**
* Class Event
*
* @property string $id
* @property string $object
* @property string $api_version
* @property int $created
* @property mixed $data
* @property bool $livemode
* @property int $pending_webhooks
* @property string $request
* @property string $type
*
* @package Stripe
*/
class Event extends ApiResource
{
/**
* @param array|string $id The ID of the event to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return Event
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Events
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,89 @@
<?php
namespace Stripe;
/**
* Class ExternalAccount
*
* @package Stripe
*/
abstract class ExternalAccount extends ApiResource
{
/**
* @return string The instance URL for this resource. It needs to be special
* cased because it doesn't fit into the standard resource pattern.
*/
public function instanceUrl()
{
$id = $this['id'];
if (!$id) {
$class = get_class($this);
$msg = "Could not determine which URL to request: $class instance "
. "has invalid ID: $id";
throw new Error\InvalidRequest($msg, null);
}
if ($this['customer']) {
$parent = $this['customer'];
$base = Customer::classUrl();
$path = 'sources';
} elseif ($this['account']) {
$parent = $this['account'];
$base = Account::classUrl();
$path = 'external_accounts';
} elseif ($this['recipient']) {
$parent = $this['recipient'];
$base = Recipient::classUrl();
$path = 'cards';
} else {
return null;
}
$parent = Util\Util::utf8($parent);
$id = Util\Util::utf8($id);
$parentExtn = urlencode($parent);
$extn = urlencode($id);
return "$base/$parentExtn/$path/$extn";
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return ExternalAccount The deleted external account.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
/**
* @param array|string|null $opts
*
* @return ExternalAccount The saved external account.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return ExternalAccount The verified (or not) external account.
*/
public function verify($params = null, $opts = null)
{
if ($this['customer']) {
$url = $this->instanceUrl() . '/verify';
list($response, $options) = $this->_request('post', $url, $params, $opts);
$this->refreshFrom($response, $options);
return $this;
} else {
$message = 'Only customer external accounts can be verified in this manner.';
throw new Error\Api($message);
}
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace Stripe;
/**
* Class FileUpload
*
* @property string $id
* @property string $object
* @property int $created
* @property string $purpose
* @property int $size
* @property string $type
*
* @package Stripe
*/
class FileUpload extends ApiResource
{
public static function baseUrl()
{
return Stripe::$apiUploadBase;
}
public static function className()
{
return 'file';
}
/**
* @param array|string $id The ID of the file upload to retrieve, or an
* options array containing an `id key.
* @param array|string|null $opts
*
* @return FileUpload
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return FileUpload The created file upload.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of FileUploads
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Stripe\HttpClient;
interface ClientInterface
{
/**
* @param string $method The HTTP method being used
* @param string $absUrl The URL being requested, including domain and protocol
* @param array $headers Headers to be used in the request (full strings, not KV pairs)
* @param array $params KV pairs for parameters. Can be nested for arrays and hashes
* @param boolean $hasFile Whether or not $params references a file (via an @ prefix or
* CurlFile)
* @throws Error\Api & Error\ApiConnection
* @return array($rawBody, $httpStatusCode, $httpHeader)
*/
public function request($method, $absUrl, $headers, $params, $hasFile);
}

View File

@ -0,0 +1,299 @@
<?php
namespace Stripe\HttpClient;
use Stripe\Stripe;
use Stripe\Error;
use Stripe\Util;
// cURL constants are not defined in PHP < 5.5
// @codingStandardsIgnoreStart
// PSR2 requires all constants be upper case. Sadly, the CURL_SSLVERSION
// constants do not abide by those rules.
// Note the values 1 and 6 come from their position in the enum that
// defines them in cURL's source code.
if (!defined('CURL_SSLVERSION_TLSv1')) {
define('CURL_SSLVERSION_TLSv1', 1);
}
if (!defined('CURL_SSLVERSION_TLSv1_2')) {
define('CURL_SSLVERSION_TLSv1_2', 6);
}
// @codingStandardsIgnoreEnd
class CurlClient implements ClientInterface
{
private static $instance;
public static function instance()
{
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
protected $defaultOptions;
protected $userAgentInfo;
/**
* CurlClient constructor.
*
* Pass in a callable to $defaultOptions that returns an array of CURLOPT_* values to start
* off a request with, or an flat array with the same format used by curl_setopt_array() to
* provide a static set of options. Note that many options are overridden later in the request
* call, including timeouts, which can be set via setTimeout() and setConnectTimeout().
*
* Note that request() will silently ignore a non-callable, non-array $defaultOptions, and will
* throw an exception if $defaultOptions returns a non-array value.
*
* @param array|callable|null $defaultOptions
*/
public function __construct($defaultOptions = null)
{
$this->defaultOptions = $defaultOptions;
$this->initUserAgentInfo();
}
public function initUserAgentInfo()
{
$curlVersion = curl_version();
$this->userAgentInfo = array(
'httplib' => 'curl ' . $curlVersion['version'],
'ssllib' => $curlVersion['ssl_version'],
);
}
public function getDefaultOptions()
{
return $this->defaultOptions;
}
public function getUserAgentInfo()
{
return $this->userAgentInfo;
}
// USER DEFINED TIMEOUTS
const DEFAULT_TIMEOUT = 80;
const DEFAULT_CONNECT_TIMEOUT = 30;
private $timeout = self::DEFAULT_TIMEOUT;
private $connectTimeout = self::DEFAULT_CONNECT_TIMEOUT;
public function setTimeout($seconds)
{
$this->timeout = (int) max($seconds, 0);
return $this;
}
public function setConnectTimeout($seconds)
{
$this->connectTimeout = (int) max($seconds, 0);
return $this;
}
public function getTimeout()
{
return $this->timeout;
}
public function getConnectTimeout()
{
return $this->connectTimeout;
}
// END OF USER DEFINED TIMEOUTS
public function request($method, $absUrl, $headers, $params, $hasFile)
{
$curl = curl_init();
$method = strtolower($method);
$opts = array();
if (is_callable($this->defaultOptions)) { // call defaultOptions callback, set options to return value
$opts = call_user_func_array($this->defaultOptions, func_get_args());
if (!is_array($opts)) {
throw new Error\Api("Non-array value returned by defaultOptions CurlClient callback");
}
} elseif (is_array($this->defaultOptions)) { // set default curlopts from array
$opts = $this->defaultOptions;
}
if ($method == 'get') {
if ($hasFile) {
throw new Error\Api(
"Issuing a GET request with a file parameter"
);
}
$opts[CURLOPT_HTTPGET] = 1;
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} elseif ($method == 'post') {
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = $hasFile ? $params : self::encode($params);
} elseif ($method == 'delete') {
$opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} else {
throw new Error\Api("Unrecognized method $method");
}
// Create a callback to capture HTTP headers for the response
$rheaders = array();
$headerCallback = function ($curl, $header_line) use (&$rheaders) {
// Ignore the HTTP request line (HTTP/1.1 200 OK)
if (strpos($header_line, ":") === false) {
return strlen($header_line);
}
list($key, $value) = explode(":", trim($header_line), 2);
$rheaders[trim($key)] = trim($value);
return strlen($header_line);
};
// By default for large request body sizes (> 1024 bytes), cURL will
// send a request without a body and with a `Expect: 100-continue`
// header, which gives the server a chance to respond with an error
// status code in cases where one can be determined right away (say
// on an authentication problem for example), and saves the "large"
// request body from being ever sent.
//
// Unfortunately, the bindings don't currently correctly handle the
// success case (in which the server sends back a 100 CONTINUE), so
// we'll error under that condition. To compensate for that problem
// for the time being, override cURL's behavior by simply always
// sending an empty `Expect:` header.
array_push($headers, 'Expect: ');
$absUrl = Util\Util::utf8($absUrl);
$opts[CURLOPT_URL] = $absUrl;
$opts[CURLOPT_RETURNTRANSFER] = true;
$opts[CURLOPT_CONNECTTIMEOUT] = $this->connectTimeout;
$opts[CURLOPT_TIMEOUT] = $this->timeout;
$opts[CURLOPT_HEADERFUNCTION] = $headerCallback;
$opts[CURLOPT_HTTPHEADER] = $headers;
if (!Stripe::$verifySslCerts) {
$opts[CURLOPT_SSL_VERIFYPEER] = false;
}
curl_setopt_array($curl, $opts);
$rbody = curl_exec($curl);
if (!defined('CURLE_SSL_CACERT_BADFILE')) {
define('CURLE_SSL_CACERT_BADFILE', 77); // constant not defined in PHP
}
$errno = curl_errno($curl);
if ($errno == CURLE_SSL_CACERT ||
$errno == CURLE_SSL_PEER_CERTIFICATE ||
$errno == CURLE_SSL_CACERT_BADFILE
) {
array_push(
$headers,
'X-Stripe-Client-Info: {"ca":"using Stripe-supplied CA bundle"}'
);
$cert = self::caBundle();
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_CAINFO, $cert);
$rbody = curl_exec($curl);
}
if ($rbody === false) {
$errno = curl_errno($curl);
$message = curl_error($curl);
curl_close($curl);
$this->handleCurlError($absUrl, $errno, $message);
}
$rcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
return array($rbody, $rcode, $rheaders);
}
/**
* @param number $errno
* @param string $message
* @throws Error\ApiConnection
*/
private function handleCurlError($url, $errno, $message)
{
switch ($errno) {
case CURLE_COULDNT_CONNECT:
case CURLE_COULDNT_RESOLVE_HOST:
case CURLE_OPERATION_TIMEOUTED:
$msg = "Could not connect to Stripe ($url). Please check your "
. "internet connection and try again. If this problem persists, "
. "you should check Stripe's service status at "
. "https://twitter.com/stripestatus, or";
break;
case CURLE_SSL_CACERT:
case CURLE_SSL_PEER_CERTIFICATE:
$msg = "Could not verify Stripe's SSL certificate. Please make sure "
. "that your network is not intercepting certificates. "
. "(Try going to $url in your browser.) "
. "If this problem persists,";
break;
default:
$msg = "Unexpected error communicating with Stripe. "
. "If this problem persists,";
}
$msg .= " let us know at support@stripe.com.";
$msg .= "\n\n(Network error [errno $errno]: $message)";
throw new Error\ApiConnection($msg);
}
private static function caBundle()
{
return dirname(__FILE__) . '/../../data/ca-certificates.crt';
}
/**
* @param array $arr An map of param keys to values.
* @param string|null $prefix
*
* Only public for testability, should not be called outside of CurlClient
*
* @return string A querystring, essentially.
*/
public static function encode($arr, $prefix = null)
{
if (!is_array($arr)) {
return $arr;
}
$r = array();
foreach ($arr as $k => $v) {
if (is_null($v)) {
continue;
}
if ($prefix) {
if ($k !== null && (!is_int($k) || is_array($v))) {
$k = $prefix."[".$k."]";
} else {
$k = $prefix."[]";
}
}
if (is_array($v)) {
$enc = self::encode($v, $k);
if ($enc) {
$r[] = $enc;
}
} else {
$r[] = urlencode($k)."=".urlencode($v);
}
}
return implode("&", $r);
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace Stripe;
/**
* Class Invoice
*
* @package Stripe
*/
class Invoice extends ApiResource
{
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Invoice The created invoice.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param array|string $id The ID of the invoice to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return Invoice
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Invoices
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param string $id The ID of the invoice to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Invoice The updated invoice.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Invoice The upcoming invoice.
*/
public static function upcoming($params = null, $opts = null)
{
$url = static::classUrl() . '/upcoming';
list($response, $opts) = static::_staticRequest('get', $url, $params, $opts);
$obj = Util\Util::convertToStripeObject($response->json, $opts);
$obj->setLastResponse($response);
return $obj;
}
/**
* @param array|string|null $opts
*
* @return Invoice The saved invoice.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @return Invoice The paid invoice.
*/
public function pay($opts = null)
{
$url = $this->instanceUrl() . '/pay';
list($response, $opts) = $this->_request('post', $url, null, $opts);
$this->refreshFrom($response, $opts);
return $this;
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Stripe;
/**
* Class InvoiceItem
*
* @package Stripe
*/
class InvoiceItem extends ApiResource
{
/**
* @param array|string $id The ID of the invoice item to retrieve, or an
* options array containing an `id` key.
* @param array|string|null $opts
*
* @return InvoiceItem
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of InvoiceItems
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return InvoiceItem The created invoice item.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the invoice item to update.
* @param array|null $params
* @param array|string|null $options
*
* @return InvoiceItem The updated invoice item.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return InvoiceItem The saved invoice item.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return InvoiceItem The deleted invoice item.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Stripe;
// JsonSerializable only exists in PHP 5.4+. Stub if out if it doesn't exist
if (interface_exists('\JsonSerializable', false)) {
interface JsonSerializable extends \JsonSerializable
{
}
} else {
// PSR2 wants each interface to have its own file.
// @codingStandardsIgnoreStart
interface JsonSerializable
{
// @codingStandardsIgnoreEnd
public function jsonSerialize();
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Stripe;
/**
* Class LoginLink
*
* @package Stripe
*/
class LoginLink extends ApiResource
{
}

View File

@ -0,0 +1,88 @@
<?php
namespace Stripe;
/**
* Class Order
*
* @package Stripe
*/
class Order extends ApiResource
{
/**
* @param array|string $id The ID of the order to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return Order
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Order The created Order.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the order to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Order The updated order.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return Order The saved Order.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Orders
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @return Order The paid order.
*/
public function pay($params = null, $opts = null)
{
$url = $this->instanceUrl() . '/pay';
list($response, $opts) = $this->_request('post', $url, $params, $opts);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @return OrderReturn The newly created return.
*/
public function returnOrder($params = null, $opts = null)
{
$url = $this->instanceUrl() . '/returns';
list($response, $opts) = $this->_request('post', $url, $params, $opts);
return Util\Util::convertToStripeObject($response, $opts);
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Stripe;
/**
* Class OrderReturn
*
* @package Stripe
*/
class OrderReturn extends ApiResource
{
/**
* @param array|string $id The ID of the order return to retrieve, or an
* options array containing an `id` field.
* @param array|string|null $opts
*
* @return Order
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of OrderReturns
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace Stripe;
/**
* Class Payout
*
* @property string $id
* @property string $object
* @property int $amount
* @property string $balance_transaction
* @property string $cancellation_balance_transaction
* @property int $created
* @property string $currency
* @property int $arrival_date
* @property string $destination
* @property string $failure_code
* @property string $failure_message
* @property bool $livemode
* @property mixed $metadata
* @property string $method
* @property string $recipient
* @property string $source_type
* @property string $statement_descriptor
* @property string $status
* @property string $type
*
* @package Stripe
*/
class Payout extends ApiResource
{
/**
* @param array|string $id The ID of the payout to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return Payout
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Payouts
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Payout The created payout.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the payout to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Payout The updated payout.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @return Payout The canceled payout.
*/
public function cancel()
{
$url = $this->instanceUrl() . '/cancel';
list($response, $opts) = $this->_request('post', $url);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @param array|string|null $opts
*
* @return Payout The saved payout.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
}

91
files/stripe/lib/Plan.php Normal file
View File

@ -0,0 +1,91 @@
<?php
namespace Stripe;
/**
* Class Plan
*
* @package Stripe
*
* @property $id
* @property $object
* @property $amount
* @property $created
* @property $currency
* @property $interval
* @property $interval_count
* @property $livemode
* @property AttachedObject $metadata
* @property $name
* @property $statement_descriptor
* @property $trial_period_days
*/
class Plan extends ApiResource
{
/**
* @param array|string $id The ID of the plan to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return Plan
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Plan The created plan.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the plan to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Plan The updated plan.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Plan The deleted plan.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
/**
* @param array|string|null $opts
*
* @return Plan The saved plan.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Plans
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Stripe;
/**
* Class Product
*
* @package Stripe
*/
class Product extends ApiResource
{
/**
* @param array|string $id The ID of the product to retrieve, or an options
* array contianing an `id` key.
* @param array|string|null $opts
*
* @return Product
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Product The created Product.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the product to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Product The updated product.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return Product The saved Product.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Products
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Product The deleted product.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace Stripe;
/**
* Class Recipient
*
* @package Stripe
*/
class Recipient extends ApiResource
{
/**
* @param array|string $id The ID of the recipient to retrieve, or an
* options array containing an `id` key.
* @param array|string|null $opts
*
* @return Recipient
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Recipients
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Recipient The created recipient.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the recipient to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Recipient The updated recipient.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return Recipient The saved recipient.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
*
* @return Recipient The deleted recipient.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
/**
* @param array|null $params
*
* @return Collection of the Recipient's Transfers
*/
public function transfers($params = null)
{
if ($params === null) {
$params = array();
}
$params['recipient'] = $this->id;
$transfers = Transfer::all($params, $this->_opts);
return $transfers;
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Stripe;
/**
* Class RecipientTransfer
*
* @property string $id
* @property string $object
* @property int $amount
* @property int $amount_reversed
* @property string $balance_transaction
* @property string $bank_account
* @property string $card
* @property int $created
* @property string $currency
* @property int $date
* @property string $description
* @property string $destination
* @property string $failure_code
* @property string $failure_message
* @property bool $livemode
* @property mixed $metadata
* @property string $method
* @property string $recipient
* @property mixed $reversals
* @property bool $reversed
* @property string $source_type
* @property string $statement_descriptor
* @property string $status
* @property string $type
*
* @package Stripe
*/
class RecipientTransfer extends ApiResource
{
}

View File

@ -0,0 +1,80 @@
<?php
namespace Stripe;
/**
* Class Refund
*
* @property string $id
* @property string $object
* @property int $amount
* @property mixed $balance_transaction
* @property string $charge
* @property int $created
* @property string $currency
* @property mixed $metadata
* @property mixed $reason
* @property mixed $receipt_number
* @property string $status
*
* @package Stripe
*/
class Refund extends ApiResource
{
/**
* @param array|string $id The ID of the refund to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $options
*
* @return Refund
*/
public static function retrieve($id, $options = null)
{
return self::_retrieve($id, $options);
}
/**
* @param string $id The ID of the refund to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Refund The updated refund.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return Collection of Refunds
*/
public static function all($params = null, $options = null)
{
return self::_all($params, $options);
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return Refund The created refund.
*/
public static function create($params = null, $options = null)
{
return self::_create($params, $options);
}
/**
* @param array|string|null $opts
*
* @return Refund The saved refund.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
}

78
files/stripe/lib/SKU.php Normal file
View File

@ -0,0 +1,78 @@
<?php
namespace Stripe;
/**
* Class SKU
*
* @package Stripe
*/
class SKU extends ApiResource
{
/**
* @param array|string $id The ID of the SKU to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return SKU
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return SKU The created SKU.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the SKU to update.
* @param array|null $params
* @param array|string|null $options
*
* @return SKU The updated SKU.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return SKU The saved SKU.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of SKUs
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return SKU The deleted sku.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Stripe;
/**
* Class SingletonApiResource
*
* @package Stripe
*/
abstract class SingletonApiResource extends ApiResource
{
protected static function _singletonRetrieve($options = null)
{
$opts = Util\RequestOptions::parse($options);
$instance = new static(null, $opts);
$instance->refresh();
return $instance;
}
/**
* @return string The endpoint associated with this singleton class.
*/
public static function classUrl()
{
$base = static::className();
return "/v1/${base}";
}
/**
* @return string The endpoint associated with this singleton API resource.
*/
public function instanceUrl()
{
return static::classUrl();
}
}

116
files/stripe/lib/Source.php Normal file
View File

@ -0,0 +1,116 @@
<?php
namespace Stripe;
/**
* Class Source
*
* @package Stripe
*/
class Source extends ApiResource
{
/**
* @param array|string $id The ID of the source to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return Source
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Sources
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Source The created Source.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the source to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Source The updated source.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return Source The saved source.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Source The deleted source.
*/
public function delete($params = null, $options = null)
{
self::_validateParams($params);
$id = $this['id'];
if (!$id) {
$class = get_class($this);
$msg = "Could not determine which URL to request: $class instance "
. "has invalid ID: $id";
throw new Error\InvalidRequest($msg, null);
}
if ($this['customer']) {
$base = Customer::classUrl();
$parentExtn = urlencode(Util\Util::utf8($this['customer']));
$extn = urlencode(Util\Util::utf8($id));
$url = "$base/$parentExtn/sources/$extn";
list($response, $opts) = $this->_request('delete', $url, $params, $options);
$this->refreshFrom($response, $opts);
return $this;
} else {
$message = "Source objects cannot be deleted, they can only be "
. "detached from customer objects. This source object does not "
. "appear to be currently attached to a customer object.";
throw new Error\Api($message);
}
}
/**
* @param array|null $params
* @param array|string|null $options
*
* @return BankAccount The verified bank account.
*/
public function verify($params = null, $options = null)
{
$url = $this->instanceUrl() . '/verify';
list($response, $opts) = $this->_request('post', $url, $params, $options);
$this->refreshFrom($response, $opts);
return $this;
}
}

151
files/stripe/lib/Stripe.php Normal file
View File

@ -0,0 +1,151 @@
<?php
namespace Stripe;
/**
* Class Stripe
*
* @package Stripe
*/
class Stripe
{
// @var string The Stripe API key to be used for requests.
public static $apiKey;
// @var string The base URL for the Stripe API.
public static $apiBase = 'https://api.stripe.com';
// @var string The base URL for the Stripe API uploads endpoint.
public static $apiUploadBase = 'https://uploads.stripe.com';
// @var string|null The version of the Stripe API to use for requests.
public static $apiVersion = null;
// @var string|null The account ID for connected accounts requests.
public static $accountId = null;
// @var boolean Defaults to true.
public static $verifySslCerts = true;
// @var array The application's information (name, version, URL)
public static $appInfo = null;
// @var Util\LoggerInterface|null The logger to which the library will
// produce messages.
public static $logger = null;
const VERSION = '4.13.0';
/**
* @return string The API key used for requests.
*/
public static function getApiKey()
{
return self::$apiKey;
}
/**
* @return Util\LoggerInterface The logger to which the library will
* produce messages.
*/
public static function getLogger()
{
if (self::$logger == null) {
return new Util\DefaultLogger();
}
return self::$logger;
}
/**
* @param Util\LoggerInterface $logger The logger to which the library
* will produce messages.
*/
public static function setLogger($logger)
{
self::$logger = $logger;
}
/**
* Sets the API key to be used for requests.
*
* @param string $apiKey
*/
public static function setApiKey($apiKey)
{
self::$apiKey = $apiKey;
}
/**
* @return string The API version used for requests. null if we're using the
* latest version.
*/
public static function getApiVersion()
{
return self::$apiVersion;
}
/**
* @param string $apiVersion The API version to use for requests.
*/
public static function setApiVersion($apiVersion)
{
self::$apiVersion = $apiVersion;
}
/**
* @return boolean
*/
public static function getVerifySslCerts()
{
return self::$verifySslCerts;
}
/**
* @param boolean $verify
*/
public static function setVerifySslCerts($verify)
{
self::$verifySslCerts = $verify;
}
/**
* @return string | null The Stripe account ID for connected account
* requests.
*/
public static function getAccountId()
{
return self::$accountId;
}
/**
* @param string $accountId The Stripe account ID to set for connected
* account requests.
*/
public static function setAccountId($accountId)
{
self::$accountId = $accountId;
}
/**
* @return array | null The application's information
*/
public static function getAppInfo()
{
return self::$appInfo;
}
/**
* @param string $appName The application's name
* @param string $appVersion The application's version
* @param string $appUrl The application's URL
*/
public static function setAppInfo($appName, $appVersion = null, $appUrl = null)
{
if (self::$appInfo === null) {
self::$appInfo = array();
}
self::$appInfo['name'] = $appName;
self::$appInfo['version'] = $appVersion;
self::$appInfo['url'] = $appUrl;
}
}

View File

@ -0,0 +1,294 @@
<?php
namespace Stripe;
use ArrayAccess;
use InvalidArgumentException;
/**
* Class StripeObject
*
* @package Stripe
*/
class StripeObject implements ArrayAccess, JsonSerializable
{
/**
* @var Util\Set Attributes that should not be sent to the API because
* they're not updatable (e.g. API key, ID).
*/
public static $permanentAttributes;
/**
* @var Util\Set Attributes that are nested but still updatable from
* the parent class's URL (e.g. metadata).
*/
public static $nestedUpdatableAttributes;
public static function init()
{
self::$permanentAttributes = new Util\Set(array('_opts', 'id'));
self::$nestedUpdatableAttributes = new Util\Set(array(
'metadata', 'legal_entity', 'address', 'dob', 'payout_schedule', 'transfer_schedule', 'verification',
'tos_acceptance', 'personal_address',
// will make the array into an AttachedObject: weird, but works for now
'additional_owners', 0, 1, 2, 3, 4, // Max 3, but leave the 4th so errors work properly
'inventory',
'owner',
));
}
/**
* @return object The last response from the Stripe API
*/
public function getLastResponse()
{
return $this->_lastResponse;
}
/**
* @param ApiResponse
*
* @return void Set the last response from the Stripe API
*/
public function setLastResponse($resp)
{
$this->_lastResponse = $resp;
}
protected $_opts;
protected $_values;
protected $_unsavedValues;
protected $_transientValues;
protected $_retrieveOptions;
protected $_lastResponse;
public function __construct($id = null, $opts = null)
{
$this->_opts = $opts ? $opts : new Util\RequestOptions();
$this->_values = array();
$this->_unsavedValues = new Util\Set();
$this->_transientValues = new Util\Set();
$this->_retrieveOptions = array();
if (is_array($id)) {
foreach ($id as $key => $value) {
if ($key != 'id') {
$this->_retrieveOptions[$key] = $value;
}
}
$id = $id['id'];
}
if ($id !== null) {
$this->id = $id;
}
}
// Standard accessor magic methods
public function __set($k, $v)
{
if ($v === "") {
throw new InvalidArgumentException(
'You cannot set \''.$k.'\'to an empty string. '
.'We interpret empty strings as NULL in requests. '
.'You may set obj->'.$k.' = NULL to delete the property'
);
}
if (self::$nestedUpdatableAttributes->includes($k)
&& isset($this->$k) && $this->$k instanceof AttachedObject && is_array($v)) {
$this->$k->replaceWith($v);
} else {
// TODO: may want to clear from $_transientValues (Won't be user-visible).
$this->_values[$k] = $v;
}
if (!self::$permanentAttributes->includes($k)) {
$this->_unsavedValues->add($k);
}
}
public function __isset($k)
{
return isset($this->_values[$k]);
}
public function __unset($k)
{
unset($this->_values[$k]);
$this->_transientValues->add($k);
$this->_unsavedValues->discard($k);
}
public function &__get($k)
{
// function should return a reference, using $nullval to return a reference to null
$nullval = null;
if (!empty($this->_values) && array_key_exists($k, $this->_values)) {
return $this->_values[$k];
} else if (!empty($this->_transientValues) && $this->_transientValues->includes($k)) {
$class = get_class($this);
$attrs = join(', ', array_keys($this->_values));
$message = "Stripe Notice: Undefined property of $class instance: $k. "
. "HINT: The $k attribute was set in the past, however. "
. "It was then wiped when refreshing the object "
. "with the result returned by Stripe's API, "
. "probably as a result of a save(). The attributes currently "
. "available on this object are: $attrs";
Stripe::getLogger()->error($message);
return $nullval;
} else {
$class = get_class($this);
Stripe::getLogger()->error("Stripe Notice: Undefined property of $class instance: $k");
return $nullval;
}
}
// ArrayAccess methods
public function offsetSet($k, $v)
{
$this->$k = $v;
}
public function offsetExists($k)
{
return array_key_exists($k, $this->_values);
}
public function offsetUnset($k)
{
unset($this->$k);
}
public function offsetGet($k)
{
return array_key_exists($k, $this->_values) ? $this->_values[$k] : null;
}
public function keys()
{
return array_keys($this->_values);
}
/**
* This unfortunately needs to be public to be used in Util\Util
*
* @param array $values
* @param array $opts
*
* @return StripeObject The object constructed from the given values.
*/
public static function constructFrom($values, $opts)
{
$obj = new static(isset($values['id']) ? $values['id'] : null);
$obj->refreshFrom($values, $opts);
return $obj;
}
/**
* Refreshes this object using the provided values.
*
* @param array $values
* @param array|Util\RequestOptions $opts
* @param boolean $partial Defaults to false.
*/
public function refreshFrom($values, $opts, $partial = false)
{
if (is_array($opts)) {
$opts = Util\RequestOptions::parse($opts);
}
$this->_opts = $opts;
// Wipe old state before setting new. This is useful for e.g. updating a
// customer, where there is no persistent card parameter. Mark those values
// which don't persist as transient
if ($partial) {
$removed = new Util\Set();
} else {
$removed = array_diff(array_keys($this->_values), array_keys($values));
}
foreach ($removed as $k) {
if (self::$permanentAttributes->includes($k)) {
continue;
}
unset($this->$k);
}
foreach ($values as $k => $v) {
if (self::$permanentAttributes->includes($k) && isset($this[$k])) {
continue;
}
if (self::$nestedUpdatableAttributes->includes($k) && is_array($v)) {
$this->_values[$k] = AttachedObject::constructFrom($v, $opts);
} else {
$this->_values[$k] = Util\Util::convertToStripeObject($v, $opts);
}
$this->_transientValues->discard($k);
$this->_unsavedValues->discard($k);
}
}
/**
* @return array A recursive mapping of attributes to values for this object,
* including the proper value for deleted attributes.
*/
public function serializeParameters()
{
$params = array();
if ($this->_unsavedValues) {
foreach ($this->_unsavedValues->toArray() as $k) {
$v = $this->$k;
if ($v === null) {
$v = '';
}
$params[$k] = $v;
}
}
// Get nested updates.
foreach (self::$nestedUpdatableAttributes->toArray() as $property) {
if (isset($this->$property)) {
if ($this->$property instanceof StripeObject) {
$serialized = $this->$property->serializeParameters();
if ($serialized) {
$params[$property] = $serialized;
}
}
}
}
return $params;
}
public function jsonSerialize()
{
return $this->__toArray(true);
}
public function __toJSON()
{
if (defined('JSON_PRETTY_PRINT')) {
return json_encode($this->__toArray(true), JSON_PRETTY_PRINT);
} else {
return json_encode($this->__toArray(true));
}
}
public function __toString()
{
$class = get_class($this);
return $class . ' JSON: ' . $this->__toJSON();
}
public function __toArray($recursive = false)
{
if ($recursive) {
return Util\Util::convertStripeObjectToArray($this->_values);
} else {
return $this->_values;
}
}
}
StripeObject::init();

View File

@ -0,0 +1,98 @@
<?php
namespace Stripe;
/**
* Class Subscription
*
* @package Stripe
*/
class Subscription extends ApiResource
{
/**
* These constants are possible representations of the status field.
*
* @link https://stripe.com/docs/api#subscription_object-status
*/
const STATUS_ACTIVE = 'active';
const STATUS_CANCELED = 'canceled';
const STATUS_PAST_DUE = 'past_due';
const STATUS_TRIALING = 'trialing';
const STATUS_UNPAID = 'unpaid';
/**
* @param array|string $id The ID of the subscription to retrieve, or an
* options array containing an `id` key.
* @param array|string|null $opts
*
* @return Subscription
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Subscriptions
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Subscription The created subscription.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the subscription to retrieve.
* @param array|null $params
* @param array|string|null $options
*
* @return Subscription The updated subscription.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|null $params
*
* @return Subscription The deleted subscription.
*/
public function cancel($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
/**
* @param array|string|null $opts
*
* @return Subscription The saved subscription.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @return Subscription The updated subscription.
*/
public function deleteDiscount()
{
$url = $this->instanceUrl() . '/discount';
list($response, $opts) = $this->_request('delete', $url);
$this->refreshFrom(array('discount' => null), $opts, true);
}
}

View File

@ -0,0 +1,89 @@
<?php
namespace Stripe;
/**
* Class SubscriptionItem
*
* @package Stripe
*/
class SubscriptionItem extends ApiResource
{
/**
* This is a special case because the subscription items endpoint has an
* underscore in it. The parent `className` function strips underscores.
*
* @return string The name of the class.
*/
public static function className()
{
return 'subscription_item';
}
/**
* @param array|string $id The ID of the subscription item to retrieve, or
* an options array containing an `id` key.
* @param array|string|null $opts
*
* @return SubscriptionItem
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of SubscriptionItems
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return SubscriptionItem The created subscription item.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the subscription item to update.
* @param array|null $params
* @param array|string|null $options
*
* @return SubscriptionItem The updated subscription item.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @param array|string|null $opts
*
* @return SubscriptionItem The saved subscription item.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return SubscriptionItem The deleted subscription item.
*/
public function delete($params = null, $opts = null)
{
return $this->_delete($params, $opts);
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Stripe;
class ThreeDSecure extends ApiResource
{
/**
* @return string The endpoint URL for the given class.
*/
public static function classUrl()
{
return "/v1/3d_secure";
}
/**
* @param array|string $id The ID of the 3DS auth to retrieve, or an
* options array contianing an `id` key.
* @param array|string|null $options
*
* @return ThreeDSecure
*/
public static function retrieve($id, $options = null)
{
return self::_retrieve($id, $options);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return ThreeDSecure The created 3D Secure object.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Stripe;
/**
* Class Token
*
* @property string $id
* @property string $object
* @property mixed $bank_account
* @property mixed $card
* @property mixed $client_ip
* @property int $created
* @property bool $livemode
* @property string $type
* @property bool $used
*
* @package Stripe
*/
class Token extends ApiResource
{
/**
* @param array|string $id The ID of the token to retrieve, or an options
* array containing an `id` key.
* @param array|string|null $opts
*
* @return Token
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Token The created token.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
}

View File

@ -0,0 +1,105 @@
<?php
namespace Stripe;
/**
* Class Transfer
*
* @property string $id
* @property string $object
* @property int $amount
* @property int $amount_reversed
* @property string $balance_transaction
* @property int $created
* @property string $currency
* @property int $date
* @property mixed $destination
* @property mixed $destination_payment
* @property bool $livemode
* @property mixed $metadata
* @property mixed $reversals
* @property bool $reversed
* @property mixed $source_transaction
*
* @package Stripe
*/
class Transfer extends ApiResource
{
/**
* @param array|string $id The ID of the transfer to retrieve, or an
* options array containing an `id` key.
* @param array|string|null $opts
*
* @return Transfer
*/
public static function retrieve($id, $opts = null)
{
return self::_retrieve($id, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Collection of Transfers
*/
public static function all($params = null, $opts = null)
{
return self::_all($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @return Transfer The created transfer.
*/
public static function create($params = null, $opts = null)
{
return self::_create($params, $opts);
}
/**
* @param string $id The ID of the transfer to update.
* @param array|null $params
* @param array|string|null $options
*
* @return Transfer The updated transfer.
*/
public static function update($id, $params = null, $options = null)
{
return self::_update($id, $params, $options);
}
/**
* @return TransferReversal The created transfer reversal.
*/
public function reverse($params = null, $opts = null)
{
$url = $this->instanceUrl() . '/reversals';
list($response, $opts) = $this->_request('post', $url, $params, $opts);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @return Transfer The canceled transfer.
*/
public function cancel()
{
$url = $this->instanceUrl() . '/cancel';
list($response, $opts) = $this->_request('post', $url);
$this->refreshFrom($response, $opts);
return $this;
}
/**
* @param array|string|null $opts
*
* @return Transfer The saved transfer.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace Stripe;
/**
* Class TransferReversal
*
* @property string $id
* @property string $object
* @property int $amount
* @property string $balance_transaction
* @property int $created
* @property string $currency
* @property mixed $metadata
* @property string $transfer
*
* @package Stripe
*/
class TransferReversal extends ApiResource
{
/**
* @return string The API URL for this Stripe transfer reversal.
*/
public function instanceUrl()
{
$id = $this['id'];
$transfer = $this['transfer'];
if (!$id) {
throw new Error\InvalidRequest(
"Could not determine which URL to request: " .
"class instance has invalid ID: $id",
null
);
}
$id = Util\Util::utf8($id);
$transfer = Util\Util::utf8($transfer);
$base = Transfer::classUrl();
$transferExtn = urlencode($transfer);
$extn = urlencode($id);
return "$base/$transferExtn/reversals/$extn";
}
/**
* @param array|string|null $opts
*
* @return TransferReversal The saved reversal.
*/
public function save($opts = null)
{
return $this->_save($opts);
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace Stripe\Util;
class AutoPagingIterator implements \Iterator
{
private $lastId = null;
private $page = null;
private $pageOffset = 0;
private $params = array();
public function __construct($collection, $params)
{
$this->page = $collection;
$this->params = $params;
}
public function rewind()
{
// Actually rewinding would require making a copy of the original page.
}
public function current()
{
$item = current($this->page->data);
$this->lastId = $item !== false ? $item['id'] : null;
return $item;
}
public function key()
{
return key($this->page->data) + $this->pageOffset;
}
public function next()
{
$item = next($this->page->data);
if ($item === false) {
// If we've run out of data on the current page, try to fetch another one
// and increase the offset the new page would start at
$this->pageOffset += count($this->page->data);
if ($this->page['has_more']) {
$this->params = array_merge(
$this->params ? $this->params : array(),
array('starting_after' => $this->lastId)
);
$this->page = $this->page->all($this->params);
} else {
return false;
}
}
}
public function valid()
{
$key = key($this->page->data);
$valid = ($key !== null && $key !== false);
return $valid;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Stripe\Util;
/**
* A very basic implementation of LoggerInterface that has just enough
* functionality that it can be the default for this library.
*/
class DefaultLogger implements LoggerInterface
{
public function error($message, array $context = array())
{
if (count($context) > 0) {
throw new Exception('DefaultLogger does not currently implement context. Please implement if you need it.');
}
error_log($message);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Stripe\Util;
/**
* Describes a logger instance.
*
* This is a subset of the interface of the same name in the PSR-3 logger
* interface. We guarantee to keep it compatible, but we'd redefined it here so
* that we don't have to pull in the extra dependencies for users who don't want
* it.
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data, the only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*/
interface LoggerInterface
{
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
* @return null
*/
public function error($message, array $context = array());
}

View File

@ -0,0 +1,79 @@
<?php
namespace Stripe\Util;
use Stripe\Error;
class RequestOptions
{
public $headers;
public $apiKey;
public function __construct($key = null, $headers = array())
{
$this->apiKey = $key;
$this->headers = $headers;
}
/**
* Unpacks an options array and merges it into the existing RequestOptions
* object.
* @param array|string|null $options a key => value array
*
* @return RequestOptions
*/
public function merge($options)
{
$other_options = self::parse($options);
if ($other_options->apiKey === null) {
$other_options->apiKey = $this->apiKey;
}
$other_options->headers = array_merge($this->headers, $other_options->headers);
return $other_options;
}
/**
* Unpacks an options array into an RequestOptions object
* @param array|string|null $options a key => value array
*
* @return RequestOptions
*/
public static function parse($options)
{
if ($options instanceof self) {
return $options;
}
if (is_null($options)) {
return new RequestOptions(null, array());
}
if (is_string($options)) {
return new RequestOptions($options, array());
}
if (is_array($options)) {
$headers = array();
$key = null;
if (array_key_exists('api_key', $options)) {
$key = $options['api_key'];
}
if (array_key_exists('idempotency_key', $options)) {
$headers['Idempotency-Key'] = $options['idempotency_key'];
}
if (array_key_exists('stripe_account', $options)) {
$headers['Stripe-Account'] = $options['stripe_account'];
}
if (array_key_exists('stripe_version', $options)) {
$headers['Stripe-Version'] = $options['stripe_version'];
}
return new RequestOptions($key, $headers);
}
$message = 'The second argument to Stripe API method calls is an '
. 'optional per-request apiKey, which must be a string, or '
. 'per-request options, which must be an array. (HINT: you can set '
. 'a global apiKey by "Stripe::setApiKey(<apiKey>)")';
throw new Error\Api($message);
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Stripe\Util;
use IteratorAggregate;
use ArrayIterator;
class Set implements IteratorAggregate
{
private $_elts;
public function __construct($members = array())
{
$this->_elts = array();
foreach ($members as $item) {
$this->_elts[$item] = true;
}
}
public function includes($elt)
{
return isset($this->_elts[$elt]);
}
public function add($elt)
{
$this->_elts[$elt] = true;
}
public function discard($elt)
{
unset($this->_elts[$elt]);
}
public function toArray()
{
return array_keys($this->_elts);
}
public function getIterator()
{
return new ArrayIterator($this->toArray());
}
}

View File

@ -0,0 +1,178 @@
<?php
namespace Stripe\Util;
use Stripe\StripeObject;
abstract class Util
{
private static $isMbstringAvailable = null;
private static $isHashEqualsAvailable = null;
/**
* Whether the provided array (or other) is a list rather than a dictionary.
*
* @param array|mixed $array
* @return boolean True if the given object is a list.
*/
public static function isList($array)
{
if (!is_array($array)) {
return false;
}
// TODO: generally incorrect, but it's correct given Stripe's response
foreach (array_keys($array) as $k) {
if (!is_numeric($k)) {
return false;
}
}
return true;
}
/**
* Recursively converts the PHP Stripe object to an array.
*
* @param array $values The PHP Stripe object to convert.
* @return array
*/
public static function convertStripeObjectToArray($values)
{
$results = array();
foreach ($values as $k => $v) {
// FIXME: this is an encapsulation violation
if ($k[0] == '_') {
continue;
}
if ($v instanceof StripeObject) {
$results[$k] = $v->__toArray(true);
} elseif (is_array($v)) {
$results[$k] = self::convertStripeObjectToArray($v);
} else {
$results[$k] = $v;
}
}
return $results;
}
/**
* Converts a response from the Stripe API to the corresponding PHP object.
*
* @param array $resp The response from the Stripe API.
* @param array $opts
* @return StripeObject|array
*/
public static function convertToStripeObject($resp, $opts)
{
$types = array(
'account' => 'Stripe\\Account',
'alipay_account' => 'Stripe\\AlipayAccount',
'apple_pay_domain' => 'Stripe\\ApplePayDomain',
'bank_account' => 'Stripe\\BankAccount',
'balance_transaction' => 'Stripe\\BalanceTransaction',
'card' => 'Stripe\\Card',
'charge' => 'Stripe\\Charge',
'country_spec' => 'Stripe\\CountrySpec',
'coupon' => 'Stripe\\Coupon',
'customer' => 'Stripe\\Customer',
'dispute' => 'Stripe\\Dispute',
'ephemeral_key' => 'Stripe\\EphemeralKey',
'list' => 'Stripe\\Collection',
'login_link' => 'Stripe\\LoginLink',
'invoice' => 'Stripe\\Invoice',
'invoiceitem' => 'Stripe\\InvoiceItem',
'event' => 'Stripe\\Event',
'file' => 'Stripe\\FileUpload',
'token' => 'Stripe\\Token',
'transfer' => 'Stripe\\Transfer',
'transfer_reversal' => 'Stripe\\TransferReversal',
'order' => 'Stripe\\Order',
'order_return' => 'Stripe\\OrderReturn',
'payout' => 'Stripe\\Payout',
'plan' => 'Stripe\\Plan',
'product' => 'Stripe\\Product',
'recipient' => 'Stripe\\Recipient',
'recipient_transfer' => 'Stripe\\RecipientTransfer',
'refund' => 'Stripe\\Refund',
'sku' => 'Stripe\\SKU',
'source' => 'Stripe\\Source',
'subscription' => 'Stripe\\Subscription',
'subscription_item' => 'Stripe\\SubscriptionItem',
'three_d_secure' => 'Stripe\\ThreeDSecure',
'fee_refund' => 'Stripe\\ApplicationFeeRefund',
'bitcoin_receiver' => 'Stripe\\BitcoinReceiver',
'bitcoin_transaction' => 'Stripe\\BitcoinTransaction',
);
if (self::isList($resp)) {
$mapped = array();
foreach ($resp as $i) {
array_push($mapped, self::convertToStripeObject($i, $opts));
}
return $mapped;
} elseif (is_array($resp)) {
if (isset($resp['object']) && is_string($resp['object']) && isset($types[$resp['object']])) {
$class = $types[$resp['object']];
} else {
$class = 'Stripe\\StripeObject';
}
return $class::constructFrom($resp, $opts);
} else {
return $resp;
}
}
/**
* @param string|mixed $value A string to UTF8-encode.
*
* @return string|mixed The UTF8-encoded string, or the object passed in if
* it wasn't a string.
*/
public static function utf8($value)
{
if (self::$isMbstringAvailable === null) {
self::$isMbstringAvailable = function_exists('mb_detect_encoding');
if (!self::$isMbstringAvailable) {
trigger_error("It looks like the mbstring extension is not enabled. " .
"UTF-8 strings will not properly be encoded. Ask your system " .
"administrator to enable the mbstring extension, or write to " .
"support@stripe.com if you have any questions.", E_USER_WARNING);
}
}
if (is_string($value) && self::$isMbstringAvailable && mb_detect_encoding($value, "UTF-8", true) != "UTF-8") {
return utf8_encode($value);
} else {
return $value;
}
}
/**
* Compares two strings for equality. The time taken is independent of the
* number of characters that match.
*
* @param string $a one of the strings to compare.
* @param string $b the other string to compare.
* @return bool true if the strings are equal, false otherwise.
*/
public static function secureCompare($a, $b)
{
if (self::$isHashEqualsAvailable === null) {
self::$isHashEqualsAvailable = function_exists('hash_equals');
}
if (self::$isHashEqualsAvailable) {
return hash_equals($a, $b);
} else {
if (strlen($a) != strlen($b)) {
return false;
}
$result = 0;
for ($i = 0; $i < strlen($a); $i++) {
$result |= ord($a[$i]) ^ ord($b[$i]);
}
return ($result == 0);
}
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Stripe;
abstract class Webhook
{
const DEFAULT_TOLERANCE = 300;
/**
* Returns an Event instance using the provided JSON payload. Throws a
* \UnexpectedValueException if the payload is not valid JSON, and a
* \Stripe\SignatureVerificationException if the signature verification
* fails for any reason.
*
* @param string $payload the payload sent by Stripe.
* @param string $sigHeader the contents of the signature header sent by
* Stripe.
* @param string $secret secret used to generate the signature.
* @param int $tolerance maximum difference allowed between the header's
* timestamp and the current time
* @return \Stripe\Event the Event instance
* @throws \UnexpectedValueException if the payload is not valid JSON,
* \Stripe\SignatureVerification if the verification fails.
*/
public static function constructEvent($payload, $sigHeader, $secret, $tolerance = self::DEFAULT_TOLERANCE)
{
$data = json_decode($payload, true);
$jsonError = json_last_error();
if ($data === null && $jsonError !== JSON_ERROR_NONE) {
$msg = "Invalid payload: $payload "
. "(json_last_error() was $jsonError)";
throw new \UnexpectedValueException($msg);
}
$event = Event::constructFrom($data, null);
WebhookSignature::verifyHeader($payload, $sigHeader, $secret, $tolerance);
return $event;
}
}

View File

@ -0,0 +1,132 @@
<?php
namespace Stripe;
abstract class WebhookSignature
{
const EXPECTED_SCHEME = "v1";
/**
* Verifies the signature header sent by Stripe. Throws a
* SignatureVerification exception if the verification fails for any
* reason.
*
* @param string $payload the payload sent by Stripe.
* @param string $header the contents of the signature header sent by
* Stripe.
* @param string $secret secret used to generate the signature.
* @param int $tolerance maximum difference allowed between the header's
* timestamp and the current time
* @throws SignatureVerification if the verification fails.
*/
public static function verifyHeader($payload, $header, $secret, $tolerance = null)
{
// Extract timestamp and signatures from header
$timestamp = self::getTimestamp($header);
$signatures = self::getSignatures($header, self::EXPECTED_SCHEME);
if ($timestamp == -1) {
throw new Error\SignatureVerification(
"Unable to extract timestamp and signatures from header",
$header,
$payload
);
}
if (empty($signatures)) {
throw new Error\SignatureVerification(
"No signatures found with expected scheme",
$header,
$payload
);
}
// Check if expected signature is found in list of signatures from
// header
$signedPayload = "$timestamp.$payload";
$expectedSignature = self::computeSignature($signedPayload, $secret);
$signatureFound = false;
foreach ($signatures as $signature) {
if (Util\Util::secureCompare($expectedSignature, $signature)) {
$signatureFound = true;
break;
}
}
if (!$signatureFound) {
throw new Error\SignatureVerification(
"No signatures found matching the expected signature for payload",
$header,
$payload
);
}
// Check if timestamp is within tolerance
if (($tolerance > 0) && ((time() - $timestamp) > $tolerance)) {
throw new Error\SignatureVerification(
"Timestamp outside the tolerance zone",
$header,
$payload
);
}
return true;
}
/**
* Extracts the timestamp in a signature header.
*
* @param string $header the signature header
* @return int the timestamp contained in the header, or -1 if no valid
* timestamp is found
*/
private static function getTimestamp($header)
{
$items = explode(",", $header);
foreach ($items as $item) {
$itemParts = explode("=", $item, 2);
if ($itemParts[0] == "t") {
if (!is_numeric($itemParts[1])) {
return -1;
}
return intval($itemParts[1]);
}
}
return -1;
}
/**
* Extracts the signatures matching a given scheme in a signature header.
*
* @param string $header the signature header
* @param string $scheme the signature scheme to look for.
* @return array the list of signatures matching the provided scheme.
*/
private static function getSignatures($header, $scheme)
{
$signatures = array();
$items = explode(",", $header);
foreach ($items as $item) {
$itemParts = explode("=", $item, 2);
if ($itemParts[0] == $scheme) {
array_push($signatures, $itemParts[1]);
}
}
return $signatures;
}
/**
* Computes the signature for a given payload and secret.
*
* The current scheme used by Stripe ("v1") is HMAC/SHA-256.
*
* @param string $payload the payload to sign.
* @param string $secret the secret used to generate the signature.
* @return string the signature as a string.
*/
private static function computeSignature($payload, $secret)
{
return hash_hmac("sha256", $payload, $secret);
}
}

View File

@ -0,0 +1,15 @@
<phpunit bootstrap="tests/bootstrap.no_autoload.php" colors="true">
<testsuites>
<testsuite name="Stripe PHP Test Suite">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>lib</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-clover" target="clover.xml"/>
</logging>
</phpunit>

15
files/stripe/phpunit.xml Normal file
View File

@ -0,0 +1,15 @@
<phpunit bootstrap="tests/bootstrap.php" colors="true">
<testsuites>
<testsuite name="Stripe PHP Test Suite">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>lib</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-clover" target="clover.xml"/>
</logging>
</phpunit>

View File

@ -0,0 +1,331 @@
<?php
namespace Stripe;
class AccountTest extends TestCase
{
private function managedAccountResponse($id)
{
return array(
'id' => $id,
'currencies_supported' => array('usd', 'aed', 'afn', '...'),
'object' => 'account',
'business_name' => 'Stripe.com',
'bank_accounts' => array(
'object' => 'list',
'total_count' => 0,
'has_more' => false,
'url' => '/v1/accounts/' . $id . '/bank_accounts',
'data' => array()
),
'verification' => array(
'fields_needed' => array(
'product_description',
'business_url',
'support_phone',
'bank_account',
'tos_acceptance.ip',
'tos_acceptance.date'
),
'due_by' => null,
'contacted' => false
),
'tos_acceptance' => array(
'ip' => null,
'date' => null,
'user_agent' => null
),
'legal_entity' => array(
'type' => null,
'business_name' => null,
'address' => array(
'line1' => null,
'line2' => null,
'city' => null,
'state' => null,
'postal_code' => null,
'country' => 'US'
),
'first_name' => null,
'last_name' => null,
'additional_owners' => null,
'verification' => array(
'status' => 'unverified',
'document' => null,
'details' => null
)
)
);
}
private function deletedAccountResponse($id)
{
return array(
'id' => $id,
'deleted' => true
);
}
public function testBasicRetrieve()
{
$this->mockRequest('GET', '/v1/account', array(), $this->managedAccountResponse('acct_ABC'));
$account = Account::retrieve();
$this->assertSame($account->id, 'acct_ABC');
}
public function testIDRetrieve()
{
$this->mockRequest('GET', '/v1/accounts/acct_DEF', array(), $this->managedAccountResponse('acct_DEF'));
$account = Account::retrieve('acct_DEF');
$this->assertSame($account->id, 'acct_DEF');
}
public function testCreate()
{
$this->mockRequest(
'POST',
'/v1/accounts',
array('managed' => 'true'),
$this->managedAccountResponse('acct_ABC')
);
$account = Account::create(array(
'managed' => true
));
$this->assertSame($account->id, 'acct_ABC');
}
public function testDelete()
{
$account = self::createTestAccount();
$this->mockRequest(
'DELETE',
'/v1/accounts/' . $account->id,
array(),
$this->deletedAccountResponse('acct_ABC')
);
$deleted = $account->delete();
$this->assertSame($deleted->id, $account->id);
$this->assertTrue($deleted->deleted);
}
public function testReject()
{
$account = self::createTestAccount();
$this->mockRequest(
'POST',
'/v1/accounts/' . $account->id . '/reject',
array('reason' => 'fraud'),
$this->deletedAccountResponse('acct_ABC')
);
$rejected = $account->reject(array('reason' => 'fraud'));
$this->assertSame($rejected->id, $account->id);
}
public function testSaveLegalEntity()
{
$response = $this->managedAccountResponse('acct_ABC');
$this->mockRequest('POST', '/v1/accounts', array('managed' => 'true'), $response);
$response['legal_entity']['first_name'] = 'Bob';
$this->mockRequest(
'POST',
'/v1/accounts/acct_ABC',
array('legal_entity' => array('first_name' => 'Bob')),
$response
);
$account = Account::create(array('managed' => true));
$account->legal_entity->first_name = 'Bob';
$account->save();
$this->assertSame('Bob', $account->legal_entity->first_name);
}
public function testUpdateLegalEntity()
{
$response = $this->managedAccountResponse('acct_ABC');
$this->mockRequest('POST', '/v1/accounts', array('managed' => 'true'), $response);
$response['legal_entity']['first_name'] = 'Bob';
$this->mockRequest(
'POST',
'/v1/accounts/acct_ABC',
array('legal_entity' => array('first_name' => 'Bob')),
$response
);
$account = Account::create(array('managed' => true));
$account = Account::update($account['id'], array(
'legal_entity' => array(
'first_name' => 'Bob'
)
));
$this->assertSame('Bob', $account->legal_entity->first_name);
}
public function testCreateAdditionalOwners()
{
$request = array(
'managed' => true,
'country' => 'GB',
'legal_entity' => array(
'additional_owners' => array(
0 => array(
'dob' => array(
'day' => 12,
'month' => 5,
'year' => 1970,
),
'first_name' => 'xgvukvfrde',
'last_name' => 'rtcyvubhy',
),
1 => array(
'dob' => array(
'day' => 8,
'month' => 4,
'year' => 1979,
),
'first_name' => 'yutreuk',
'last_name' => 'dfcgvhbjihmv',
),
),
),
);
$acct = Account::create($request);
$response = $acct->__toArray(true);
$req_ao = $request['legal_entity']['additional_owners'];
$resp_ao = $response['legal_entity']['additional_owners'];
$this->assertSame($req_ao[0]['dob'], $resp_ao[0]['dob']);
$this->assertSame($req_ao[1]['dob'], $resp_ao[1]['dob']);
$this->assertSame($req_ao[0]['first_name'], $resp_ao[0]['first_name']);
$this->assertSame($req_ao[1]['first_name'], $resp_ao[1]['first_name']);
}
public function testUpdateAdditionalOwners()
{
$response = $this->managedAccountResponse('acct_ABC');
$this->mockRequest('POST', '/v1/accounts', array('managed' => 'true'), $response);
$response['legal_entity']['additional_owners'] = array(array(
'first_name' => 'Bob',
'last_name' => null,
'address' => array(
'line1' => null,
'line2' => null,
'city' => null,
'state' => null,
'postal_code' => null,
'country' => null
),
'verification' => array(
'status' => 'unverified',
'document' => null,
'details' => null
)
));
$this->mockRequest(
'POST',
'/v1/accounts/acct_ABC',
array('legal_entity' => array('additional_owners' => array(array('first_name' => 'Bob')))),
$response
);
$response['legal_entity']['additional_owners'][0]['last_name'] = 'Smith';
$this->mockRequest(
'POST',
'/v1/accounts/acct_ABC',
array('legal_entity' => array('additional_owners' => array(array('last_name' => 'Smith')))),
$response
);
$response['legal_entity']['additional_owners'][0]['last_name'] = 'Johnson';
$this->mockRequest(
'POST',
'/v1/accounts/acct_ABC',
array('legal_entity' => array('additional_owners' => array(array('last_name' => 'Johnson')))),
$response
);
$response['legal_entity']['additional_owners'][0]['verification']['document'] = 'file_123';
$this->mockRequest(
'POST',
'/v1/accounts/acct_ABC',
array('legal_entity' => array('additional_owners' => array(array('verification' => array('document' => 'file_123'))))),
$response
);
$response['legal_entity']['additional_owners'][1] = array(
'first_name' => 'Jane',
'last_name' => 'Doe'
);
$this->mockRequest(
'POST',
'/v1/accounts/acct_ABC',
array('legal_entity' => array('additional_owners' => array(1 => array('first_name' => 'Jane')))),
$response
);
$account = Account::create(array('managed' => true));
$account->legal_entity->additional_owners = array(array('first_name' => 'Bob'));
$account->save();
$this->assertSame(1, count($account->legal_entity->additional_owners));
$this->assertSame('Bob', $account->legal_entity->additional_owners[0]->first_name);
$account->legal_entity->additional_owners[0]->last_name = 'Smith';
$account->save();
$this->assertSame(1, count($account->legal_entity->additional_owners));
$this->assertSame('Smith', $account->legal_entity->additional_owners[0]->last_name);
$account['legal_entity']['additional_owners'][0]['last_name'] = 'Johnson';
$account->save();
$this->assertSame(1, count($account->legal_entity->additional_owners));
$this->assertSame('Johnson', $account->legal_entity->additional_owners[0]->last_name);
$account->legal_entity->additional_owners[0]->verification->document = 'file_123';
$account->save();
$this->assertSame('file_123', $account->legal_entity->additional_owners[0]->verification->document);
$account->legal_entity->additional_owners[1] = array('first_name' => 'Jane');
$account->save();
$this->assertSame(2, count($account->legal_entity->additional_owners));
$this->assertSame('Jane', $account->legal_entity->additional_owners[1]->first_name);
}
public function testLoginLinkCreation()
{
$accountId = 'acct_EXPRESS';
$mockExpress = array(
'id' => $accountId,
'object' => 'account',
'login_links' => array(
'object' => 'list',
'data' => array(),
'has_more' => false,
'url' => "/v1/accounts/$accountId/login_links"
)
);
$this->mockRequest('GET', "/v1/accounts/$accountId", array(), $mockExpress);
$mockLoginLink = array(
'object' => 'login_link',
'created' => 1493820886,
'url' => "https://connect.stripe.com/$accountId/AAAAAAAA"
);
$this->mockRequest('POST', "/v1/accounts/$accountId/login_links", array(), $mockLoginLink);
$account = Account::retrieve($accountId);
$loginLink = $account->login_links->create();
$this->assertSame('login_link', $loginLink->object);
$this->assertSame('Stripe\LoginLink', get_class($loginLink));
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace Stripe;
use Stripe\HttpClient\CurlClient;
class ApiRequestorTest extends TestCase
{
public function testEncodeObjects()
{
$reflector = new \ReflectionClass('Stripe\\ApiRequestor');
$method = $reflector->getMethod('_encodeObjects');
$method->setAccessible(true);
$a = array('customer' => new Customer('abcd'));
$enc = $method->invoke(null, $a);
$this->assertSame($enc, array('customer' => 'abcd'));
// Preserves UTF-8
$v = array('customer' => "");
$enc = $method->invoke(null, $v);
$this->assertSame($enc, $v);
// Encodes latin-1 -> UTF-8
$v = array('customer' => "\xe9");
$enc = $method->invoke(null, $v);
$this->assertSame($enc, array('customer' => "\xc3\xa9"));
}
public function testHttpClientInjection()
{
$reflector = new \ReflectionClass('Stripe\\ApiRequestor');
$method = $reflector->getMethod('httpClient');
$method->setAccessible(true);
$curl = new CurlClient();
$curl->setTimeout(10);
ApiRequestor::setHttpClient($curl);
$injectedCurl = $method->invoke(new ApiRequestor());
$this->assertSame($injectedCurl, $curl);
}
public function testDefaultHeaders()
{
$reflector = new \ReflectionClass('Stripe\\ApiRequestor');
$method = $reflector->getMethod('_defaultHeaders');
$method->setAccessible(true);
// no way to stub static methods with PHPUnit 4.x :(
Stripe::setAppInfo('MyTestApp', '1.2.34', 'https://mytestapp.example');
$apiKey = 'sk_test_notarealkey';
$clientInfo = array('httplib' => 'testlib 0.1.2');
$headers = $method->invoke(null, $apiKey, $clientInfo);
$ua = json_decode($headers['X-Stripe-Client-User-Agent']);
$this->assertSame($ua->application->name, 'MyTestApp');
$this->assertSame($ua->application->version, '1.2.34');
$this->assertSame($ua->application->url, 'https://mytestapp.example');
$this->assertSame($ua->httplib, 'testlib 0.1.2');
$this->assertSame(
$headers['User-Agent'],
'Stripe/v1 PhpBindings/' . Stripe::VERSION . ' MyTestApp/1.2.34 (https://mytestapp.example)'
);
$this->assertSame($headers['Authorization'], 'Bearer ' . $apiKey);
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace Stripe;
class ApplePayDomainTest extends TestCase
{
public function testCreation()
{
$this->mockRequest(
'POST',
'/v1/apple_pay/domains',
array('domain_name' => 'test.com'),
array(
'id' => 'apwc_create',
'object' => 'apple_pay_domain'
)
);
$d = ApplePayDomain::create(array(
'domain_name' => 'test.com'
));
$this->assertSame('apwc_create', $d->id);
$this->assertInstanceOf('Stripe\\ApplePayDomain', $d);
}
public function testRetrieve()
{
$this->mockRequest(
'GET',
'/v1/apple_pay/domains/apwc_retrieve',
array(),
array(
'id' => 'apwc_retrieve',
'object' => 'apple_pay_domain'
)
);
$d = ApplePayDomain::retrieve('apwc_retrieve');
$this->assertSame('apwc_retrieve', $d->id);
$this->assertInstanceOf('Stripe\\ApplePayDomain', $d);
}
public function testDeletion()
{
self::authorizeFromEnv();
$d = ApplePayDomain::create(array(
'domain_name' => 'jackshack.website'
));
$this->assertInstanceOf('Stripe\\ApplePayDomain', $d);
$this->mockRequest(
'DELETE',
'/v1/apple_pay/domains/' . $d->id,
array(),
array('deleted' => true)
);
$d->delete();
$this->assertTrue($d->deleted);
}
public function testList()
{
$this->mockRequest(
'GET',
'/v1/apple_pay/domains',
array(),
array(
'url' => '/v1/apple_pay/domains',
'object' => 'list'
)
);
$all = ApplePayDomain::all();
$this->assertSame($all->url, '/v1/apple_pay/domains');
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Stripe;
class ApplicationFeeRefundTest extends TestCase
{
public function testUrls()
{
$refund = new ApplicationFeeRefund();
$refund->id = 'refund_id';
$refund->fee = 'fee_id';
$this->assertSame(
$refund->instanceUrl(),
'/v1/application_fees/fee_id/refunds/refund_id'
);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Stripe;
class ApplicationFeeTest extends TestCase
{
public function testUrls()
{
$applicationFee = new ApplicationFee('abcd/efgh');
$this->assertSame(
$applicationFee->instanceUrl(),
'/v1/application_fees/abcd%2Fefgh'
);
}
public function testList()
{
self::authorizeFromEnv();
$d = ApplicationFee::all();
$this->assertSame($d->url, '/v1/application_fees');
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Stripe;
class AttachedObjectTest extends TestCase
{
public function testCount()
{
$ao = new AttachedObject();
$this->assertSame(0, count($ao));
$ao['key1'] = 'value1';
$this->assertSame(1, count($ao));
$ao['key2'] = 'value2';
$this->assertSame(2, count($ao));
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Stripe;
class AuthenticationErrorTest extends TestCase
{
public function testInvalidCredentials()
{
Stripe::setApiKey('invalid');
try {
Customer::create();
} catch (Error\Authentication $e) {
$this->assertSame(401, $e->getHttpStatus());
}
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Stripe;
class BalanceTest extends TestCase
{
public function testRetrieve()
{
self::authorizeFromEnv();
$d = Balance::retrieve();
$this->assertSame($d->object, "balance");
$this->assertTrue(Util\Util::isList($d->available));
$this->assertTrue(Util\Util::isList($d->pending));
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Stripe;
class BalanceTransactionTest extends TestCase
{
public function testList()
{
self::authorizeFromEnv();
$d = BalanceTransaction::all();
$this->assertSame($d->url, '/v1/balance/history');
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Stripe;
class BankAccountTest extends TestCase
{
public function testVerify()
{
self::authorizeFromEnv();
$customer = self::createTestCustomer();
$bankAccount = $customer->sources->create(array(
'source' => array(
'object' => 'bank_account',
'account_holder_type' => 'individual',
'account_number' => '000123456789',
'account_holder_name' => 'John Doe',
'routing_number' => '110000000',
'country' => 'US'
)
));
$this->assertSame($bankAccount->status, 'new');
$bankAccount = $bankAccount->verify(array(
'amounts' => array(32, 45)
));
$this->assertSame($bankAccount->status, 'verified');
}
}

View File

@ -0,0 +1,120 @@
<?php
namespace Stripe;
class BitcoinReceiverTest extends TestCase
{
public function testUrls()
{
$classUrl = BitcoinReceiver::classUrl('Stripe_BitcoinReceiver');
$this->assertSame($classUrl, '/v1/bitcoin/receivers');
$receiver = new BitcoinReceiver('abcd/efgh');
$instanceUrl = $receiver->instanceUrl();
$this->assertSame($instanceUrl, '/v1/bitcoin/receivers/abcd%2Fefgh');
}
public function testCreate()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$this->assertSame(100, $receiver->amount);
$this->assertNotNull($receiver->id);
}
public function testRetrieve()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$r = BitcoinReceiver::retrieve($receiver->id);
$this->assertSame($receiver->id, $r->id);
$this->assertInstanceOf('Stripe\\BitcoinTransaction', $r->transactions->data[0]);
}
public function testList()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$receivers = BitcoinReceiver::all();
$this->assertGreaterThan(0, count($receivers->data));
}
public function testListTransactions()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$this->assertSame(0, count($receiver->transactions->data));
$transactions = $receiver->transactions->all(array("limit" => 1));
$this->assertSame(1, count($transactions->data));
}
public function testDeleteWithCustomer()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$customer = Customer::create(array("source" => $receiver->id));
$charge = Charge::create(array(
"customer" => $customer->id,
"amount" => $receiver->amount,
"currency" => $receiver->currency
));
$receiver = BitcoinReceiver::retrieve($receiver->id);
$response = $receiver->delete();
$this->assertTrue($response->deleted);
}
public function testUpdateWithCustomer()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$customer = Customer::create(array("source" => $receiver->id));
$receiver = BitcoinReceiver::retrieve($receiver->id);
$receiver->description = "a new description";
$receiver->save();
$base = Customer::classUrl();
$parentExtn = $receiver['customer'];
$extn = $receiver['id'];
$this->assertEquals("$base/$parentExtn/sources/$extn", $receiver->instanceUrl());
$updatedReceiver = BitcoinReceiver::retrieve($receiver->id);
$this->assertEquals($receiver["description"], $updatedReceiver["description"]);
}
public function testUpdateWithoutCustomer()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$receiver->description = "a new description";
$receiver->save();
$this->assertEquals(BitcoinReceiver::classUrl() . "/" . $receiver['id'], $receiver->instanceUrl());
$updatedReceiver = BitcoinReceiver::retrieve($receiver->id);
$this->assertEquals($receiver["description"], $updatedReceiver["description"]);
}
public function testRefund()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$receiver = BitcoinReceiver::retrieve($receiver->id);
$this->assertNull($receiver->refund_address);
$refundAddress = "REFUNDHERE";
$receiver->refund(array("refund_address" => $refundAddress));
$this->assertSame($refundAddress, $receiver->refund_address);
}
}

Some files were not shown because too many files have changed in this diff Show More