PageRenderTime 25ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/HttpClient/Curl.php

http://github.com/hybridauth/hybridauth
PHP | 316 lines | 158 code | 43 blank | 115 comment | 10 complexity | b58e3a620c461690b4a8abb0dcc2dfc4 MD5 | raw file
  1. <?php
  2. /*!
  3. * Hybridauth
  4. * https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
  5. * (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
  6. */
  7. namespace Hybridauth\HttpClient;
  8. /**
  9. * Hybridauth default Http client
  10. */
  11. class Curl implements HttpClientInterface
  12. {
  13. /**
  14. * Default curl options
  15. *
  16. * These defaults options can be overwritten when sending requests.
  17. *
  18. * See setCurlOptions()
  19. *
  20. * @var array
  21. */
  22. protected $curlOptions = [
  23. CURLOPT_TIMEOUT => 30,
  24. CURLOPT_CONNECTTIMEOUT => 30,
  25. CURLOPT_SSL_VERIFYPEER => false,
  26. CURLOPT_SSL_VERIFYHOST => false,
  27. CURLOPT_RETURNTRANSFER => true,
  28. CURLOPT_FOLLOWLOCATION => true,
  29. CURLOPT_MAXREDIRS => 5,
  30. CURLINFO_HEADER_OUT => true,
  31. CURLOPT_ENCODING => 'identity',
  32. // phpcs:ignore
  33. CURLOPT_USERAGENT => 'Hybridauth, PHP Social Authentication Library (https://github.com/hybridauth/hybridauth)',
  34. ];
  35. /**
  36. * Method request() arguments
  37. *
  38. * This is used for debugging.
  39. *
  40. * @var array
  41. */
  42. protected $requestArguments = [];
  43. /**
  44. * Default request headers
  45. *
  46. * @var array
  47. */
  48. protected $requestHeader = [
  49. 'Accept' => '*/*',
  50. 'Cache-Control' => 'max-age=0',
  51. 'Connection' => 'keep-alive',
  52. 'Expect' => '',
  53. 'Pragma' => '',
  54. ];
  55. /**
  56. * Raw response returned by server
  57. *
  58. * @var string
  59. */
  60. protected $responseBody = '';
  61. /**
  62. * Headers returned in the response
  63. *
  64. * @var array
  65. */
  66. protected $responseHeader = [];
  67. /**
  68. * Response HTTP status code
  69. *
  70. * @var int
  71. */
  72. protected $responseHttpCode = 0;
  73. /**
  74. * Last curl error number
  75. *
  76. * @var mixed
  77. */
  78. protected $responseClientError = null;
  79. /**
  80. * Information about the last transfer
  81. *
  82. * @var mixed
  83. */
  84. protected $responseClientInfo = [];
  85. /**
  86. * Hybridauth logger instance
  87. *
  88. * @var object
  89. */
  90. protected $logger = null;
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public function request($uri, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
  95. {
  96. $this->requestHeader = array_replace($this->requestHeader, (array)$headers);
  97. $this->requestArguments = [
  98. 'uri' => $uri,
  99. 'method' => $method,
  100. 'parameters' => $parameters,
  101. 'headers' => $this->requestHeader,
  102. ];
  103. $curl = curl_init();
  104. switch ($method) {
  105. case 'GET':
  106. case 'DELETE':
  107. unset($this->curlOptions[CURLOPT_POST]);
  108. unset($this->curlOptions[CURLOPT_POSTFIELDS]);
  109. $uri = $uri . (strpos($uri, '?') ? '&' : '?') . http_build_query($parameters);
  110. if ($method === 'DELETE') {
  111. $this->curlOptions[CURLOPT_CUSTOMREQUEST] = 'DELETE';
  112. }
  113. break;
  114. case 'PUT':
  115. case 'POST':
  116. case 'PATCH':
  117. $body_content = $multipart ? $parameters : http_build_query($parameters);
  118. if (isset($this->requestHeader['Content-Type'])
  119. && $this->requestHeader['Content-Type'] == 'application/json'
  120. ) {
  121. $body_content = json_encode($parameters);
  122. }
  123. if ($method === 'POST') {
  124. $this->curlOptions[CURLOPT_POST] = true;
  125. } else {
  126. $this->curlOptions[CURLOPT_CUSTOMREQUEST] = $method;
  127. }
  128. $this->curlOptions[CURLOPT_POSTFIELDS] = $body_content;
  129. break;
  130. }
  131. $this->curlOptions[CURLOPT_URL] = $uri;
  132. $this->curlOptions[CURLOPT_HTTPHEADER] = $this->prepareRequestHeaders();
  133. $this->curlOptions[CURLOPT_HEADERFUNCTION] = [$this, 'fetchResponseHeader'];
  134. foreach ($this->curlOptions as $opt => $value) {
  135. curl_setopt($curl, $opt, $value);
  136. }
  137. $response = curl_exec($curl);
  138. $this->responseBody = $response;
  139. $this->responseHttpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  140. $this->responseClientError = curl_error($curl);
  141. $this->responseClientInfo = curl_getinfo($curl);
  142. if ($this->logger) {
  143. // phpcs:ignore
  144. $this->logger->debug(sprintf('%s::request( %s, %s ), response:', get_class($this), $uri, $method), $this->getResponse());
  145. if (false === $response) {
  146. // phpcs:ignore
  147. $this->logger->error(sprintf('%s::request( %s, %s ), error:', get_class($this), $uri, $method), [$this->responseClientError]);
  148. }
  149. }
  150. curl_close($curl);
  151. return $this->responseBody;
  152. }
  153. /**
  154. * Get response details
  155. *
  156. * @return array Map structure of details
  157. */
  158. public function getResponse()
  159. {
  160. $curlOptions = $this->curlOptions;
  161. $curlOptions[CURLOPT_HEADERFUNCTION] = '*omitted';
  162. return [
  163. 'request' => $this->getRequestArguments(),
  164. 'response' => [
  165. 'code' => $this->getResponseHttpCode(),
  166. 'headers' => $this->getResponseHeader(),
  167. 'body' => $this->getResponseBody(),
  168. ],
  169. 'client' => [
  170. 'error' => $this->getResponseClientError(),
  171. 'info' => $this->getResponseClientInfo(),
  172. 'opts' => $curlOptions,
  173. ],
  174. ];
  175. }
  176. /**
  177. * Reset curl options
  178. *
  179. * @param array $curlOptions
  180. */
  181. public function setCurlOptions($curlOptions)
  182. {
  183. foreach ($curlOptions as $opt => $value) {
  184. $this->curlOptions[$opt] = $value;
  185. }
  186. }
  187. /**
  188. * Set logger instance
  189. *
  190. * @param object $logger
  191. */
  192. public function setLogger($logger)
  193. {
  194. $this->logger = $logger;
  195. }
  196. /**
  197. * {@inheritdoc}
  198. */
  199. public function getResponseBody()
  200. {
  201. return $this->responseBody;
  202. }
  203. /**
  204. * {@inheritdoc}
  205. */
  206. public function getResponseHeader()
  207. {
  208. return $this->responseHeader;
  209. }
  210. /**
  211. * {@inheritdoc}
  212. */
  213. public function getResponseHttpCode()
  214. {
  215. return $this->responseHttpCode;
  216. }
  217. /**
  218. * {@inheritdoc}
  219. */
  220. public function getResponseClientError()
  221. {
  222. return $this->responseClientError;
  223. }
  224. /**
  225. * @return array
  226. */
  227. protected function getResponseClientInfo()
  228. {
  229. return $this->responseClientInfo;
  230. }
  231. /**
  232. * Returns method request() arguments
  233. *
  234. * This is used for debugging.
  235. *
  236. * @return array
  237. */
  238. protected function getRequestArguments()
  239. {
  240. return $this->requestArguments;
  241. }
  242. /**
  243. * Fetch server response headers
  244. *
  245. * @param mixed $curl
  246. * @param string $header
  247. *
  248. * @return int
  249. */
  250. protected function fetchResponseHeader($curl, $header)
  251. {
  252. $pos = strpos($header, ':');
  253. if (!empty($pos)) {
  254. $key = str_replace('-', '_', strtolower(substr($header, 0, $pos)));
  255. $value = trim(substr($header, $pos + 2));
  256. $this->responseHeader[$key] = $value;
  257. }
  258. return strlen($header);
  259. }
  260. /**
  261. * Convert request headers to the expect curl format
  262. *
  263. * @return array
  264. */
  265. protected function prepareRequestHeaders()
  266. {
  267. $headers = [];
  268. foreach ($this->requestHeader as $header => $value) {
  269. $headers[] = trim($header) . ': ' . trim($value);
  270. }
  271. return $headers;
  272. }
  273. }