Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
906 additions
and
799 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
// Tested on PHP 5.2, 5.3 | ||
|
||
// This snippet (and some of the curl code) due to the Facebook SDK. | ||
if (!function_exists('curl_init')) { | ||
throw new Exception('Stripe needs the CURL PHP extension.'); | ||
} | ||
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'; | ||
const VERSION = '1.5.1'; | ||
} | ||
|
||
// Utilities | ||
require_once(dirname(__FILE__) . '/Stripe/Util.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/Util/Set.php'); | ||
|
||
// Errors | ||
require_once(dirname(__FILE__) . '/Stripe/Error.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/Error/Api.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/Error/ApiConnection.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/Error/Authentication.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/Error/Card.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/Error/InvalidRequest.php'); | ||
|
||
// Plumbing | ||
require_once(dirname(__FILE__) . '/Stripe/Object.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/ApiRequestor.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/ApiResource.php'); | ||
|
||
// Stripe API Resources | ||
require_once(dirname(__FILE__) . '/Stripe/Charge.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/Customer.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/Invoice.php'); | ||
require_once(dirname(__FILE__) . '/Stripe/InvoiceItem.php'); | ||
|
||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
<?php | ||
|
||
class Stripe_ApiRequestor { | ||
public $apiKey; | ||
|
||
public function __construct($apiKey=null) { | ||
$this->apiKey = $apiKey; | ||
} | ||
|
||
public static function apiUrl($url='') { | ||
$apiBase = Stripe::$apiBase; | ||
return "$apiBase$url"; | ||
} | ||
|
||
public static function utf8($value) { | ||
if (is_string($value)) | ||
return utf8_encode($value); | ||
else | ||
return $value; | ||
} | ||
|
||
private static function objectsToIds($d) { | ||
if ($d instanceof Stripe_ApiRequestor) { | ||
return $d->id; | ||
} else if (is_array($d)) { | ||
$res = array(); | ||
foreach ($res as $k => $v) | ||
$res[$k] = self::objectsToIds($v); | ||
return $res; | ||
} else { | ||
return $d; | ||
} | ||
} | ||
|
||
public static function encode($d) { | ||
return http_build_query($d, null, '&'); | ||
} | ||
|
||
public function request($meth, $url, $params=null) { | ||
if (!$params) | ||
$params = array(); | ||
list($rbody, $rcode, $myApiKey) = $this->requestRaw($meth, $url, $params); | ||
$resp = $this->interpretResponse($rbody, $rcode); | ||
return array($resp, $myApiKey); | ||
} | ||
|
||
public function handleApiError($rbody, $rcode, $resp) { | ||
if (!is_array($resp) || !isset($resp['error'])) | ||
throw new Stripe_Error_Api("Invalid response object from API: $rbody (HTTP response code was $rcode)"); | ||
$error = $resp['error']; | ||
switch ($rcode) { | ||
case 400: | ||
case 404: | ||
throw new Stripe_Error_InvalidRequest(isset($error['message']) ? $error['message'] : null, | ||
isset($error['param']) ? $error['param'] : null); | ||
case 401: | ||
throw new Stripe_Error_Authentication(isset($error['message']) ? $error['message'] : null); | ||
case 402: | ||
throw new Stripe_Error_Card(isset($error['message']) ? $error['message'] : null, | ||
isset($error['param']) ? $error['param'] : null, | ||
isset($error['code']) ? $error['code'] : null); | ||
default: | ||
throw new Stripe_Error_Api(isset($error['message']) ? $error['message'] : null); | ||
} | ||
} | ||
|
||
private function requestRaw($meth, $url, $params) { | ||
$myApiKey = $this->apiKey; | ||
if (!$myApiKey) | ||
$myApiKey = Stripe::$apiKey; | ||
if (!$myApiKey) | ||
throw new Stripe_Error_Authentication('No API key provided. (HINT: set your API key using "Stripe::$apiKey = <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.'); | ||
|
||
$absUrl = $this->apiUrl($url); | ||
$params = Stripe_Util::arrayClone($params); | ||
$this->objectsToIds($params); | ||
$langVersion = phpversion(); | ||
$uname = php_uname(); | ||
$ua = array('bindings_version' => Stripe::VERSION, | ||
'lang' => 'php', | ||
'lang_version' => $langVersion, | ||
'publisher' => 'stripe', | ||
'uname' => $uname); | ||
$headers = array('X-Stripe-Client-User-Agent: ' . json_encode($ua), | ||
'User-Agent: Stripe/v1 RubyBindings/' . Stripe::VERSION); | ||
list($rbody, $rcode) = $this->curlRequest($meth, $absUrl, $headers, $params, $myApiKey); | ||
return array($rbody, $rcode, $myApiKey); | ||
} | ||
|
||
private function interpretResponse($rbody, $rcode) { | ||
try { | ||
$resp = json_decode($rbody, true); | ||
} catch (Exception $e) { | ||
throw new Stripe_Error_Api("Invalid response body from API: $rbody (HTTP response code was $rcode)"); | ||
} | ||
|
||
if ($rcode < 200 || $rcode >= 300) { | ||
$this->handleApiError($rbody, $rcode, $resp); | ||
} | ||
return $resp; | ||
} | ||
|
||
private function curlRequest($meth, $absUrl, $headers, $params, $myApiKey) { | ||
$curl = curl_init(); | ||
$meth = strtolower($meth); | ||
$opts = array(); | ||
if ($meth == 'get') { | ||
$opts[CURLOPT_HTTPGET] = 1; | ||
if (count($params) > 0) { | ||
$encoded = self::encode($params); | ||
$absUrl = "$absUrl?$encoded"; | ||
} | ||
} else if ($meth == 'post') { | ||
$opts[CURLOPT_POST] = 1; | ||
$opts[CURLOPT_POSTFIELDS] = self::encode($params); | ||
} else if ($meth == 'delete') { | ||
$opts[CURLOPT_CUSTOMREQUEST] = 'DELETE'; | ||
} else { | ||
throw new Stripe_Error_Api("Unrecognized method $meth"); | ||
} | ||
|
||
$absUrl = self::utf8($absUrl); | ||
$opts[CURLOPT_URL] = $absUrl; | ||
$opts[CURLOPT_RETURNTRANSFER] = true; | ||
$opts[CURLOPT_CONNECTTIMEOUT] = 30; | ||
$opts[CURLOPT_TIMEOUT] = 80; | ||
$opts[CURLOPT_RETURNTRANSFER] = true; | ||
$opts[CURLOPT_HTTPHEADER] = $headers; | ||
$opts[CURLOPT_USERPWD] = $myApiKey . ':'; | ||
|
||
curl_setopt_array($curl, $opts); | ||
$rbody = curl_exec($curl); | ||
|
||
if (curl_errno($curl) == 60) { // CURLE_SSL_CACERT | ||
curl_setopt($curl, CURLOPT_CAINFO, | ||
dirname(__FILE__) . '/data/ca-certificates.crt'); | ||
$rbody = curl_exec($curl); | ||
} | ||
|
||
if ($rbody === false) { | ||
$errno = curl_errno($curl); | ||
$message = curl_error($curl); | ||
curl_close($curl); | ||
$this->handleCurlError($errno, $message); | ||
} | ||
|
||
$rcode = curl_getinfo($curl, CURLINFO_HTTP_CODE); | ||
curl_close($curl); | ||
return array($rbody, $rcode); | ||
} | ||
|
||
public function handleCurlError($errno, $message) { | ||
$apiBase = Stripe::$apiBase; | ||
switch ($errno) { | ||
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/stripe, or let us know at support@stripe.com."; | ||
case CURLE_SSL_CACERT: | ||
$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."; | ||
default: | ||
$msg = "Unexpected error communicating with Stripe. If this problem persists, let us know at support@stripe.com."; | ||
} | ||
|
||
$msg .= "\n\n(Network error: $message)"; | ||
throw new Stripe_Error_ApiConnection($msg); | ||
} | ||
} | ||
|
||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
<?php | ||
|
||
abstract class Stripe_ApiResource extends Stripe_Object { | ||
protected function ident() { | ||
return array($this['id']); | ||
} | ||
|
||
protected static function scopedRetrieve($class, $id, $apiKey=null) { | ||
$instance = new $class($id, $apiKey); | ||
$instance->refresh(); | ||
return $instance; | ||
} | ||
|
||
public function refresh() { | ||
$requestor = new Stripe_ApiRequestor($this->apiKey); | ||
$url = $this->instanceUrl(); | ||
list($response, $apiKey) = $requestor->request('get', $url); | ||
$this->refreshFrom($response, $apiKey); | ||
return $this; | ||
} | ||
|
||
public static function classUrl($class) { | ||
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"; | ||
} | ||
|
||
public function instanceUrl() { | ||
$id = $this['id']; | ||
if (!$id) { | ||
$class = get_class($this); | ||
throw new Stripe_Error_InvalidRequest("Could not determine which URL to request: $class instance has invalid ID: $id"); | ||
} | ||
$id = Stripe_ApiRequestor::utf8($id); | ||
$class = get_class($this); | ||
$base = self::classUrl($class); | ||
$extn = urlencode($id); | ||
return "$base/$extn"; | ||
} | ||
|
||
private static function validateCall($method, $params=null, $apiKey=null) { | ||
if ($params && !is_array($params)) | ||
throw new StripeError("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 StripeError('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::$apiKey = <apiKey>")'); | ||
} | ||
|
||
protected static function scopedAll($class, $params=null, $apiKey=null) { | ||
self::validateCall('all', $params, $apiKey); | ||
$requestor = new Stripe_ApiRequestor($apiKey); | ||
$url = self::classUrl($class); | ||
list($response, $apiKey) = $requestor->request('get', $url, $params); | ||
return Stripe_Util::convertToStripeObject($response, $apiKey); | ||
} | ||
|
||
protected static function scopedCreate($class, $params=null, $apiKey=null) { | ||
self::validateCall('create', $params, $apiKey); | ||
$requestor = new Stripe_ApiRequestor($apiKey); | ||
$url = self::classUrl($class); | ||
list($response, $apiKey) = $requestor->request('post', $url, $params); | ||
return Stripe_Util::convertToStripeObject($response, $apiKey); | ||
} | ||
|
||
protected function scopedSave($class) { | ||
self::validateCall('save'); | ||
if ($this->unsavedValues) { | ||
$requestor = new Stripe_ApiRequestor($this->apiKey); | ||
$params = array(); | ||
foreach ($this->unsavedValues->toArray() as $k) | ||
$params[$k] = $this->$k; | ||
$url = $this->instanceUrl(); | ||
list($response, $apiKey) = $requestor->request('post', $url, $params); | ||
$this->refreshFrom($response, $apiKey); | ||
} | ||
return $this; | ||
} | ||
|
||
protected function scopedDelete($class) { | ||
self::validateCall('delete'); | ||
$requestor = new Stripe_ApiRequestor($this->apiKey); | ||
$url = $this->instanceUrl(); | ||
list($response, $apiKey) = $requestor->request('delete', $url); | ||
$this->refreshFrom($response, $apiKey); | ||
return $this; | ||
} | ||
} | ||
|
||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
class Stripe_Charge extends Stripe_ApiResource { | ||
public static function constructFrom($values, $apiKey=null) { | ||
$class = get_class(); | ||
return self::scopedConstructFrom($class, $values, $apiKey); | ||
} | ||
|
||
public static function retrieve($id, $apiKey=null) { | ||
$class = get_class(); | ||
return self::scopedRetrieve($class, $id, $apiKey); | ||
} | ||
|
||
public static function all($params=null, $apiKey=null) { | ||
$class = get_class(); | ||
return self::scopedAll($class, $params, $apiKey); | ||
} | ||
|
||
public static function create($params=null, $apiKey=null) { | ||
$class = get_class(); | ||
return self::scopedCreate($class, $params, $apiKey); | ||
} | ||
|
||
public function refund() { | ||
$requestor = new Stripe_ApiRequestor($this->apiKey); | ||
$url = $this->instanceUrl() . '/refund'; | ||
list($response, $apiKey) = $requestor->request('post', $url); | ||
$this->refreshFrom($response, $apiKey); | ||
return $this; | ||
} | ||
} | ||
|
||
?> |
Oops, something went wrong.