/src/Requests/MailchimpConnection.php

https://github.com/Jhut89/Mailchimp-API-3.0-PHP · PHP · 328 lines · 153 code · 45 blank · 130 comment · 9 complexity · baa4eb7f14a5982ab186dace9e1822c7 MD5 · raw file

  1. <?php
  2. namespace MailchimpAPI\Requests;
  3. use MailchimpAPI\MailchimpException;
  4. use MailchimpAPI\Responses\FailureResponse;
  5. use MailchimpAPI\Responses\MailchimpResponse;
  6. use MailchimpAPI\Responses\SuccessResponse;
  7. use MailchimpAPI\Settings\MailchimpSettings;
  8. /**
  9. * Class MailchimpConnection
  10. * @package MailchimpAPI\Requests
  11. */
  12. class MailchimpConnection implements HttpRequest
  13. {
  14. /**
  15. * Custom user agent for this library
  16. */
  17. const USER_AGENT = 'jhut89/Mailchimp-API-3.0-PHP (https://github.com/Jhut89/Mailchimp-API-3.0-PHP)';
  18. /**
  19. * The url used to request an access token from mailchimp
  20. */
  21. const TOKEN_REQUEST_URL = 'https://login.mailchimp.com/oauth2/token';
  22. /**
  23. * The url used to request metadata about an access token
  24. */
  25. const OAUTH_METADATA_URL = 'https://login.mailchimp.com/oauth2/metadata/';
  26. /**
  27. * The current request object passed into this connection
  28. * @var MailchimpRequest
  29. */
  30. private $current_request;
  31. /**
  32. * The current settings object passed into this connection
  33. * @var MailChimpSettings
  34. */
  35. private $current_settings;
  36. /**
  37. * Raw response from mailchimp api
  38. * @var string
  39. */
  40. private $response;
  41. /**
  42. * Response body
  43. * @var string
  44. */
  45. private $response_body;
  46. /**
  47. * An integer representation of the http response code
  48. * @var int
  49. */
  50. private $http_code;
  51. /**
  52. * The parsed response headers from the request
  53. * @var array
  54. */
  55. private $headers = [];
  56. /**
  57. * The curl handle for this connection
  58. * @var resource
  59. */
  60. private $handle;
  61. /**
  62. * A holder for the option that are set on this connections handle
  63. * @var array
  64. */
  65. private $current_options = [];
  66. /**
  67. * MailchimpConnection constructor.
  68. *
  69. * @param MailchimpRequest $request
  70. * @param MailchimpSettings|null $settings
  71. *
  72. * @throws MailchimpException
  73. */
  74. public function __construct(MailchimpRequest &$request, MailchimpSettings &$settings = null)
  75. {
  76. $this->current_request = $request;
  77. $settings ?
  78. $this->current_settings = $settings :
  79. $this->current_settings = new MailchimpSettings();
  80. $this->handle = curl_init();
  81. $this->prepareHandle();
  82. $this->setHandlerOptionsForMethod();
  83. }
  84. /**
  85. * Prepares this connections handle for execution
  86. *
  87. * @return void
  88. *
  89. * @throws MailchimpException
  90. */
  91. private function prepareHandle()
  92. {
  93. // set the URL for this request
  94. $this->setOption(CURLOPT_URL, $this->current_request->getUrl());
  95. // set headers to be sent
  96. $this->setOption(CURLOPT_HTTPHEADER, $this->current_request->getHeaders());
  97. // set custom user-agent
  98. $this->setOption(CURLOPT_USERAGENT, self::USER_AGENT);
  99. // make response returnable
  100. $this->setOption(CURLOPT_RETURNTRANSFER, true);
  101. // get headers in return
  102. $this->setOption(CURLOPT_HEADER, true);
  103. // set verify ssl
  104. $this->setOption(CURLOPT_SSL_VERIFYPEER, $this->current_settings->shouldVerifySsl());
  105. // set the callback to run against each of the response headers
  106. $this->setOption(CURLOPT_HEADERFUNCTION, [&$this, "parseResponseHeader"]);
  107. // if an custom curl settings are present set them now
  108. $this->setCustomHandleOptions($this->current_settings->getCustomCurlSettings());
  109. }
  110. /**
  111. * Set custom curl handler options
  112. *
  113. * @param array $options
  114. */
  115. private function setCustomHandleOptions(array $options)
  116. {
  117. if (!empty($options)) {
  118. foreach ($options as $option => $value) {
  119. $this->setOption($option, $value);
  120. }
  121. }
  122. }
  123. /**
  124. * Prepares the handler for a request based on the requests method
  125. * @return void
  126. */
  127. private function setHandlerOptionsForMethod()
  128. {
  129. $method = $this->current_request->getMethod();
  130. switch ($method) {
  131. case MailchimpRequest::POST:
  132. $this->setOption(CURLOPT_POST, true);
  133. $this->setOption(CURLOPT_POSTFIELDS, $this
  134. ->current_request
  135. ->getPayload());
  136. break;
  137. case MailchimpRequest::PUT:
  138. case MailchimpRequest::PATCH:
  139. $this->setOption(CURLOPT_CUSTOMREQUEST, $method);
  140. $this->setOption(CURLOPT_POSTFIELDS, $this
  141. ->current_request
  142. ->getPayload());
  143. break;
  144. case MailchimpRequest::DELETE:
  145. $this->setOption(CURLOPT_CUSTOMREQUEST, $method);
  146. break;
  147. }
  148. }
  149. /**
  150. * Executes a connection with the current request and settings
  151. *
  152. * @param bool $close close this connection after execution
  153. *
  154. * @return MailchimpResponse
  155. * @throws MailchimpException
  156. */
  157. public function execute($close = true)
  158. {
  159. $this->response = $this->executeCurl();
  160. if (!$this->response) {
  161. throw new MailchimpException("The curl request failed: " . $this->getError());
  162. }
  163. $this->http_code = $this->getInfo(CURLINFO_HTTP_CODE);
  164. $head_len = $this->getInfo(CURLINFO_HEADER_SIZE);
  165. $this->response_body = substr(
  166. $this->response,
  167. $head_len,
  168. strlen($this->response)
  169. );
  170. if ($close) {
  171. $this->close();
  172. }
  173. if ($this->isSuccess()) {
  174. return new SuccessResponse(
  175. $this->headers,
  176. $this->response_body,
  177. $this->http_code,
  178. $this->current_request->getSuccessCallback()
  179. );
  180. } else {
  181. return new FailureResponse(
  182. $this->headers,
  183. $this->response_body,
  184. $this->http_code,
  185. $this->current_request->getFailureCallback()
  186. );
  187. }
  188. }
  189. /**
  190. * Gets the currently set curl options by key
  191. *
  192. * @param $key
  193. *
  194. * @return mixed
  195. */
  196. public function getCurrentOption($key)
  197. {
  198. return $this->current_options[$key];
  199. }
  200. /**
  201. * Bulk set curl options
  202. * Update current settings
  203. *
  204. * @param array $options
  205. */
  206. public function setCurrentOptions($options)
  207. {
  208. $this->current_options = [];
  209. foreach ($options as $option_name => $option_value) {
  210. $this->setOption($option_name, $option_value);
  211. }
  212. }
  213. /**
  214. * Sets a curl option on the handler
  215. * Updates the current settings array with ne setting
  216. * @inheritdoc
  217. */
  218. public function setOption($name, $value)
  219. {
  220. curl_setopt($this->handle, $name, $value);
  221. $this->current_options[$name] = $value;
  222. }
  223. /**
  224. * @inheritdoc
  225. */
  226. public function executeCurl()
  227. {
  228. return curl_exec($this->handle);
  229. }
  230. /**
  231. * @inheritdoc
  232. */
  233. public function getInfo($name)
  234. {
  235. return curl_getinfo($this->handle, $name);
  236. }
  237. /**
  238. * @return string
  239. */
  240. public function getError()
  241. {
  242. return curl_error($this->handle);
  243. }
  244. /**
  245. * @inheritdoc
  246. */
  247. public function close()
  248. {
  249. curl_close($this->handle);
  250. }
  251. /**
  252. * Called statically during prepareHandle();
  253. *
  254. * @param $handle
  255. * @param $header
  256. *
  257. * @return int
  258. */
  259. private function parseResponseHeader($handle, $header)
  260. {
  261. $header_length = strlen($header);
  262. $header_array = explode(':', $header, 2);
  263. if (count($header_array) == 2) {
  264. $this->pushToHeaders($header_array);
  265. }
  266. return $header_length;
  267. }
  268. /**
  269. * @param array $header
  270. */
  271. private function pushToHeaders($header)
  272. {
  273. $this->headers[$header[0]] = trim($header[1]);
  274. }
  275. /**
  276. * A function for evaluating if a connection was successful
  277. * @return bool
  278. */
  279. private function isSuccess()
  280. {
  281. return ($this->http_code > 199 && $this->http_code < 300);
  282. }
  283. }