self::$client_id, 'redirect_uri' => $redirect_uri, 'scope' => implode(',', $scope), 'state' => empty($options['state']) ? '' : $options['state'], 'user_name' => empty($options['user_name']) ? '' : $options['user_name'], 'user_email' => empty($options['user_email']) ? '' : $options['user_email'], ), '', '&'); return $uri; } private static function getDomain() { if (self::$production === true) { return 'https://wepayapi.com/v2/'; } elseif (self::$production === false) { return 'https://stage.wepayapi.com/v2/'; } else { throw new RuntimeException('You must initialize the WePay SDK with WePay::useStaging() or WePay::useProduction()'); } } /** * Exchange a temporary access code for a (semi-)permanent access token * @param string $code 'code' field from query string passed to your redirect_uri page * @param string $redirect_uri Where user went after logging in at WePay (must match value from getAuthorizationUri) * @return StdClass|false * user_id * access_token * token_type */ public static function getToken($code, $redirect_uri) { $params = (array( 'client_id' => self::$client_id, 'client_secret' => self::$client_secret, 'redirect_uri' => $redirect_uri, 'code' => $code, 'state' => '', // do not hardcode )); $result = self::make_request('oauth2/token', $params); return $result; } /** * Configure SDK to run against WePay's production servers * @param string $client_id Your application's client id * @param string $client_secret Your application's client secret * @return void * @throws RuntimeException */ public static function useProduction($client_id, $client_secret) { if (self::$production !== null) { throw new RuntimeException('API mode has already been set.'); } self::$production = true; self::$client_id = $client_id; self::$client_secret = $client_secret; } /** * Configure SDK to run against WePay's staging servers * @param string $client_id Your application's client id * @param string $client_secret Your application's client secret * @return void * @throws RuntimeException */ public static function useStaging($client_id, $client_secret) { if (self::$production !== null) { throw new RuntimeException('API mode has already been set.'); } self::$production = false; self::$client_id = $client_id; self::$client_secret = $client_secret; } /** * Create a new API session * @param string $token - access_token returned from WePay::getToken */ public function __construct($token) { if ($token && !is_string($token)) { throw new InvalidArgumentException('$token must be a string, ' . gettype($token) . ' provided'); } $this->token = $token; } /** * Clean up cURL handle */ public function __destruct() { if (self::$ch) { curl_close(self::$ch); self::$ch = NULL; } } /** * create the cURL request and execute it */ private static function make_request($endpoint, $values, $headers = array()) { self::$ch = curl_init(); $headers = array_merge(array("Content-Type: application/json"), $headers); // always pass the correct Content-Type header curl_setopt(self::$ch, CURLOPT_USERAGENT, 'WePay v2 PHP SDK v' . self::VERSION); curl_setopt(self::$ch, CURLOPT_RETURNTRANSFER, true); curl_setopt(self::$ch, CURLOPT_HTTPHEADER, $headers); curl_setopt(self::$ch, CURLOPT_TIMEOUT, 30); // 30-second timeout, adjust to taste curl_setopt(self::$ch, CURLOPT_POST, !empty($values)); // WePay's API is not strictly RESTful, so all requests are sent as POST unless there are no request values $uri = self::getDomain() . $endpoint; curl_setopt(self::$ch, CURLOPT_URL, $uri); if (!empty($values)) { curl_setopt(self::$ch, CURLOPT_POSTFIELDS, json_encode($values)); } $raw = curl_exec(self::$ch); if ($errno = curl_errno(self::$ch)) { // Set up special handling for request timeouts if ($errno == CURLE_OPERATION_TIMEOUTED) { throw new WePayServerException("Timeout occurred while trying to connect to WePay"); } throw new Exception('cURL error while making API call to WePay: ' . curl_error(self::$ch), $errno); } $result = json_decode($raw); $error_code = null; if (isset($result->error_code)) { $error_code = $result->error_code; } $httpCode = curl_getinfo(self::$ch, CURLINFO_HTTP_CODE); if ($httpCode >= 400) { if ($httpCode >= 500) { throw new WePayServerException($result->error_description, $httpCode, $result, $error_code); } switch ($result->error) { case 'invalid_request': throw new WePayRequestException($result->error_description, $httpCode, $result, $error_code); case 'access_denied': default: throw new WePayPermissionException($result->error_description, $httpCode, $result, $error_code); } } return $result; } /** * Make API calls against authenticated user * @param string $endpoint - API call to make (ex. 'user', 'account/find') * @param array $values - Associative array of values to send in API call * @return StdClass * @throws WePayException on failure * @throws Exception on catastrophic failure (non-WePay-specific cURL errors) */ public function request($endpoint, array $values = array()) { $headers = array(); if ($this->token) { // if we have an access_token, add it to the Authorization header $headers[] = "Authorization: Bearer $this->token"; } $result = self::make_request($endpoint, $values, $headers); return $result; } } /** * Different problems will have different exception types so you can * catch and handle them differently. * * WePayServerException indicates some sort of 500-level error code and * was unavoidable from your perspective. You may need to re-run the * call, or check whether it was received (use a "find" call with your * reference_id and make a decision based on the response) * * WePayRequestException indicates a development error - invalid endpoint, * erroneous parameter, etc. * * WePayPermissionException indicates your authorization token has expired, * was revoked, or is lacking in scope for the call you made */ class WePayException extends Exception { public function __construct($description = '', $http_code = FALSE, $response = FALSE, $code = 0, $previous = NULL) { $this->response = $response; if (!defined('PHP_VERSION_ID')) { $version = explode('.', PHP_VERSION); define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2])); } if (PHP_VERSION_ID < 50300) { parent::__construct($description, $code); } else { parent::__construct($description, $code, $previous); } } } class WePayRequestException extends WePayException {} class WePayPermissionException extends WePayException {} class WePayServerException extends WePayException {}