PPPStripeHttpClientCurlClient

The Gravity Forms + Stripe PPP Stripe HttpClient CurlClient class.

Defined (1)

The class is defined in the following location(s).

/includes/api/stripe-php/lib/HttpClient/CurlClient.php  
  1. class CurlClient implements ClientInterface 
  2. private static $instance; 
  3.  
  4. public static function instance() 
  5. if (!self::$instance) { 
  6. self::$instance = new self(); 
  7. return self::$instance; 
  8.  
  9. protected $defaultOptions; 
  10.  
  11. /** 
  12. * CurlClient constructor. 
  13. * Pass in a callable to $defaultOptions that returns an array of CURLOPT_* values to start 
  14. * off a request with, or an flat array with the same format used by curl_setopt_array() to 
  15. * provide a static set of options. Note that many options are overridden later in the request 
  16. * call, including timeouts, which can be set via setTimeout() and setConnectTimeout(). 
  17. * Note that request() will silently ignore a non-callable, non-array $defaultOptions, and will 
  18. * throw an exception if $defaultOptions returns a non-array value. 
  19. * @param array|callable|null $defaultOptions 
  20. */ 
  21. public function __construct($defaultOptions = null) 
  22. $this->defaultOptions = $defaultOptions; 
  23.  
  24. public function getDefaultOptions() 
  25. return $this->defaultOptions; 
  26.  
  27. // USER DEFINED TIMEOUTS 
  28.  
  29. const DEFAULT_TIMEOUT = 80; 
  30. const DEFAULT_CONNECT_TIMEOUT = 30; 
  31.  
  32. private $timeout = self::DEFAULT_TIMEOUT; 
  33. private $connectTimeout = self::DEFAULT_CONNECT_TIMEOUT; 
  34.  
  35. public function setTimeout($seconds) 
  36. $this->timeout = (int) max($seconds, 0); 
  37. return $this; 
  38.  
  39. public function setConnectTimeout($seconds) 
  40. $this->connectTimeout = (int) max($seconds, 0); 
  41. return $this; 
  42.  
  43. public function getTimeout() 
  44. return $this->timeout; 
  45.  
  46. public function getConnectTimeout() 
  47. return $this->connectTimeout; 
  48.  
  49. // END OF USER DEFINED TIMEOUTS 
  50.  
  51. public function request($method, $absUrl, $headers, $params, $hasFile) 
  52. $curl = curl_init(); 
  53. $method = strtolower($method); 
  54.  
  55. $opts = array(); 
  56. if (is_callable($this->defaultOptions)) { // call defaultOptions callback, set options to return value 
  57. $opts = call_user_func_array($this->defaultOptions, func_get_args()); 
  58. if (!is_array($opts)) { 
  59. throw new Error\Api("Non-array value returned by defaultOptions CurlClient callback"); 
  60. } elseif (is_array($this->defaultOptions)) { // set default curlopts from array 
  61. $opts = $this->defaultOptions; 
  62.  
  63. if ($method == 'get') { 
  64. if ($hasFile) { 
  65. throw new Error\Api( 
  66. "Issuing a GET request with a file parameter" 
  67. ); 
  68. $opts[CURLOPT_HTTPGET] = 1; 
  69. if (count($params) > 0) { 
  70. $encoded = self::encode($params); 
  71. $absUrl = "$absUrl?$encoded"; 
  72. } elseif ($method == 'post') { 
  73. $opts[CURLOPT_POST] = 1; 
  74. $opts[CURLOPT_POSTFIELDS] = $hasFile ? $params : self::encode($params); 
  75. } elseif ($method == 'delete') { 
  76. $opts[CURLOPT_CUSTOMREQUEST] = 'DELETE'; 
  77. if (count($params) > 0) { 
  78. $encoded = self::encode($params); 
  79. $absUrl = "$absUrl?$encoded"; 
  80. } else { 
  81. throw new Error\Api("Unrecognized method $method"); 
  82.  
  83. // Create a callback to capture HTTP headers for the response 
  84. $rheaders = array(); 
  85. $headerCallback = function ($curl, $header_line) use (&$rheaders) { 
  86. // Ignore the HTTP request line (HTTP/1.1 200 OK) 
  87. if (strpos($header_line, ":") === false) { 
  88. return strlen($header_line); 
  89. list($key, $value) = explode(":", trim($header_line), 2); 
  90. $rheaders[trim($key)] = trim($value); 
  91. return strlen($header_line); 
  92. }; 
  93.  
  94. // By default for large request body sizes (> 1024 bytes), cURL will 
  95. // send a request without a body and with a `Expect: 100-continue` 
  96. // header, which gives the server a chance to respond with an error 
  97. // status code in cases where one can be determined right away (say 
  98. // on an authentication problem for example), and saves the "large" 
  99. // request body from being ever sent. 
  100. // 
  101. // Unfortunately, the bindings don't currently correctly handle the 
  102. // success case (in which the server sends back a 100 CONTINUE), so 
  103. // we'll error under that condition. To compensate for that problem 
  104. // for the time being, override cURL's behavior by simply always 
  105. // sending an empty `Expect:` header. 
  106. array_push($headers, 'Expect: '); 
  107.  
  108. $absUrl = Util\Util::utf8($absUrl); 
  109. $opts[CURLOPT_URL] = $absUrl; 
  110. $opts[CURLOPT_RETURNTRANSFER] = true; 
  111. $opts[CURLOPT_CONNECTTIMEOUT] = $this->connectTimeout; 
  112. $opts[CURLOPT_TIMEOUT] = $this->timeout; 
  113. $opts[CURLOPT_HEADERFUNCTION] = $headerCallback; 
  114. $opts[CURLOPT_HTTPHEADER] = $headers; 
  115. if (!Stripe::$verifySslCerts) { 
  116. $opts[CURLOPT_SSL_VERIFYPEER] = false; 
  117.  
  118. curl_setopt_array($curl, $opts); 
  119. $rbody = curl_exec($curl); 
  120.  
  121. if (!defined('CURLE_SSL_CACERT_BADFILE')) { 
  122. define('CURLE_SSL_CACERT_BADFILE', 77); // constant not defined in PHP 
  123.  
  124. $errno = curl_errno($curl); 
  125. if ($errno == CURLE_SSL_CACERT || 
  126. $errno == CURLE_SSL_PEER_CERTIFICATE || 
  127. $errno == CURLE_SSL_CACERT_BADFILE 
  128. ) { 
  129. array_push( 
  130. $headers,  
  131. 'X-Stripe-Client-Info: {"ca":"using Stripe-supplied CA bundle"}' 
  132. ); 
  133. $cert = self::caBundle(); 
  134. curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); 
  135. curl_setopt($curl, CURLOPT_CAINFO, $cert); 
  136. $rbody = curl_exec($curl); 
  137.  
  138. if ($rbody === false) { 
  139. $errno = curl_errno($curl); 
  140. $message = curl_error($curl); 
  141. curl_close($curl); 
  142. $this->handleCurlError($absUrl, $errno, $message); 
  143.  
  144. $rcode = curl_getinfo($curl, CURLINFO_HTTP_CODE); 
  145. curl_close($curl); 
  146. return array($rbody, $rcode, $rheaders); 
  147.  
  148. /** 
  149. * @param number $errno 
  150. * @param string $message 
  151. * @throws Error\ApiConnection 
  152. */ 
  153. private function handleCurlError($url, $errno, $message) 
  154. switch ($errno) { 
  155. case CURLE_COULDNT_CONNECT: 
  156. case CURLE_COULDNT_RESOLVE_HOST: 
  157. case CURLE_OPERATION_TIMEOUTED: 
  158. $msg = "Could not connect to Stripe ($url). Please check your " 
  159. . "internet connection and try again. If this problem persists, " 
  160. . "you should check Stripe's service status at " 
  161. . "https://twitter.com/stripestatus, or"; 
  162. break; 
  163. case CURLE_SSL_CACERT: 
  164. case CURLE_SSL_PEER_CERTIFICATE: 
  165. $msg = "Could not verify Stripe's SSL certificate. Please make sure " 
  166. . "that your network is not intercepting certificates. " 
  167. . "(Try going to $url in your browser.) " 
  168. . "If this problem persists, "; 
  169. break; 
  170. default: 
  171. $msg = "Unexpected error communicating with Stripe. " 
  172. . "If this problem persists, "; 
  173. $msg .= " let us know at support@stripe.com."; 
  174.  
  175. $msg .= "\n\n(Network error [errno $errno]: $message)"; 
  176. throw new Error\ApiConnection($msg); 
  177.  
  178. private static function caBundle() 
  179. return dirname(__FILE__) . '/../../data/ca-certificates.crt'; 
  180.  
  181. /** 
  182. * @param array $arr An map of param keys to values. 
  183. * @param string|null $prefix 
  184. * Only public for testability, should not be called outside of CurlClient 
  185. * @return string A querystring, essentially. 
  186. */ 
  187. public static function encode($arr, $prefix = null) 
  188. if (!is_array($arr)) { 
  189. return $arr; 
  190.  
  191. $r = array(); 
  192. foreach ($arr as $k => $v) { 
  193. if (is_null($v)) { 
  194. continue; 
  195.  
  196. if ($prefix) { 
  197. if ($k !== null && (!is_int($k) || is_array($v))) { 
  198. $k = $prefix."[".$k."]"; 
  199. } else { 
  200. $k = $prefix."[]"; 
  201.  
  202. if (is_array($v)) { 
  203. $enc = self::encode($v, $k); 
  204. if ($enc) { 
  205. $r[] = $enc; 
  206. } else { 
  207. $r[] = urlencode($k)."=".urlencode($v); 
  208.  
  209. return implode("&", $r);