PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Component/Stripe.php

https://gitlab.com/scribe-inc/ScribeStripeBundle
PHP | 320 lines | 178 code | 49 blank | 93 comment | 26 complexity | d854a964891bbf7db759d251d52c406e MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Scribe World Application.
  4. *
  5. * (c) Scribe Inc. <scribe@scribenet.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Scribe\StripeBundle\Component;
  11. use Symfony\Component\DependencyInjection\ContainerAwareInterface,
  12. Symfony\Component\DependencyInjection\ContainerInterface;
  13. use Scribe\StripeBundle\Exception\StripeException;
  14. /**
  15. * Stripe class
  16. */
  17. abstract class Stripe implements ContainerAwareInterface
  18. {
  19. /**
  20. * bundle version
  21. */
  22. const BUNDLE_VERSION = '0.5.0';
  23. /**
  24. * api version
  25. */
  26. const API_VERSION = '2014-01-31';
  27. /**
  28. * the base url for all api calls
  29. */
  30. const API_URL_BASE = 'api.stripe.com/';
  31. /**
  32. * the api protocol
  33. */
  34. const API_URL_PROTOCOL = 'https';
  35. /**
  36. * api get request
  37. */
  38. const API_REQUEST_GET = 'get';
  39. /**
  40. * api post request
  41. */
  42. const API_REQUEST_POST = 'post';
  43. /**
  44. * api delete request
  45. */
  46. const API_REQUEST_DELETE = 'delete';
  47. /**
  48. * api charge method
  49. */
  50. const API_METHOD_CHARGES = 'charges';
  51. /**
  52. * @var ContainerInterface
  53. */
  54. private $container = null;
  55. /**
  56. * @var string
  57. */
  58. private $api_key;
  59. /**
  60. * @var boolean
  61. */
  62. private $verify_ssl_certificates;
  63. /**
  64. * @var boolean
  65. */
  66. private $log_activity;
  67. /**
  68. * @param ContainerInterface $container
  69. */
  70. public function __construct(ContainerInterface $container = null)
  71. {
  72. $this->setContainer($container);
  73. $this->api_key = $container->getParameter('scribe_stripe.api_key');
  74. $this->verify_ssl_certificates = $container->getParameter('scribe_stripe.verify_ssl_certificates');
  75. $this->log_activity = $container->getParameter('scribe_stripe.log_activity');
  76. }
  77. /**
  78. * @param ContainerInterface $container
  79. * @return Stripe
  80. */
  81. public function setContainer(ContainerInterface $container = null)
  82. {
  83. $this->container = $container;
  84. return $this;
  85. }
  86. /**
  87. * @param string $method
  88. * @return string
  89. */
  90. private function buildApiBaseUrl($method, $get = null)
  91. {
  92. $url = self::API_URL_PROTOCOL . '://' . self::API_URL_BASE . 'v1/' . $method;
  93. if ($get !== null) {
  94. $url = $url . '/' . $get;
  95. }
  96. return $url;
  97. }
  98. /**
  99. * @param array $data
  100. * @param null|string $prefix
  101. * @return string
  102. */
  103. private function urlEncodeData(array $data = array(), $prefix = null)
  104. {
  105. $parameters = [];
  106. foreach ($data as $key => $value) {
  107. if (is_null($value)) {
  108. continue;
  109. }
  110. if ($prefix !== null && $key && !is_int($key)) {
  111. $key = $prefix . '[' . $key . ']';
  112. } else if ($prefix !== null) {
  113. $key = $prefix . '[]';
  114. }
  115. if (is_array($value)) {
  116. $parameters[] = $this->urlEncodeData($value, $key);
  117. } else {
  118. $parameters[] = urlencode($key) . '=' . urlencode($value);
  119. }
  120. }
  121. return implode('&', $parameters);
  122. }
  123. /**
  124. * @param string $response
  125. * @param mixed $code
  126. * @return string
  127. */
  128. private function interpretResponse($response, $code)
  129. {
  130. try {
  131. $response_decoded = json_decode($response, true);
  132. } catch (\Exception $e) {
  133. throw new StripeException('Invalid response body from API (HTTP code ' . $code . '): ' . $response);
  134. }
  135. if ($code < 200 || $code >= 300) {
  136. $this->handleApiError($response, $response_decoded, $code);
  137. }
  138. return $response_decoded;
  139. }
  140. /**
  141. * @param string $response
  142. * @param object $response_decoded
  143. * @param mixed $code
  144. */
  145. private function handleApiError($response, $response_decoded, $code)
  146. {
  147. if (!is_array($response_decoded) || !isset($response_decoded['error'])) {
  148. throw new StripeException('Invalid response object from API (HTTP code ' . $code . ')');
  149. }
  150. $error = $response_decoded['error'];
  151. $error_message = isset($error['message']) ? $error['message'] : 'No additional details...';
  152. switch ($code) {
  153. case 400:
  154. case 404:
  155. throw new StripeException('Invalid request: ' . $error_message);
  156. break;
  157. case 401:
  158. throw new StripeException('Authentication error: ' . $error_message);
  159. break;
  160. case 402:
  161. throw new StripeException('Card error: ' . $error_message);
  162. break;
  163. default:
  164. throw new StripeException('General API Error: ' . $error_message);
  165. break;
  166. }
  167. }
  168. /**
  169. * @throws StripeException
  170. * @param mixed $error_number
  171. * @param string $error_message
  172. */
  173. private function handleCurlError($error_number, $error_message)
  174. {
  175. switch ($error_number) {
  176. case CURLE_COULDNT_CONNECT:
  177. case CURLE_COULDNT_RESOLVE_HOST:
  178. case CURLE_OPERATION_TIMEOUTED:
  179. $display_message = 'Could not connect to stripe. Please check your internet connection and try again.';
  180. break;
  181. case CURLE_SSL_CACERT:
  182. case CURLE_SSL_PEER_CERTIFICATE:
  183. case 77:
  184. $display_message = 'Error during the request with the peer certificate or CA cert.';
  185. break;
  186. default:
  187. $display_message = 'Unexpected error communicating with Stripe.';
  188. break;
  189. }
  190. throw new StripeException('Curl network error #' . $error_number . ': ' . $display_message . ' (' . $error_message . ')');
  191. }
  192. /**
  193. * @throws StripeException
  194. * @param string $method
  195. * @param string $type
  196. * @param array $data
  197. * @return array
  198. */
  199. protected function request($method, $type, array $data = array(), $get = null)
  200. {
  201. $user_agent = [
  202. 'bindings_version' => self::BUNDLE_VERSION,
  203. 'lang' => 'php',
  204. 'lang_version' => PHP_VERSION,
  205. 'publisher' => 'scribe',
  206. 'uname' => php_uname(),
  207. ];
  208. $headers = [
  209. 'X-Stripe-Client-User-Agent: ' . json_encode($user_agent),
  210. 'User-Agent: Stripe/v1 ScribeStripeBundle/' . self::BUNDLE_VERSION,
  211. 'Authorization: Bearer ' . $this->api_key,
  212. 'Stripe-Version: ' . self::API_VERSION
  213. ];
  214. list($response, $code)
  215. = $this->curlRequest($method, $type, $data, $get, $headers)
  216. ;
  217. return $this->interpretResponse($response, $code);
  218. }
  219. /**
  220. * @throws StripeException
  221. * @param string $method
  222. * @param string $type
  223. * @param array $data
  224. * @param array $headers
  225. * @return array
  226. */
  227. private function curlRequest($method, $type, array $data = array(), $get = null, array $headers = array())
  228. {
  229. if (!extension_loaded('curl')) {
  230. throw new StripeException('Stripe requires the Curl PHP module is loaded');
  231. }
  232. $url = $this->buildApiBaseUrl($method, $get);
  233. $handle = curl_init($url);
  234. if ($type === self::API_REQUEST_GET) {
  235. curl_setopt($handle, CURLOPT_HTTPGET, 1);
  236. if (count($data) > 0) {
  237. $url = $url . '?' . $this->urlEncodeData($data);
  238. }
  239. } else if ($type === self::API_REQUEST_POST) {
  240. curl_setopt($handle, CURLOPT_POST, 1);
  241. curl_setopt($handle, CURLOPT_POSTFIELDS, $this->urlEncodeData($data));
  242. } else if ($type === self::API_REQUEST_DELETE) {
  243. curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'DELETE');
  244. if (count($data) > 0) {
  245. $url = $url . '?' . $this->urlEncodeData($data);
  246. }
  247. } else {
  248. throw new StripeException('Unknown API request type ' . $type);
  249. }
  250. curl_setopt($handle, CURLOPT_URL, $url);
  251. curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
  252. curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 30);
  253. curl_setopt($handle, CURLOPT_TIMEOUT , 90);
  254. curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
  255. if ($this->verify_ssl_certificates === false) {
  256. curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
  257. }
  258. $response = curl_exec($handle);
  259. $response_code = curl_getinfo($handle, CURLINFO_HTTP_CODE);
  260. $error_number = curl_errno($handle);
  261. $error_message = curl_error($handle);
  262. if ($response === false) {
  263. $this->handleCurlError($error_number, $error_message);
  264. }
  265. curl_close($handle);
  266. return [
  267. $response,
  268. $response_code,
  269. ];
  270. }
  271. }