Merge branch 'master' into blender-tweaks

Conflicts:
	resources/celerity/map.php
	src/applications/home/controller/PhabricatorHomeMainController.php
	src/applications/maniphest/controller/ManiphestTaskEditController.php
	src/applications/maniphest/query/ManiphestTaskQuery.php
	src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
This commit is contained in:
2014-07-17 01:33:33 +06:00
1591 changed files with 23233 additions and 15178 deletions

View File

@@ -1,7 +1,8 @@
{
"exclude": [
"(^externals/)",
"(\\.lint-test$)"
"(^webroot/rsrc/externals/)",
"(/__tests__/data/)"
],
"linters": {
"chmod": {
@@ -10,26 +11,30 @@
"filename": {
"type": "filename"
},
"generated": {
"type": "generated"
},
"javelin": {
"type": "javelin",
"include": "(\\.js$)",
"exclude": [
"(^externals/JsShrink/)",
"(^support/aphlict/)",
"(^webroot/rsrc/externals/raphael/)"
"(^support/aphlict/)"
]
},
"jshint": {
"type": "jshint",
"include": "(\\.js$)",
"exclude": [
"(^externals/JsShrink/)",
"(^webroot/rsrc/externals/raphael/)"
],
"flags": ["--config=support/jshint/jshintconfig"]
"jshint.jshintrc": "support/lint/jshintrc"
},
"generated": {
"type": "generated"
"json": {
"type": "json",
"include": [
"(^src/docs/book/.*\\.book$)",
"(^support/lint/jshintrc$)",
"(^\\.arcconfig$)",
"(^\\.arclint$)",
"(\\.json$)"
]
},
"merge-conflict": {
"type": "merge-conflict"
@@ -37,6 +42,10 @@
"nolint": {
"type": "nolint"
},
"phutil-library": {
"type": "phutil-library",
"include": "(\\.php$)"
},
"phutil-xhpast": {
"type": "phutil-xhpast",
"include": "(\\.php$)",
@@ -44,9 +53,8 @@
"phutil_escape_html": "The phutil_escape_html() function is deprecated. Raw strings passed to phutil_tag() or hsprintf() are escaped automatically."
}
},
"phutil-library": {
"type": "phutil-library",
"include": "(\\.php$)"
"spelling": {
"type": "spelling"
},
"text": {
"type": "text",
@@ -63,20 +71,16 @@
"(^\\.arclint)"
]
},
"spelling": {
"type": "spelling"
},
"xhpast": {
"type": "xhpast",
"include": "(\\.php$)",
"severity": {
"16": "advice",
"29": "warning",
"31": "error",
"34": "error",
"35": "error"
"34": "error"
},
"xhpast.naminghook": "PhabricatorSymbolNameLinter"
"xhpast.naminghook": "PhabricatorSymbolNameLinter",
"xhpast.php-version": "5.2.3",
"xhpast.php-version.windows": "5.3.0"
}
}
}

19
.gitignore vendored
View File

@@ -1,22 +1,9 @@
.DS_Store
._*
.#*
*#
*~
*.swp
# NetBeans project files
/nbproject/
# PhpStorm project files
.idea/
# Arcanist scratch directory
/.arc
# NOTE: Thinking about adding files created by your operating system, IDE,
# or text editor here? Don't! Add them to your per-user .gitignore instead.
# Diviner
/docs/
/.divinercache
/.divinercache/
# libphutil
/src/.phutil_module_cache

22
NOTICE
View File

@@ -1,7 +1,21 @@
Phabricator
Copyright 2013 Facebook, Inc.
Copyright 2014 Phacility, Inc.
This product includes software developed at
Facebook, Inc. (http://www.facebook.com/facebook).
This software is primarily developed and maintained by Phacility, Inc.
Libraries in externals/ have their own licenses and copyright holders.
http://www.phacility.com/
Portions of this software were developed by various contributors, who retain
copyright on their work. These works are licensed to Phacility, Inc.
Phabricator is available under the Apache 2.0 license. See LICENSE for more
information.
Phabricator and Phacility are trademarks of Phacility, Inc. For additional
information about trademarks that pertain to this software, see:
http://www.phacility.com/trademarks/
This software uses other open source libraries, which are located in
"externals/" and "webroot/rsrc/externals/". These libraries have their own
licenses and copyright holders.

11
README
View File

@@ -11,13 +11,10 @@ Phabricator includes applications for:
- also some other things.
You can learn more about the project (and find links to documentation and
resources) here:
resources) [[http://phabricator.org/ | here]].
http://phabricator.org/
Phabricator is developed and maintained by Phacility. The first version of
Phabricator was originally built at Facebook.
LICENSE
Phabricator is developed and maintained by [[http://phacility.com/ |
Phacility]]. The first version of Phabricator was originally built at Facebook.
= LICENSE =
Phabricator is released under the Apache 2.0 license except as otherwise noted.

View File

@@ -808,7 +808,7 @@ return array(
// '#/autobuilt/#',
),
// If you set this to true, users can accept their own revisions. This action
// If you set this to true, users can accept their own revisions. This action
// is disabled by default because it's most likely not a behavior you want,
// but it proves useful if you are working alone on a project and want to make
// use of all of differential's features.
@@ -827,7 +827,7 @@ return array(
// If you set this to true, any user can reopen a revision so long as it has
// been closed. This can be useful if a revision is accidentally closed or
// if a developer changes his or her mind after closing a revision. If it is
// if a developer changes his or her mind after closing a revision. If it is
// false, reopening is not allowed.
'differential.allow-reopen' => false,

View File

@@ -13,7 +13,11 @@ function jsShrink($input) {
(?:
(^|[-+\([{}=,:;!%^&*|?~]|/(?![/*])|return|throw) # context before regexp
(?:\s|//[^\n]*+\n|/\*(?:[^*]|\*(?!/))*+\*/)* # optional space
(/(?![/*])(?:\\\\[^\n]|[^[\n/\\\\]|\[(?:\\\\[^\n]|[^]])++)+/) # regexp
(/(?![/*])(?:
\\\\[^\n]
|[^[\n/\\\\]++
|\[(?:\\\\[^\n]|[^]])++
)+/) # regexp
|(^
|\'(?:\\\\.|[^\n\'\\\\])*\'
|"(?:\\\\.|[^\n"\\\\])*"

View File

@@ -27,8 +27,6 @@ use Balanced\Card;
* <li>$BALANCED_URL_ROOT If set applies to \Balanced\Settings::$url_root.
* <li>$BALANCED_API_KEY If set applies to \Balanced\Settings::$api_key.
* </ul>
*
* @group suite
*/
class SuiteTest extends \PHPUnit_Framework_TestCase
{

View File

@@ -102,7 +102,7 @@ class MimeMailParser_attachment {
/**
* Retrieve the file content in one go
* Once you retreive the content you cannot use MimeMailParser_attachment::read()
* Once you retrieve the content you cannot use MimeMailParser_attachment::read()
* @return String
*/
public function getContent() {

17
externals/stripe-php/.travis.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
language: php
php:
- 5.2
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
before_script:
- sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.2' ]; then wget http://iweb.dl.sourceforge.net/project/simpletest/simpletest/simpletest_1.1/simpletest_1.1.0.tar.gz; tar xf simpletest_1.1.0.tar.gz -C test; else composer install --dev --prefer-source; fi"
- sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.6' ]; then pear install pear/PHP_CodeSniffer; phpenv rehash; fi"
script:
- sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.6' ]; then phpcs --standard=zend --encoding=UTF-8 --ignore=vendor -p ./; fi"
- php test/Stripe.php

156
externals/stripe-php/CHANGELOG vendored Normal file
View File

@@ -0,0 +1,156 @@
=== 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

View File

@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010 Stripe
Copyright (c) 2010-2014 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

View File

@@ -1,13 +1,49 @@
= Installation
= Stripe PHP bindings
{<img src="https://travis-ci.org/stripe/stripe-php.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/stripe/stripe-php]
{<img src="https://poser.pugx.org/stripe/stripe-php/v/stable.svg" alt="Latest Stable Version" />}[https://packagist.org/packages/stripe/stripe-php]
{<img src="https://poser.pugx.org/stripe/stripe-php/downloads.svg" alt="Total Downloads" />}[https://packagist.org/packages/stripe/stripe-php]
{<img src="https://poser.pugx.org/stripe/stripe-php/license.svg" alt="License" />}[https://packagist.org/packages/stripe/stripe-php]
You can sign up for a Stripe account at https://stripe.com.
== Requirements
PHP 5.2 and later.
== Composer
You can install the bindings via Composer[http://getcomposer.org/]. Add this to your +composer.json+:
{
"require": {
"stripe/stripe-php": "1.*"
}
}
Then install via:
composer.phar install
To use the bindings, either user Composer's autoload[https://getcomposer.org/doc/00-intro.md#autoloading]:
require_once('vendor/autoload.php');
Or manually:
require_once('/path/to/vendor/stripe/stripe-php/lib/Stripe.php');
== Manual Installation
Obtain the latest version of the Stripe PHP bindings with:
git clone https://github.com/stripe/stripe-php
To get started, add the following to your PHP script:
To use the bindings, add the following to your PHP script:
require_once("/path/to/stripe-php/lib/Stripe.php");
== Getting Started
Simple usage looks like:
Stripe::setApiKey('d8e8fca2dc0f896fd7cb4cb0031ba249');
@@ -15,6 +51,17 @@ Simple usage looks like:
$charge = Stripe_Charge::create(array('card' => $myCard, 'amount' => 2000, 'currency' => 'usd'));
echo $charge;
= Documentation
== Documentation
Please see https://stripe.com/api for up-to-date documentation.
== Tests
In order to run tests you have to install SimpleTest[http://packagist.org/packages/simpletest/simpletest] via Composer[http://getcomposer.org/] (recommended way):
composer.phar update --dev
Run test suite:
php ./test/Stripe.php

View File

@@ -1 +1 @@
1.6.3
1.16.0

29
externals/stripe-php/composer.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"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.2",
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*"
},
"require-dev": {
"simpletest/simpletest": "*"
},
"autoload": {
"classmap": ["lib/Stripe/"]
}
}

View File

@@ -9,34 +9,12 @@ if (!function_exists('curl_init')) {
if (!function_exists('json_decode')) {
throw new Exception('Stripe needs the JSON PHP extension.');
}
abstract class Stripe
{
public static $apiKey;
public static $apiBase = 'https://api.stripe.com/v1';
public static $verifySslCerts = true;
const VERSION = '1.6.3';
public static function getApiKey()
{
return self::$apiKey;
}
public static function setApiKey($apiKey)
{
self::$apiKey = $apiKey;
}
public static function getVerifySslCerts() {
return self::$verifySslCerts;
}
public static function setVerifySslCerts($verify) {
self::$verifySslCerts = $verify;
}
if (!function_exists('mb_detect_encoding')) {
throw new Exception('Stripe needs the Multibyte String PHP extension.');
}
// Stripe singleton
require(dirname(__FILE__) . '/Stripe/Stripe.php');
// Utilities
require(dirname(__FILE__) . '/Stripe/Util.php');
@@ -49,18 +27,31 @@ require(dirname(__FILE__) . '/Stripe/ApiConnectionError.php');
require(dirname(__FILE__) . '/Stripe/AuthenticationError.php');
require(dirname(__FILE__) . '/Stripe/CardError.php');
require(dirname(__FILE__) . '/Stripe/InvalidRequestError.php');
require(dirname(__FILE__) . '/Stripe/RateLimitError.php');
// Plumbing
require(dirname(__FILE__) . '/Stripe/Object.php');
require(dirname(__FILE__) . '/Stripe/ApiRequestor.php');
require(dirname(__FILE__) . '/Stripe/ApiResource.php');
require(dirname(__FILE__) . '/Stripe/SingletonApiResource.php');
require(dirname(__FILE__) . '/Stripe/AttachedObject.php');
require(dirname(__FILE__) . '/Stripe/List.php');
// Stripe API Resources
require(dirname(__FILE__) . '/Stripe/Account.php');
require(dirname(__FILE__) . '/Stripe/Card.php');
require(dirname(__FILE__) . '/Stripe/Balance.php');
require(dirname(__FILE__) . '/Stripe/BalanceTransaction.php');
require(dirname(__FILE__) . '/Stripe/Charge.php');
require(dirname(__FILE__) . '/Stripe/Customer.php');
require(dirname(__FILE__) . '/Stripe/Invoice.php');
require(dirname(__FILE__) . '/Stripe/InvoiceItem.php');
require(dirname(__FILE__) . '/Stripe/Plan.php');
require(dirname(__FILE__) . '/Stripe/Subscription.php');
require(dirname(__FILE__) . '/Stripe/Token.php');
require(dirname(__FILE__) . '/Stripe/Coupon.php');
require(dirname(__FILE__) . '/Stripe/Event.php');
require(dirname(__FILE__) . '/Stripe/Transfer.php');
require(dirname(__FILE__) . '/Stripe/Recipient.php');
require(dirname(__FILE__) . '/Stripe/Refund.php');
require(dirname(__FILE__) . '/Stripe/ApplicationFee.php');

View File

@@ -0,0 +1,15 @@
<?php
class Stripe_Account extends Stripe_SingletonApiResource
{
/**
* @param string|null $apiKey
*
* @return Stripe_Account
*/
public static function retrieve($apiKey=null)
{
$class = get_class();
return self::_scopedSingletonRetrieve($class, $apiKey);
}
}

View File

@@ -2,31 +2,57 @@
class Stripe_ApiRequestor
{
/**
* @var string $apiKey The API key that's to be used to make requests.
*/
public $apiKey;
private static $_preFlight;
private static function blacklistedCerts()
{
return array(
'05c0b3643694470a888c6e7feb5c9e24e823dc53',
'5b7dc7fbc98d78bf76d4d4fa6f597a0c901fad5c',
);
}
public function __construct($apiKey=null)
{
$this->_apiKey = $apiKey;
}
/**
* @param string $url The path to the API endpoint.
*
* @returns string The full path.
*/
public static function apiUrl($url='')
{
$apiBase = Stripe::$apiBase;
return "$apiBase$url";
}
/**
* @param string|mixed $value A string to UTF8-encode.
*
* @returns string|mixed The UTF8-encoded string, or the object passed in if
* it wasn't a string.
*/
public static function utf8($value)
{
if (is_string($value))
if (is_string($value)
&& mb_detect_encoding($value, "UTF-8", TRUE) != "UTF-8") {
return utf8_encode($value);
else
} else {
return $value;
}
}
private static function _encodeObjects($d)
{
if ($d instanceof Stripe_ApiRequestor) {
return $d->id;
if ($d instanceof Stripe_ApiResource) {
return self::utf8($d->id);
} else if ($d === true) {
return 'true';
} else if ($d === false) {
@@ -34,70 +60,142 @@ class Stripe_ApiRequestor
} else if (is_array($d)) {
$res = array();
foreach ($d as $k => $v)
$res[$k] = self::_encodeObjects($v);
$res[$k] = self::_encodeObjects($v);
return $res;
} else {
return $d;
return self::utf8($d);
}
}
public static function encode($d)
/**
* @param array $arr An map of param keys to values.
* @param string|null $prefix (It doesn't look like we ever use $prefix...)
*
* @returns string A querystring, essentially.
*/
public static function encode($arr, $prefix=null)
{
return http_build_query($d, null, '&');
if (!is_array($arr))
return $arr;
$r = array();
foreach ($arr as $k => $v) {
if (is_null($v))
continue;
if ($prefix && $k && !is_int($k))
$k = $prefix."[".$k."]";
else if ($prefix)
$k = $prefix."[]";
if (is_array($v)) {
$r[] = self::encode($v, $k, true);
} else {
$r[] = urlencode($k)."=".urlencode($v);
}
}
return implode("&", $r);
}
public function request($meth, $url, $params=null)
/**
* @param string $method
* @param string $url
* @param array|null $params
*
* @return array An array whose first element is the response and second
* element is the API key used to make the request.
*/
public function request($method, $url, $params=null)
{
if (!$params)
$params = array();
list($rbody, $rcode, $myApiKey) = $this->_requestRaw($meth, $url, $params);
list($rbody, $rcode, $myApiKey) =
$this->_requestRaw($method, $url, $params);
$resp = $this->_interpretResponse($rbody, $rcode);
return array($resp, $myApiKey);
}
/**
* @param string $rbody A JSON string.
* @param int $rcode
* @param array $resp
*
* @throws Stripe_InvalidRequestError if the error is caused by the user.
* @throws Stripe_AuthenticationError if the error is caused by a lack of
* permissions.
* @throws Stripe_CardError if the error is the error code is 402 (payment
* required)
* @throws Stripe_ApiError otherwise.
*/
public function handleApiError($rbody, $rcode, $resp)
{
if (!is_array($resp) || !isset($resp['error']))
throw new Stripe_ApiError("Invalid response object from API: $rbody (HTTP response code was $rcode)", $rcode, $rbody, $resp);
if (!is_array($resp) || !isset($resp['error'])) {
$msg = "Invalid response object from API: $rbody "
."(HTTP response code was $rcode)";
throw new Stripe_ApiError($msg, $rcode, $rbody, $resp);
}
$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:
if ($code == 'rate_limit') {
throw new Stripe_RateLimitError(
$msg, $param, $rcode, $rbody, $resp
);
}
case 404:
throw new Stripe_InvalidRequestError(isset($error['message']) ? $error['message'] : null,
isset($error['param']) ? $error['param'] : null,
$rcode, $rbody, $resp);
throw new Stripe_InvalidRequestError(
$msg, $param, $rcode, $rbody, $resp
);
case 401:
throw new Stripe_AuthenticationError(isset($error['message']) ? $error['message'] : null, $rcode, $rbody, $resp);
throw new Stripe_AuthenticationError($msg, $rcode, $rbody, $resp);
case 402:
throw new Stripe_CardError(isset($error['message']) ? $error['message'] : null,
isset($error['param']) ? $error['param'] : null,
isset($error['code']) ? $error['code'] : null,
$rcode, $rbody, $resp);
throw new Stripe_CardError($msg, $param, $code, $rcode, $rbody, $resp);
default:
throw new Stripe_ApiError(isset($error['message']) ? $error['message'] : null, $rcode, $rbody, $resp);
throw new Stripe_ApiError($msg, $rcode, $rbody, $resp);
}
}
private function _requestRaw($meth, $url, $params)
private function _requestRaw($method, $url, $params)
{
$myApiKey = $this->_apiKey;
if (!$myApiKey)
$myApiKey = Stripe::$apiKey;
if (!$myApiKey)
throw new Stripe_AuthenticationError('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.');
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 Stripe_AuthenticationError($msg);
}
$absUrl = $this->apiUrl($url);
$params = self::_encodeObjects($params);
$langVersion = phpversion();
$uname = php_uname();
$ua = array('bindings_version' => Stripe::VERSION,
'lang' => 'php',
'lang_version' => $langVersion,
'publisher' => 'stripe',
'uname' => $uname);
'lang' => 'php',
'lang_version' => $langVersion,
'publisher' => 'stripe',
'uname' => $uname);
$headers = array('X-Stripe-Client-User-Agent: ' . json_encode($ua),
'User-Agent: Stripe/v1 PhpBindings/' . Stripe::VERSION);
list($rbody, $rcode) = $this->_curlRequest($meth, $absUrl, $headers, $params, $myApiKey);
'User-Agent: Stripe/v1 PhpBindings/' . Stripe::VERSION,
'Authorization: Bearer ' . $myApiKey);
if (Stripe::$apiVersion)
$headers[] = 'Stripe-Version: ' . Stripe::$apiVersion;
list($rbody, $rcode) = $this->_curlRequest(
$method,
$absUrl,
$headers,
$params
);
return array($rbody, $rcode, $myApiKey);
}
@@ -106,7 +204,9 @@ class Stripe_ApiRequestor
try {
$resp = json_decode($rbody, true);
} catch (Exception $e) {
throw new Stripe_ApiError("Invalid response body from API: $rbody (HTTP response code was $rcode)", $rcode, $rbody);
$msg = "Invalid response body from API: $rbody "
. "(HTTP response code was $rcode)";
throw new Stripe_ApiError($msg, $rcode, $rbody);
}
if ($rcode < 200 || $rcode >= 300) {
@@ -115,28 +215,33 @@ class Stripe_ApiRequestor
return $resp;
}
private function _curlRequest($meth, $absUrl, $headers, $params, $myApiKey)
private function _curlRequest($method, $absUrl, $headers, $params)
{
if (!self::$_preFlight) {
self::$_preFlight = $this->checkSslCert($this->apiUrl());
}
$curl = curl_init();
$meth = strtolower($meth);
$method = strtolower($method);
$opts = array();
if ($meth == 'get') {
if ($method == 'get') {
$opts[CURLOPT_HTTPGET] = 1;
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} else if ($meth == 'post') {
} else if ($method == 'post') {
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = self::encode($params);
} else if ($meth == 'delete') {
} else if ($method == 'delete') {
$opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} else {
throw new Stripe_ApiError("Unrecognized method $meth");
throw new Stripe_ApiError("Unrecognized method $method");
}
$absUrl = self::utf8($absUrl);
@@ -146,19 +251,27 @@ class Stripe_ApiRequestor
$opts[CURLOPT_TIMEOUT] = 80;
$opts[CURLOPT_RETURNTRANSFER] = true;
$opts[CURLOPT_HTTPHEADER] = $headers;
$opts[CURLOPT_USERPWD] = $myApiKey . ':';
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) {
array_push($headers, 'X-Stripe-Client-Info: {"ca":"using Stripe-supplied CA bundle"}');
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 = $this->caBundle();
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_CAINFO,
dirname(__FILE__) . '/../data/ca-certificates.crt');
curl_setopt($curl, CURLOPT_CAINFO, $cert);
$rbody = curl_exec($curl);
}
@@ -174,6 +287,11 @@ class Stripe_ApiRequestor
return array($rbody, $rcode);
}
/**
* @param number $errno
* @param string $message
* @throws Stripe_ApiConnectionError
*/
public function handleCurlError($errno, $message)
{
$apiBase = Stripe::$apiBase;
@@ -181,17 +299,119 @@ class Stripe_ApiRequestor
case CURLE_COULDNT_CONNECT:
case CURLE_COULDNT_RESOLVE_HOST:
case CURLE_OPERATION_TIMEOUTED:
$msg = "Could not connect to Stripe ($apiBase). 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 let us know at support@stripe.com.";
break;
$msg = "Could not connect to Stripe ($apiBase). 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 $apiBase in your browser.) If this problem persists, let us know at support@stripe.com.";
break;
$msg = "Could not verify Stripe's SSL certificate. Please make sure "
. "that your network is not intercepting certificates. "
. "(Try going to $apiBase in your browser.) "
. "If this problem persists,";
break;
default:
$msg = "Unexpected error communicating with Stripe. If this problem persists, let us know at support@stripe.com.";
$msg = "Unexpected error communicating with Stripe. "
. "If this problem persists,";
}
$msg .= " let us know at support@stripe.com.";
$msg .= "\n\n(Network error: $message)";
$msg .= "\n\n(Network error [errno $errno]: $message)";
throw new Stripe_ApiConnectionError($msg);
}
/**
* Preflight the SSL certificate presented by the backend. This isn't 100%
* bulletproof, in that we're not actually validating the transport used to
* communicate with Stripe, merely that the first attempt to does not use a
* revoked certificate.
*
* Unfortunately the interface to OpenSSL doesn't make it easy to check the
* certificate before sending potentially sensitive data on the wire. This
* approach raises the bar for an attacker significantly.
*/
private function checkSslCert($url)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
error_log(
'Warning: This version of PHP is too old to check SSL certificates '.
'correctly. Stripe cannot guarantee that the server has a '.
'certificate which is not blacklisted'
);
return true;
}
if (strpos(PHP_VERSION, 'hiphop') !== false) {
error_log(
'Warning: HHVM does not support Stripe\'s SSL certificate '.
'verification. (See http://docs.hhvm.com/manual/en/context.ssl.php) '.
'Stripe cannot guarantee that the server has a certificate which is '.
'not blacklisted'
);
return true;
}
$url = parse_url($url);
$port = isset($url["port"]) ? $url["port"] : 443;
$url = "ssl://{$url["host"]}:{$port}";
$sslContext = stream_context_create(
array('ssl' => array(
'capture_peer_cert' => true,
'verify_peer' => true,
'cafile' => $this->caBundle(),
))
);
$result = stream_socket_client(
$url, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $sslContext
);
if ($errno !== 0) {
$apiBase = Stripe::$apiBase;
throw new Stripe_ApiConnectionError(
'Could not connect to Stripe (' . $apiBase . '). Please check your '.
'internet connection and try again. If this problem persists, '.
'you should check Stripe\'s service status at '.
'https://twitter.com/stripestatus. Reason was: '.$errstr
);
}
$params = stream_context_get_params($result);
$cert = $params['options']['ssl']['peer_certificate'];
openssl_x509_export($cert, $pemCert);
if (self::isBlackListed($pemCert)) {
throw new Stripe_ApiConnectionError(
'Invalid server certificate. You tried to connect to a server that '.
'has a revoked SSL certificate, which means we cannot securely send '.
'data to that server. Please email support@stripe.com if you need '.
'help connecting to the correct API server.'
);
}
return true;
}
/* Checks if a valid PEM encoded certificate is blacklisted
* @return boolean
*/
public static function isBlackListed($certificate)
{
$certificate = trim($certificate);
$lines = explode("\n", $certificate);
// Kludgily remove the PEM padding
array_shift($lines); array_pop($lines);
$derCert = base64_decode(implode("", $lines));
$fingerprint = sha1($derCert);
return in_array($fingerprint, self::blacklistedCerts());
}
private function caBundle()
{
return dirname(__FILE__) . '/../data/ca-certificates.crt';
}
}

View File

@@ -9,54 +9,102 @@ abstract class Stripe_ApiResource extends Stripe_Object
return $instance;
}
/**
* @returns Stripe_ApiResource The refreshed resource.
*/
public function refresh()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('get', $url);
list($response, $apiKey) = $requestor->request(
'get',
$url,
$this->_retrieveOptions
);
$this->refreshFrom($response, $apiKey);
return $this;
}
}
public static function classUrl($class)
/**
* @param string $class
*
* @returns string The name of the class, with namespacing and underscores
* stripped.
*/
public static function className($class)
{
// Useful for namespaces: Foo\Stripe_Charge
if ($postfix = strrchr($class, '\\'))
$class = substr($postfix, 1);
if (substr($class, 0, strlen('Stripe')) == 'Stripe')
if ($postfixNamespaces = strrchr($class, '\\')) {
$class = substr($postfixNamespaces, 1);
}
// Useful for underscored 'namespaces': Foo_Stripe_Charge
if ($postfixFakeNamespaces = strrchr($class, 'Stripe_')) {
$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}s";
return $name;
}
/**
* @param string $class
*
* @returns string The endpoint URL for the given class.
*/
public static function classUrl($class)
{
$base = self::_scopedLsb($class, 'className', $class);
return "/v1/${base}s";
}
/**
* @returns string The full API URL for this API resource.
*/
public function instanceUrl()
{
$id = $this['id'];
$class = get_class($this);
if (!$id) {
throw new Stripe_InvalidRequestError("Could not determine which URL to request: $class instance has invalid ID: $id");
if ($id === null) {
$message = "Could not determine which URL to request: "
. "$class instance has invalid ID: $id";
throw new Stripe_InvalidRequestError($message, null);
}
$id = Stripe_ApiRequestor::utf8($id);
$base = self::classUrl($class);
$base = $this->_lsb('classUrl', $class);
$extn = urlencode($id);
return "$base/$extn";
}
private static function _validateCall($method, $params=null, $apiKey=null)
{
if ($params && !is_array($params))
throw new Stripe_Error("You must pass an array as the first argument to Stripe API method calls. (HINT: an example call to create a charge would be: \"StripeCharge::create(array('amount' => 100, 'currency' => 'usd', 'card' => array('number' => 4242424242424242, 'exp_month' => 5, 'exp_year' => 2015)))\")");
if ($apiKey && !is_string($apiKey))
throw new Stripe_Error('The second argument to Stripe API method calls is an optional per-request apiKey, which must be a string. (HINT: you can set a global apiKey by "Stripe::setApiKey(<apiKey>)")');
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: \"StripeCharge::create(array('amount' => 100, "
. "'currency' => 'usd', 'card' => array('number' => "
. "4242424242424242, 'exp_month' => 5, 'exp_year' => 2015)))\")";
throw new Stripe_Error($message);
}
if ($apiKey && !is_string($apiKey)) {
$message = 'The second argument to Stripe API method calls is an '
. 'optional per-request apiKey, which must be a string. '
. '(HINT: you can set a global apiKey by '
. '"Stripe::setApiKey(<apiKey>)")';
throw new Stripe_Error($message);
}
}
protected static function _scopedAll($class, $params=null, $apiKey=null)
{
self::_validateCall('all', $params, $apiKey);
$requestor = new Stripe_ApiRequestor($apiKey);
$url = self::classUrl($class);
$url = self::_scopedLsb($class, 'classUrl', $class);
list($response, $apiKey) = $requestor->request('get', $url, $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
@@ -65,19 +113,18 @@ abstract class Stripe_ApiResource extends Stripe_Object
{
self::_validateCall('create', $params, $apiKey);
$requestor = new Stripe_ApiRequestor($apiKey);
$url = self::classUrl($class);
$url = self::_scopedLsb($class, 'classUrl', $class);
list($response, $apiKey) = $requestor->request('post', $url, $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
protected function _scopedSave($class)
protected function _scopedSave($class, $apiKey=null)
{
self::_validateCall('save');
if ($this->_unsavedValues) {
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$params = array();
foreach ($this->_unsavedValues->toArray() as $k)
$params[$k] = $this->$k;
$requestor = new Stripe_ApiRequestor($apiKey);
$params = $this->serializeParameters();
if (count($params) > 0) {
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom($response, $apiKey);

View File

@@ -0,0 +1,53 @@
<?php
class Stripe_ApplicationFee extends Stripe_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($class)
{
return 'application_fee';
}
/**
* @param string $id The ID of the application fee to retrieve.
* @param string|null $apiKey
*
* @return Stripe_ApplicationFee
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param string|null $params
* @param string|null $apiKey
*
* @return array An array of application fees.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param string|null $params
*
* @return Stripe_ApplicationFee The refunded application fee.
*/
public function refund($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/refund';
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom($response, $apiKey);
return $this;
}
}

View File

@@ -0,0 +1,23 @@
<?php
// e.g. metadata on Stripe objects.
class Stripe_AttachedObject extends Stripe_Object
{
/**
* 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;
}
}
}

View File

@@ -0,0 +1,15 @@
<?php
class Stripe_Balance extends Stripe_SingletonApiResource
{
/**
* @param string|null $apiKey
*
* @return Stripe_Balance
*/
public static function retrieve($apiKey=null)
{
$class = get_class();
return self::_scopedSingletonRetrieve($class, $apiKey);
}
}

View File

@@ -0,0 +1,39 @@
<?php
class Stripe_BalanceTransaction extends Stripe_ApiResource
{
/**
* @param string $class Ignored.
*
* @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($class)
{
return "/v1/balance/history";
}
/**
* @param string $id The ID of the balance transaction to retrieve.
* @param string|null $apiKey
*
* @return Stripe_BalanceTransaction
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_BalanceTransactions.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@@ -0,0 +1,66 @@
<?php
class Stripe_Card extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @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 Stripe_InvalidRequestError($msg, null);
}
if (isset($this['customer'])) {
$parent = $this['customer'];
$base = self::classUrl('Stripe_Customer');
} else if (isset($this['recipient'])) {
$parent = $this['recipient'];
$base = self::classUrl('Stripe_Recipient');
} else {
return null;
}
$parent = Stripe_ApiRequestor::utf8($parent);
$id = Stripe_ApiRequestor::utf8($id);
$parentExtn = urlencode($parent);
$extn = urlencode($id);
return "$base/$parentExtn/cards/$extn";
}
/**
* @param array|null $params
*
* @return Stripe_Card The deleted card.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @return Stripe_Card The saved card.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
}

View File

@@ -2,9 +2,11 @@
class Stripe_CardError extends Stripe_Error
{
public function __construct($message, $param, $code, $http_status=null, $http_body=null, $json_body=null)
public function __construct($message, $param, $code, $httpStatus,
$httpBody, $jsonBody
)
{
parent::__construct($message, $http_status, $http_body, $json_body);
parent::__construct($message, $httpStatus, $httpBody, $jsonBody);
$this->param = $param;
$this->code = $code;
}

View File

@@ -2,30 +2,56 @@
class Stripe_Charge extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @param string $id The ID of the charge to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Charge
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Charges.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Charge The created charge.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @return Stripe_Charge The saved charge.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @param array|null $params
*
* @return Stripe_Charge The refunded charge.
*/
public function refund($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
@@ -35,6 +61,11 @@ class Stripe_Charge extends Stripe_ApiResource
return $this;
}
/**
* @param array|null $params
*
* @return Stripe_Charge The captured charge.
*/
public function capture($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
@@ -43,4 +74,30 @@ class Stripe_Charge extends Stripe_ApiResource
$this->refreshFrom($response, $apiKey);
return $this;
}
/**
* @param array|null $params
*
* @return array The updated dispute.
*/
public function updateDispute($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/dispute';
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom(array('dispute' => $response), $apiKey, true);
return $this->dispute;
}
/**
* @return Stripe_Charge The updated charge.
*/
public function closeDispute()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/dispute/close';
list($response, $apiKey) = $requestor->request('post', $url);
$this->refreshFrom($response, $apiKey);
return $this;
}
}

View File

@@ -2,30 +2,47 @@
class Stripe_Coupon extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @param string $id The ID of the coupon to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Coupon
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Coupon The created coupon.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @param array|null $params
*
* @return Stripe_Coupon The deleted coupon.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Coupons.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();

View File

@@ -2,42 +2,67 @@
class Stripe_Customer extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @param string $id The ID of the customer to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Customer
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Customers.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Customer The created customer.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @returns Stripe_Customer The saved customer.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @param array|null $params
*
* @returns Stripe_Customer The deleted customer.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @param array|null $params
*
* @returns Stripe_InvoiceItem The resulting invoice item.
*/
public function addInvoiceItem($params=null)
{
if (!$params)
@@ -47,6 +72,11 @@ class Stripe_Customer extends Stripe_ApiResource
return $ii;
}
/**
* @param array|null $params
*
* @returns array An array of the customer's Stripe_Invoices.
*/
public function invoices($params=null)
{
if (!$params)
@@ -56,6 +86,11 @@ class Stripe_Customer extends Stripe_ApiResource
return $invoices;
}
/**
* @param array|null $params
*
* @returns array An array of the customer's Stripe_InvoiceItems.
*/
public function invoiceItems($params=null)
{
if (!$params)
@@ -65,6 +100,11 @@ class Stripe_Customer extends Stripe_ApiResource
return $iis;
}
/**
* @param array|null $params
*
* @returns array An array of the customer's Stripe_Charges.
*/
public function charges($params=null)
{
if (!$params)
@@ -74,6 +114,11 @@ class Stripe_Customer extends Stripe_ApiResource
return $charges;
}
/**
* @param array|null $params
*
* @returns Stripe_Subscription The updated subscription.
*/
public function updateSubscription($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
@@ -83,6 +128,11 @@ class Stripe_Customer extends Stripe_ApiResource
return $this->subscription;
}
/**
* @param array|null $params
*
* @returns Stripe_Subscription The cancelled subscription.
*/
public function cancelSubscription($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
@@ -91,4 +141,17 @@ class Stripe_Customer extends Stripe_ApiResource
$this->refreshFrom(array('subscription' => $response), $apiKey, true);
return $this->subscription;
}
/**
* @param array|null $params
*
* @returns Stripe_Customer The updated customer.
*/
public function deleteDiscount()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/discount';
list($response, $apiKey) = $requestor->request('delete', $url);
$this->refreshFrom(array('discount' => null), $apiKey, true);
}
}

View File

@@ -2,26 +2,28 @@
class Stripe_Error extends Exception
{
public function __construct($message=null, $http_status=null, $http_body=null, $json_body=null)
public function __construct($message, $httpStatus=null,
$httpBody=null, $jsonBody=null
)
{
parent::__construct($message);
$this->http_status = $http_status;
$this->http_body = $http_body;
$this->json_body = $json_body;
$this->httpStatus = $httpStatus;
$this->httpBody = $httpBody;
$this->jsonBody = $jsonBody;
}
public function getHttpStatus()
{
return $this->http_status;
return $this->httpStatus;
}
public function getHttpBody()
{
return $this->http_body;
return $this->httpBody;
}
public function getJsonBody()
{
return $this->json_body;
return $this->jsonBody;
}
}

View File

@@ -2,18 +2,24 @@
class Stripe_Event extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @param string $id The ID of the event to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Event
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Events.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();

View File

@@ -2,9 +2,11 @@
class Stripe_InvalidRequestError extends Stripe_Error
{
public function __construct($message, $param, $http_status=null, $http_body=null, $json_body=null)
public function __construct($message, $param, $httpStatus=null,
$httpBody=null, $jsonBody=null
)
{
parent::__construct($message, $http_status, $http_body, $json_body);
parent::__construct($message, $httpStatus, $httpBody, $jsonBody);
$this->param = $param;
}
}

View File

@@ -2,24 +2,48 @@
class Stripe_Invoice extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Invoice The created invoice.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @param string $id The ID of the invoice to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Invoice
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Invoices.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Invoice The upcoming invoice.
*/
public static function upcoming($params=null, $apiKey=null)
{
$requestor = new Stripe_ApiRequestor($apiKey);
@@ -27,4 +51,25 @@ class Stripe_Invoice extends Stripe_ApiResource
list($response, $apiKey) = $requestor->request('get', $url, $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
/**
* @return Stripe_Invoice The saved invoice.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @return Stripe_Invoice The paid invoice.
*/
public function pay()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/pay';
list($response, $apiKey) = $requestor->request('post', $url);
$this->refreshFrom($response, $apiKey);
return $this;
}
}

View File

@@ -2,36 +2,54 @@
class Stripe_InvoiceItem extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @param string $id The ID of the invoice item to retrieve.
* @param string|null $apiKey
*
* @return Stripe_InvoiceItem
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_InvoiceItems.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_InvoiceItem The created invoice item.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @return Stripe_InvoiceItem The saved invoice item.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @return Stripe_InvoiceItem The deleted invoice item.
*/
public function delete($params=null)
{
$class = get_class();

View File

@@ -0,0 +1,37 @@
<?php
class Stripe_List extends Stripe_Object
{
public function all($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
list($response, $apiKey) = $requestor->request(
'get',
$this['url'],
$params
);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
public function create($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
list($response, $apiKey) = $requestor->request(
'post', $this['url'], $params
);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
public function retrieve($id, $params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$base = $this['url'];
$id = Stripe_ApiRequestor::utf8($id);
$extn = urlencode($id);
list($response, $apiKey) = $requestor->request(
'get', "$base/$extn", $params
);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
}

View File

@@ -2,17 +2,28 @@
class Stripe_Object implements ArrayAccess
{
public static $_permanentAttributes;
/**
* @var Stripe_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 Stripe_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 Stripe_Util_Set(array('_apiKey'));
self::$permanentAttributes = new Stripe_Util_Set(array('_apiKey', 'id'));
self::$nestedUpdatableAttributes = new Stripe_Util_Set(array('metadata'));
}
protected $_apiKey;
protected $_values;
protected $_unsavedValues;
protected $_transientValues;
protected $_retrieveOptions;
public function __construct($id=null, $apiKey=null)
{
@@ -20,16 +31,41 @@ class Stripe_Object implements ArrayAccess
$this->_values = array();
$this->_unsavedValues = new Stripe_Util_Set();
$this->_transientValues = new Stripe_Util_Set();
if ($id)
$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)
{
// TODO: may want to clear from $_transientValues. (Won't be user-visible.)
$this->_values[$k] = $v;
if (!self::$_permanentAttributes->includes($k))
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) && 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)
@@ -44,12 +80,18 @@ class Stripe_Object implements ArrayAccess
}
public function __get($k)
{
if (isset($this->_values[$k])) {
if (array_key_exists($k, $this->_values)) {
return $this->_values[$k];
} else if ($this->_transientValues->includes($k)) {
$class = get_class($this);
$attrs = join(', ', array_keys($this->_values));
error_log("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");
$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";
error_log($message);
return null;
} else {
$class = get_class($this);
@@ -63,20 +105,35 @@ class Stripe_Object implements ArrayAccess
{
$this->$k = $v;
}
public function offsetExists($k)
{
return isset($this->$k);
return array_key_exists($k, $this->_values);
}
public function offsetUnset($k)
{
unset($this->$k);
}
public function offsetGet($k)
{
return isset($this->_values[$k]) ? $this->_values[$k] : null;
return array_key_exists($k, $this->_values) ? $this->_values[$k] : null;
}
// This unfortunately needs to be public to be used in Util.php
public function keys()
{
return array_keys($this->_values);
}
/**
* This unfortunately needs to be public to be used in Util.php
*
* @param string $class
* @param array $values
* @param string|null $apiKey
*
* @return Stripe_Object The object constructed from the given values.
*/
public static function scopedConstructFrom($class, $values, $apiKey=null)
{
$obj = new $class(isset($values['id']) ? $values['id'] : null, $apiKey);
@@ -84,44 +141,108 @@ class Stripe_Object implements ArrayAccess
return $obj;
}
/**
* @param array $values
* @param string|null $apiKey
*
* @return Stripe_Object The object of the same class as $this constructed
* from the given values.
*/
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
return self::scopedConstructFrom(__CLASS__, $values, $apiKey);
}
/**
* Refreshes this object using the provided values.
*
* @param array $values
* @param string $apiKey
* @param boolean $partial Defaults to false.
*/
public function refreshFrom($values, $apiKey, $partial=false)
{
$this->_apiKey = $apiKey;
// 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)
if ($partial) {
$removed = new Stripe_Util_Set();
else
} else {
$removed = array_diff(array_keys($this->_values), array_keys($values));
}
foreach ($removed as $k) {
if (self::$_permanentAttributes->includes($k))
if (self::$permanentAttributes->includes($k))
continue;
unset($this->$k);
}
foreach ($values as $k => $v) {
if (self::$_permanentAttributes->includes($k))
if (self::$permanentAttributes->includes($k) && isset($this[$k]))
continue;
$this->_values[$k] = Stripe_Util::convertToStripeObject($v, $apiKey);
if (self::$nestedUpdatableAttributes->includes($k) && is_array($v)) {
$this->_values[$k] = Stripe_Object::scopedConstructFrom(
'Stripe_AttachedObject', $v, $apiKey
);
} else {
$this->_values[$k] = Stripe_Util::convertToStripeObject($v, $apiKey);
}
$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)
&& $this->$property instanceOf Stripe_Object) {
$params[$property] = $this->$property->serializeParameters();
}
}
return $params;
}
// Pretend to have late static bindings, even in PHP 5.2
protected function _lsb($method)
{
$class = get_class($this);
$args = array_slice(func_get_args(), 1);
return call_user_func_array(array($class, $method), $args);
}
protected static function _scopedLsb($class, $method)
{
$args = array_slice(func_get_args(), 2);
return call_user_func_array(array($class, $method), $args);
}
public function __toJSON()
{
if (defined('JSON_PRETTY_PRINT'))
if (defined('JSON_PRETTY_PRINT')) {
return json_encode($this->__toArray(true), JSON_PRETTY_PRINT);
else
} else {
return json_encode($this->__toArray(true));
}
}
public function __toString()
@@ -131,10 +252,11 @@ class Stripe_Object implements ArrayAccess
public function __toArray($recursive=false)
{
if ($recursive)
if ($recursive) {
return Stripe_Util::convertStripeObjectToArray($this->_values);
else
} else {
return $this->_values;
}
}
}

View File

@@ -2,36 +2,56 @@
class Stripe_Plan extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @param string $id The ID of the plan to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Plan
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Plan The created plan.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @param array|null $params
*
* @return Stripe_Plan The deleted plan.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @return Stripe_Plan The saved plan.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Plans.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();

View File

@@ -0,0 +1,11 @@
<?php
class Stripe_RateLimitError extends Stripe_InvalidRequestError
{
public function __construct($message, $param, $httpStatus=null,
$httpBody=null, $jsonBody=null
)
{
parent::__construct($message, $httpStatus, $httpBody, $jsonBody);
}
}

View File

@@ -0,0 +1,75 @@
<?php
class Stripe_Recipient extends Stripe_ApiResource
{
/**
* @param string $id The ID of the recipient to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Recipient
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Recipients.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Recipient The created recipient.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @return Stripe_Recipient The saved recipient.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @param array|null $params
*
* @return Stripe_Recipient The deleted recipient.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @param array|null $params
*
* @return array An array of the recipient's Stripe_Transfers.
*/
public function transfers($params=null)
{
if (!$params)
$params = array();
$params['recipient'] = $this->id;
$transfers = Stripe_Transfer::all($params, $this->_apiKey);
return $transfers;
}
}

View File

@@ -0,0 +1,36 @@
<?php
class Stripe_Refund extends Stripe_ApiResource
{
/**
* @return string The API URL for this Stripe refund.
*/
public function instanceUrl()
{
$id = $this['id'];
$charge = $this['charge'];
if (!$id) {
throw new Stripe_InvalidRequestError(
"Could not determine which URL to request: " .
"class instance has invalid ID: $id",
null
);
}
$id = Stripe_ApiRequestor::utf8($id);
$charge = Stripe_ApiRequestor::utf8($charge);
$base = self::classUrl('Stripe_Charge');
$chargeExtn = urlencode($charge);
$extn = urlencode($id);
return "$base/$chargeExtn/refunds/$extn";
}
/**
* @return Stripe_Refund The saved refund.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
}

View File

@@ -0,0 +1,31 @@
<?php
abstract class Stripe_SingletonApiResource extends Stripe_ApiResource
{
protected static function _scopedSingletonRetrieve($class, $apiKey=null)
{
$instance = new $class(null, $apiKey);
$instance->refresh();
return $instance;
}
/**
* @param Stripe_SingletonApiResource $class
* @return string The endpoint associated with this singleton class.
*/
public static function classUrl($class)
{
$base = self::className($class);
return "/v1/${base}";
}
/**
* @return string The endpoint associated with this singleton API resource.
*/
public function instanceUrl()
{
$class = get_class($this);
$base = self::classUrl($class);
return "$base";
}
}

View File

@@ -0,0 +1,73 @@
<?php
abstract 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|null The version of the Stripe API to use for requests.
*/
public static $apiVersion = null;
/**
* @var boolean Defaults to true.
*/
public static $verifySslCerts = true;
const VERSION = '1.16.0';
/**
* @return string The API key used for requests.
*/
public static function getApiKey()
{
return self::$apiKey;
}
/**
* 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;
}
}

View File

@@ -0,0 +1,57 @@
<?php
class Stripe_Subscription extends Stripe_ApiResource
{
/**
* @return string The API URL for this Stripe subscription.
*/
public function instanceUrl()
{
$id = $this['id'];
$customer = $this['customer'];
if (!$id) {
throw new Stripe_InvalidRequestError(
"Could not determine which URL to request: " .
"class instance has invalid ID: $id",
null
);
}
$id = Stripe_ApiRequestor::utf8($id);
$customer = Stripe_ApiRequestor::utf8($customer);
$base = self::classUrl('Stripe_Customer');
$customerExtn = urlencode($customer);
$extn = urlencode($id);
return "$base/$customerExtn/subscriptions/$extn";
}
/**
* @param array|null $params
* @return Stripe_Subscription The deleted subscription.
*/
public function cancel($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @return Stripe_Subscription The saved subscription.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @return Stripe_Subscription The updated subscription.
*/
public function deleteDiscount()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/discount';
list($response, $apiKey) = $requestor->request('delete', $url);
$this->refreshFrom(array('discount' => null), $apiKey, true);
}
}

View File

@@ -2,18 +2,24 @@
class Stripe_Token extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @param string $id The ID of the token to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Token
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Coupon The created token.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();

View File

@@ -0,0 +1,62 @@
<?php
class Stripe_Transfer extends Stripe_ApiResource
{
/**
* @param string $id The ID of the transfer to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Transfer
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Transfers.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Transfer The created transfer.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @return Stripe_Transfer The canceled transfer.
*/
public function cancel()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/cancel';
list($response, $apiKey) = $requestor->request('post', $url);
$this->refreshFrom($response, $apiKey);
return $this;
}
/**
* @return Stripe_Transfer The saved transfer.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
}

View File

@@ -2,11 +2,18 @@
abstract class Stripe_Util
{
/**
* 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: this isn't actually correct in general, but it's correct given Stripe's responses
// TODO: generally incorrect, but it's correct given Stripe's response
foreach (array_keys($array) as $k) {
if (!is_numeric($k))
return false;
@@ -14,43 +21,67 @@ abstract class Stripe_Util
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 (Stripe_Object::$_permanentAttributes->includes($k)) {
if ($k[0] == '_') {
continue;
}
if ($v instanceof Stripe_Object) {
$results[$k] = $v->__toArray(true);
}
else if (is_array($v)) {
} else if (is_array($v)) {
$results[$k] = self::convertStripeObjectToArray($v);
}
else {
} 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 string $apiKey
* @return Stripe_Object|array
*/
public static function convertToStripeObject($resp, $apiKey)
{
$types = array('charge' => 'Stripe_Charge',
'customer' => 'Stripe_Customer',
'invoice' => 'Stripe_Invoice',
'invoiceitem' => 'Stripe_InvoiceItem', 'event' => 'Stripe_Event');
$types = array(
'card' => 'Stripe_Card',
'charge' => 'Stripe_Charge',
'customer' => 'Stripe_Customer',
'list' => 'Stripe_List',
'invoice' => 'Stripe_Invoice',
'invoiceitem' => 'Stripe_InvoiceItem',
'event' => 'Stripe_Event',
'transfer' => 'Stripe_Transfer',
'plan' => 'Stripe_Plan',
'recipient' => 'Stripe_Recipient',
'refund' => 'Stripe_Refund',
'subscription' => 'Stripe_Subscription'
);
if (self::isList($resp)) {
$mapped = array();
foreach ($resp as $i)
array_push($mapped, self::convertToStripeObject($i, $apiKey));
return $mapped;
} else if (is_array($resp)) {
if (isset($resp['object']) && is_string($resp['object']) && isset($types[$resp['object']]))
if (isset($resp['object'])
&& is_string($resp['object'])
&& isset($types[$resp['object']])) {
$class = $types[$resp['object']];
else
} else {
$class = 'Stripe_Object';
}
return Stripe_Object::scopedConstructFrom($class, $resp, $apiKey);
} else {
return $resp;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -91,7 +91,6 @@ return array(
'phabricator-flag-css',
'aphront-error-view-css',
'sprite-remarkup-css',
'sprite-gradient-css',
'sprite-menu-css',
'sprite-apps-css',
@@ -175,7 +174,6 @@ return array(
),
'maniphest.pkg.css' => array(
'maniphest-task-summary-css',
'phabricator-project-tag-css',
),
'maniphest.pkg.js' => array(
'javelin-behavior-maniphest-batch-selector',

View File

@@ -9,8 +9,8 @@
"PhabricatorBotObjectNameHandler",
"PhabricatorBotSymbolHandler",
"PhabricatorBotLogHandler",
"PhabricatorBotFeedNotificationHandler",
"PhabricatorBotWhatsNewHandler",
"PhabricatorBotDifferentialNotificationHandler",
"PhabricatorBotMacroHandler"
],

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -1,20 +1,35 @@
{
"version" : 1,
"sprites" : {
"gradient-dark-grey-header" : {
"gradient-dark-grey-header" : {
"name" : "gradient-dark-grey-header",
"rule" : ".gradient-dark-grey-header",
"hash" : "e8762dd2849410a7e4fba8f972f946ff"
},
"gradient-grey-header" : {
"gradient-grey-header" : {
"name" : "gradient-grey-header",
"rule" : ".gradient-grey-header",
"hash" : "1c8f8d61984e3fc5a7e528b9bd4d484a"
},
"gradient-lightblue-header" : {
"gradient-lightblue-header" : {
"name" : "gradient-lightblue-header",
"rule" : ".gradient-lightblue-header",
"hash" : "e7753a6ce63c6822a559266eef9e255b"
},
"gradient-lightgreen-header" : {
"name" : "gradient-lightgreen-header",
"rule" : ".gradient-lightgreen-header",
"hash" : "87b5c391ea4ea84dd8531fb0f199cbeb"
},
"gradient-lightred-header" : {
"name" : "gradient-lightred-header",
"rule" : ".gradient-lightred-header",
"hash" : "a367ea9163aa15f52c105b5805cf493e"
},
"gradient-lightviolet-header" : {
"name" : "gradient-lightviolet-header",
"rule" : ".gradient-lightviolet-header",
"hash" : "e17e05135e53e1258340cfc27f96f23f"
}
},
"scales" : [

View File

@@ -11,6 +11,11 @@
"rule" : ".login-Asana",
"hash" : "30df492eab339fa64c9ae9b21bb46a18"
},
"login-Bitbucket" : {
"name" : "login-Bitbucket",
"rule" : ".login-Bitbucket",
"hash" : "899182cf1ca35891b64aaa5426bf623a"
},
"login-Disqus" : {
"name" : "login-Disqus",
"rule" : ".login-Disqus",
@@ -61,6 +66,11 @@
"rule" : ".login-Linkedin",
"hash" : "0dd89825046fa4fd0fe402aa2cd55fd1"
},
"login-MediaWiki" : {
"name" : "login-MediaWiki",
"rule" : ".login-MediaWiki",
"hash" : "6e9e75fdad545f415d78719bd2dee3ec"
},
"login-Openid" : {
"name" : "login-Openid",
"rule" : ".login-Openid",

View File

@@ -14,7 +14,7 @@
"arrow-right" : {
"name" : "arrow-right",
"rule" : ".phabricator-crumb-divider",
"hash" : "ae2d24462b09e41b62a43b11f57f17af"
"hash" : "87affa58adbe8da437a1cea6ffc5d8a4"
},
"conf-hover" : {
"name" : "conf-hover",

View File

@@ -1,91 +0,0 @@
{
"version" : 1,
"sprites" : {
"remarkup-assist-none" : {
"name" : "remarkup-assist-none",
"rule" : ".remarkup-assist-",
"hash" : "a7a394dbf21494f2279cc3d528aeb40b"
},
"remarkup-assist-text_b" : {
"name" : "remarkup-assist-text_b",
"rule" : ".remarkup-assist-b",
"hash" : "ba8a8f8928f2f90e7acd024df8bdee3b"
},
"remarkup-assist-text_code" : {
"name" : "remarkup-assist-text_code",
"rule" : ".remarkup-assist-code",
"hash" : "b8a03a1004074f0582e77eb4f916b00b"
},
"remarkup-assist-text_fullscreen" : {
"name" : "remarkup-assist-text_fullscreen",
"rule" : ".remarkup-assist-fullscreen",
"hash" : "63254d9cbe6eadee87d1a28c1d246f9d"
},
"remarkup-assist-text_fullscreen_off" : {
"name" : "remarkup-assist-text_fullscreen_off",
"rule" : ".remarkup-control-fullscreen-mode .remarkup-assist-fullscreen",
"hash" : "cdcdca0556b6f16b0628684470fc1251"
},
"remarkup-assist-text_help" : {
"name" : "remarkup-assist-text_help",
"rule" : ".remarkup-assist-help",
"hash" : "106f56bad2932f523cbf1a62ab12b681"
},
"remarkup-assist-text_i" : {
"name" : "remarkup-assist-text_i",
"rule" : ".remarkup-assist-i",
"hash" : "d9b1a0629d40edd5d32d3e6e21ec1574"
},
"remarkup-assist-text_image" : {
"name" : "remarkup-assist-text_image",
"rule" : ".remarkup-assist-image",
"hash" : "3e84bf38ccb50c9109dfd78b1711dbb6"
},
"remarkup-assist-text_larger" : {
"name" : "remarkup-assist-text_larger",
"rule" : ".remarkup-assist-larger",
"hash" : "05909067a2513b9b664b313974643ce3"
},
"remarkup-assist-text_link" : {
"name" : "remarkup-assist-text_link",
"rule" : ".remarkup-assist-link",
"hash" : "3a6575ca85ddfaa63103d5a8ab80fc09"
},
"remarkup-assist-text_meme" : {
"name" : "remarkup-assist-text_meme",
"rule" : ".remarkup-assist-meme",
"hash" : "3fa5e69cfc12cd5eba038b48f1efb6c5"
},
"remarkup-assist-text_ol" : {
"name" : "remarkup-assist-text_ol",
"rule" : ".remarkup-assist-ol",
"hash" : "b1964f62cb2c3cd6ed12bb04522a22c7"
},
"remarkup-assist-text_table" : {
"name" : "remarkup-assist-text_table",
"rule" : ".remarkup-assist-table",
"hash" : "95fffc501412b323fbdccc98f5bb595c"
},
"remarkup-assist-text_tag" : {
"name" : "remarkup-assist-text_tag",
"rule" : ".remarkup-assist-tag",
"hash" : "49ed577b1081dd44f60325795468c8ad"
},
"remarkup-assist-text_tt" : {
"name" : "remarkup-assist-text_tt",
"rule" : ".remarkup-assist-tt",
"hash" : "3c8753b5df23a2a48348cb4ef86b3c02"
},
"remarkup-assist-text_ul" : {
"name" : "remarkup-assist-text_ul",
"rule" : ".remarkup-assist-ul",
"hash" : "6b1add427c45ed676b9b7f220f16513a"
}
},
"scales" : [
1,
2
],
"header" : "\/**\n * @provides sprite-remarkup-css\n * @generated\n *\/\n\n.sprite-remarkup {\n background-image: url(\/rsrc\/image\/sprite-remarkup.png);\n background-repeat: no-repeat;\n}\n\n@media\nonly screen and (min-device-pixel-ratio: 1.5),\nonly screen and (-webkit-min-device-pixel-ratio: 1.5) {\n .sprite-remarkup {\n background-image: url(\/rsrc\/image\/sprite-remarkup-X2.png);\n background-size: {X}px {Y}px;\n }\n}\n",
"type" : "standard"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 988 B

View File

@@ -0,0 +1 @@
DROP TABLE {$NAMESPACE}_differential.differential_relationship;

View File

@@ -0,0 +1 @@
DROP TABLE {$NAMESPACE}_differential.differential_comment;

View File

@@ -0,0 +1 @@
DROP TABLE {$NAMESPACE}_differential.differential_inlinecomment;

View File

@@ -0,0 +1 @@
DROP TABLE {$NAMESPACE}_differential.differential_auxiliaryfield;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_pholio.pholio_mock
ADD editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin;

View File

@@ -0,0 +1,2 @@
UPDATE {$NAMESPACE}_pholio.pholio_mock
SET editPolicy = authorPHID WHERE editPolicy = '';

View File

@@ -0,0 +1,3 @@
ALTER TABLE {$NAMESPACE}_daemon.daemon_log
ADD COLUMN explicitArgv longtext CHARACTER SET utf8
COLLATE utf8_bin NOT NULL AFTER argv;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_daemon.daemon_log
ADD KEY (dateCreated);

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_project.project
ADD color VARCHAR(32) NOT NULL COLLATE utf8_bin;

View File

@@ -0,0 +1,2 @@
UPDATE {$NAMESPACE}_project.project
SET color = 'blue' WHERE color = '';

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_dashboard.dashboard_panel
ADD isArchived BOOL NOT NULL DEFAULT 0 AFTER editPolicy;

View File

@@ -0,0 +1,7 @@
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
ADD signerName VARCHAR(255) NOT NULL COLLATE utf8_general_ci
AFTER signerPHID;
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
ADD signerEmail VARCHAR(255) NOT NULL COLLATE utf8_general_ci
AFTER signerName;

View File

@@ -0,0 +1,17 @@
<?php
$table = new LegalpadDocumentSignature();
$conn_w = $table->establishConnection('w');
foreach (new LiskMigrationIterator($table) as $signature) {
echo pht("Updating Legalpad signature %d...\n", $signature->getID());
$data = $signature->getSignatureData();
queryfx(
$conn_w,
'UPDATE %T SET signerName = %s, signerEmail = %s WHERE id = %d',
$table->getTableName(),
(string)idx($data, 'name'),
(string)idx($data, 'email'),
$signature->getID());
}

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
ADD isExemption BOOL NOT NULL DEFAULT 0 AFTER verified;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
ADD exemptionPHID VARCHAR(64) COLLATE utf8_bin AFTER isExemption;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_document
ADD signatureType VARCHAR(4) NOT NULL COLLATE utf8_bin;

View File

@@ -0,0 +1,2 @@
UPDATE {$NAMESPACE}_legalpad.legalpad_document
SET signatureType = 'user' WHERE signatureType = '';

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
ADD signatureType VARCHAR(4) NOT NULL COLLATE utf8_bin AFTER documentVersion;

View File

@@ -0,0 +1,2 @@
UPDATE {$NAMESPACE}_legalpad.legalpad_documentsignature
SET signatureType = 'user' WHERE signatureType = '';

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
CHANGE signerPHID signerPHID VARCHAR(64) COLLATE utf8_bin;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildstep
ADD name VARCHAR(255) COLLATE utf8_bin;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildtarget
ADD name VARCHAR(255) COLLATE utf8_bin;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_document
ADD preamble LONGTEXT NOT NULL COLLATE utf8_general_ci;

View File

@@ -0,0 +1,11 @@
ALTER TABLE {$NAMESPACE}_worker.worker_activetask
ADD COLUMN priority int unsigned NOT NULL;
ALTER TABLE {$NAMESPACE}_worker.worker_activetask
ADD KEY (leaseOwner, priority, id);
ALTER TABLE {$NAMESPACE}_worker.worker_archivetask
ADD COLUMN priority int unsigned NOT NULL;
ALTER TABLE {$NAMESPACE}_worker.worker_archivetask
ADD KEY (leaseOwner, priority, id);

View File

@@ -0,0 +1,5 @@
ALTER TABLE {$NAMESPACE}_project.project_column
DROP KEY key_sequence;
ALTER TABLE {$NAMESPACE}_project.project_column
ADD KEY key_sequence (projectPHID, sequence);

View File

@@ -24,7 +24,7 @@ foreach ($tables as $table) {
echo "Converting {$name}...\n";
queryfx(
$conn,
"ALTER TABLE %T.%T ENGINE=InnoDB",
'ALTER TABLE %T.%T ENGINE=InnoDB',
$table['db'],
$table['tbl']);
}

View File

@@ -7,10 +7,10 @@ $table->openTransaction();
$table->beginReadLocking();
$users = $table->loadAll();
echo count($users)." users to index";
echo count($users).' users to index';
foreach ($users as $user) {
$user->updateNameTokens();
echo ".";
echo '.';
}
$table->endReadLocking();

View File

@@ -64,9 +64,9 @@ while ($update) {
}
if (count($update) == $size) {
throw new Exception(
"Failed to make any progress while updating projects. Schema upgrade ".
"has failed. Go manually fix your project names to be unique (they are ".
"probably ridiculous?) and then try again.");
'Failed to make any progress while updating projects. Schema upgrade '.
'has failed. Go manually fix your project names to be unique (they are '.
'probably ridiculous?) and then try again.');
}
}

View File

@@ -41,7 +41,7 @@ foreach ($rules as $rule) {
$rule->getRuleType(),
$rule->getID());
echo "Setting rule '" . $rule->getName() . "' to personal. ";
echo "Setting rule '".$rule->getName()."' to personal. ";
}
}
}

View File

@@ -24,14 +24,14 @@ if ($rules) {
mpull($rules, 'getID'));
}
echo "This may take a moment";
echo 'This may take a moment';
do {
queryfx(
$conn_w,
'DELETE FROM %T %Q LIMIT 1000',
HeraldRule::TABLE_RULE_APPLIED,
$clause);
echo ".";
echo '.';
} while ($conn_w->getAffectedRows());
$table->endReadLocking();

View File

@@ -2,5 +2,5 @@
$conn = id(new PhabricatorRepository())->establishConnection('w');
if (queryfx_one($conn, "SHOW COLUMNS FROM `repository` LIKE 'description'")) {
queryfx($conn, "ALTER TABLE `repository` DROP `description`");
queryfx($conn, 'ALTER TABLE `repository` DROP `description`');
}

View File

@@ -5,12 +5,12 @@ $table->openTransaction();
$table->beginReadLocking();
$conn_w = $table->establishConnection('w');
echo "Migrating revisions";
echo 'Migrating revisions';
do {
$revisions = $table->loadAllWhere('branchName IS NULL LIMIT 1000');
foreach ($revisions as $revision) {
echo ".";
echo '.';
$diff = $revision->loadActiveDiff();
if (!$diff) {

View File

@@ -1,6 +1,6 @@
<?php
echo "Giving image macros PHIDs";
echo 'Giving image macros PHIDs';
$table = new PhabricatorFileImageMacro();
$table->openTransaction();
@@ -9,7 +9,7 @@ foreach (new LiskMigrationIterator($table) as $macro) {
continue;
}
echo ".";
echo '.';
queryfx(
$macro->establishConnection('w'),

View File

@@ -11,7 +11,7 @@ $revs = queryfx_all(
'SELECT id, phid, unsubscribed FROM differential_revision');
foreach ($revs as $rev) {
echo ".";
echo '.';
$unsubscribed = json_decode($rev['unsubscribed']);
if (!$unsubscribed) {

View File

@@ -22,12 +22,12 @@ foreach (new LiskMigrationIterator($commit_table) as $commit) {
$editor->addEdge($commit->getPHID(), $commit_drev, $revision_phid);
$edges++;
if ($edges % 256 == 0) {
echo ".";
echo '.';
$editor->save();
$editor = id(new PhabricatorEdgeEditor())->setSuppressEvents(true);
}
}
echo ".";
echo '.';
$editor->save();
echo "\nDone.\n";

View File

@@ -1,6 +1,6 @@
<?php
echo "Giving countdowns PHIDs";
echo 'Giving countdowns PHIDs';
$table = new PhabricatorCountdown();
$table->openTransaction();
@@ -9,7 +9,7 @@ foreach (new LiskMigrationIterator($table) as $countdown) {
continue;
}
echo ".";
echo '.';
queryfx(
$countdown->establishConnection('w'),

View File

@@ -1,6 +1,6 @@
<?php
echo "Populating Legalpad Documents with ",
echo 'Populating Legalpad Documents with ',
"titles, recentContributorPHIDs, and contributorCounts...\n";
$table = new LegalpadDocument();
$table->openTransaction();

View File

@@ -1,6 +1,6 @@
<?php
echo "Giving pholio images PHIDs";
echo 'Giving pholio images PHIDs';
$table = new PholioImage();
$table->openTransaction();
@@ -9,7 +9,7 @@ foreach (new LiskMigrationIterator($table) as $image) {
continue;
}
echo ".";
echo '.';
queryfx(
$image->establishConnection('w'),

View File

@@ -13,9 +13,9 @@ foreach (new LiskMigrationIterator($table) as $plan) {
$rows = queryfx_all(
$conn_w,
"SELECT id, sequence FROM harbormaster_buildstep ".
"WHERE buildPlanPHID = %s ".
"ORDER BY id ASC",
'SELECT id, sequence FROM harbormaster_buildstep '.
'WHERE buildPlanPHID = %s '.
'ORDER BY id ASC',
$plan->getPHID());
$sequence = 1;
@@ -29,9 +29,9 @@ foreach (new LiskMigrationIterator($table) as $plan) {
echo " - {$id} to position {$sequence}...\n";
queryfx(
$conn_w,
"UPDATE harbormaster_buildstep ".
"SET sequence = %d ".
"WHERE id = %d",
'UPDATE harbormaster_buildstep '.
'SET sequence = %d '.
'WHERE id = %d',
$sequence,
$id);
$sequence++;

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