These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace DrewM\MailChimp; |
||
4 | |||
5 | /** |
||
6 | * Super-simple, minimum abstraction MailChimp API v3 wrapper |
||
7 | * MailChimp API v3: http://developer.mailchimp.com |
||
8 | * This wrapper: https://github.com/drewm/mailchimp-api |
||
9 | * |
||
10 | * @author Drew McLellan <[email protected]> |
||
11 | * @version 2.2 |
||
12 | */ |
||
13 | class MailChimp |
||
14 | { |
||
15 | private $api_key; |
||
16 | private $api_endpoint = 'https://<dc>.api.mailchimp.com/3.0'; |
||
17 | |||
18 | /* SSL Verification |
||
19 | Read before disabling: |
||
20 | http://snippets.webaware.com.au/howto/stop-turning-off-curlopt_ssl_verifypeer-and-fix-your-php-config/ |
||
21 | */ |
||
22 | public $verify_ssl = true; |
||
23 | |||
24 | private $request_successful = false; |
||
25 | private $last_error = ''; |
||
26 | private $last_response = array(); |
||
27 | private $last_request = array(); |
||
28 | |||
29 | /** |
||
30 | * Create a new instance |
||
31 | * @param string $api_key Your MailChimp API key |
||
32 | * @throws \Exception |
||
33 | */ |
||
34 | public function __construct($api_key) |
||
35 | { |
||
36 | $this->api_key = $api_key; |
||
37 | |||
38 | if (strpos($this->api_key, '-') === false) { |
||
39 | throw new \Exception('Invalid MailChimp API key supplied.'); |
||
40 | } |
||
41 | |||
42 | list(, $data_center) = explode('-', $this->api_key); |
||
43 | $this->api_endpoint = str_replace('<dc>', $data_center, $this->api_endpoint); |
||
44 | |||
45 | $this->last_response = array('headers' => null, 'body' => null); |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * Create a new instance of a Batch request. Optionally with the ID of an existing batch. |
||
50 | * @param string $batch_id Optional ID of an existing batch, if you need to check its status for example. |
||
51 | * @return Batch New Batch object. |
||
52 | */ |
||
53 | public function new_batch($batch_id = null) |
||
54 | { |
||
55 | return new Batch($this, $batch_id); |
||
56 | } |
||
57 | |||
58 | /** |
||
59 | * Convert an email address into a 'subscriber hash' for identifying the subscriber in a method URL |
||
60 | * @param string $email The subscriber's email address |
||
61 | * @return string Hashed version of the input |
||
62 | */ |
||
63 | public function subscriberHash($email) |
||
64 | { |
||
65 | return md5(strtolower($email)); |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * Was the last request successful? |
||
70 | * @return bool True for success, false for failure |
||
71 | */ |
||
72 | public function success() |
||
73 | { |
||
74 | return $this->request_successful; |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * Get the last error returned by either the network transport, or by the API. |
||
79 | * If something didn't work, this should contain the string describing the problem. |
||
80 | * @return array|false describing the error |
||
81 | */ |
||
82 | public function getLastError() |
||
83 | { |
||
84 | return $this->last_error ?: false; |
||
85 | } |
||
86 | |||
87 | /** |
||
88 | * Get an array containing the HTTP headers and the body of the API response. |
||
89 | * @return array Assoc array with keys 'headers' and 'body' |
||
90 | */ |
||
91 | public function getLastResponse() |
||
92 | { |
||
93 | return $this->last_response; |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * Get an array containing the HTTP headers and the body of the API request. |
||
98 | * @return array Assoc array |
||
99 | */ |
||
100 | public function getLastRequest() |
||
101 | { |
||
102 | return $this->last_request; |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * Make an HTTP DELETE request - for deleting data |
||
107 | * @param string $method URL of the API request method |
||
108 | * @param array $args Assoc array of arguments (if any) |
||
109 | * @param int $timeout Timeout limit for request in seconds |
||
110 | * @return array|false Assoc array of API response, decoded from JSON |
||
111 | */ |
||
112 | public function delete($method, $args = array(), $timeout = 10) |
||
113 | { |
||
114 | return $this->makeRequest('delete', $method, $args, $timeout); |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Make an HTTP GET request - for retrieving data |
||
119 | * @param string $method URL of the API request method |
||
120 | * @param array $args Assoc array of arguments (usually your data) |
||
121 | * @param int $timeout Timeout limit for request in seconds |
||
122 | * @return array|false Assoc array of API response, decoded from JSON |
||
123 | */ |
||
124 | public function get($method, $args = array(), $timeout = 10) |
||
125 | { |
||
126 | return $this->makeRequest('get', $method, $args, $timeout); |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Make an HTTP PATCH request - for performing partial updates |
||
131 | * @param string $method URL of the API request method |
||
132 | * @param array $args Assoc array of arguments (usually your data) |
||
133 | * @param int $timeout Timeout limit for request in seconds |
||
134 | * @return array|false Assoc array of API response, decoded from JSON |
||
135 | */ |
||
136 | public function patch($method, $args = array(), $timeout = 10) |
||
137 | { |
||
138 | return $this->makeRequest('patch', $method, $args, $timeout); |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Make an HTTP POST request - for creating and updating items |
||
143 | * @param string $method URL of the API request method |
||
144 | * @param array $args Assoc array of arguments (usually your data) |
||
145 | * @param int $timeout Timeout limit for request in seconds |
||
146 | * @return array|false Assoc array of API response, decoded from JSON |
||
147 | */ |
||
148 | public function post($method, $args = array(), $timeout = 10) |
||
149 | { |
||
150 | return $this->makeRequest('post', $method, $args, $timeout); |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * Make an HTTP PUT request - for creating new items |
||
155 | * @param string $method URL of the API request method |
||
156 | * @param array $args Assoc array of arguments (usually your data) |
||
157 | * @param int $timeout Timeout limit for request in seconds |
||
158 | * @return array|false Assoc array of API response, decoded from JSON |
||
159 | */ |
||
160 | public function put($method, $args = array(), $timeout = 10) |
||
161 | { |
||
162 | return $this->makeRequest('put', $method, $args, $timeout); |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * Performs the underlying HTTP request. Not very exciting. |
||
167 | * @param string $http_verb The HTTP verb to use: get, post, put, patch, delete |
||
168 | * @param string $method The API method to be called |
||
169 | * @param array $args Assoc array of parameters to be passed |
||
170 | * @param int $timeout |
||
171 | * @return array|false Assoc array of decoded result |
||
172 | * @throws \Exception |
||
173 | */ |
||
174 | private function makeRequest($http_verb, $method, $args = array(), $timeout = 10) |
||
175 | { |
||
176 | if (!function_exists('curl_init') || !function_exists('curl_setopt')) { |
||
177 | throw new \Exception("cURL support is required, but can't be found."); |
||
178 | } |
||
179 | |||
180 | $url = $this->api_endpoint . '/' . $method; |
||
181 | |||
182 | $this->last_error = ''; |
||
183 | $this->request_successful = false; |
||
184 | $response = array('headers' => null, 'body' => null); |
||
185 | $this->last_response = $response; |
||
186 | |||
187 | $this->last_request = array( |
||
188 | 'method' => $http_verb, |
||
189 | 'path' => $method, |
||
190 | 'url' => $url, |
||
191 | 'body' => '', |
||
192 | 'timeout' => $timeout, |
||
193 | ); |
||
194 | |||
195 | $ch = curl_init(); |
||
196 | curl_setopt($ch, CURLOPT_URL, $url); |
||
197 | curl_setopt($ch, CURLOPT_HTTPHEADER, array( |
||
198 | 'Accept: application/vnd.api+json', |
||
199 | 'Content-Type: application/vnd.api+json', |
||
200 | 'Authorization: apikey ' . $this->api_key |
||
201 | )); |
||
202 | curl_setopt($ch, CURLOPT_USERAGENT, 'DrewM/MailChimp-API/3.0 (github.com/drewm/mailchimp-api)'); |
||
203 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
||
204 | curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); |
||
205 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->verify_ssl); |
||
206 | curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); |
||
207 | curl_setopt($ch, CURLOPT_ENCODING, ''); |
||
208 | curl_setopt($ch, CURLINFO_HEADER_OUT, true); |
||
209 | |||
210 | switch ($http_verb) { |
||
211 | case 'post': |
||
212 | curl_setopt($ch, CURLOPT_POST, true); |
||
213 | $this->attachRequestPayload($ch, $args); |
||
214 | break; |
||
215 | |||
216 | case 'get': |
||
217 | $query = http_build_query($args); |
||
218 | curl_setopt($ch, CURLOPT_URL, $url . '?' . $query); |
||
219 | break; |
||
220 | |||
221 | case 'delete': |
||
222 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); |
||
223 | break; |
||
224 | |||
225 | case 'patch': |
||
226 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH'); |
||
227 | $this->attachRequestPayload($ch, $args); |
||
228 | break; |
||
229 | |||
230 | case 'put': |
||
231 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); |
||
232 | $this->attachRequestPayload($ch, $args); |
||
233 | break; |
||
234 | } |
||
235 | |||
236 | $response['body'] = curl_exec($ch); |
||
237 | $response['headers'] = curl_getinfo($ch); |
||
238 | |||
239 | if (isset($response['headers']['request_header'])) { |
||
240 | $this->last_request['headers'] = $response['headers']['request_header']; |
||
241 | } |
||
242 | |||
243 | if ($response['body'] === false) { |
||
244 | $this->last_error = curl_error($ch); |
||
245 | } |
||
246 | |||
247 | curl_close($ch); |
||
248 | |||
249 | $formattedResponse = $this->formatResponse($response); |
||
250 | |||
251 | $this->determineSuccess($response, $formattedResponse); |
||
0 ignored issues
–
show
|
|||
252 | |||
253 | return $formattedResponse; |
||
254 | } |
||
255 | |||
256 | /** |
||
257 | * Encode the data and attach it to the request |
||
258 | * @param resource $ch cURL session handle, used by reference |
||
259 | * @param array $data Assoc array of data to attach |
||
260 | */ |
||
261 | private function attachRequestPayload(&$ch, $data) |
||
262 | { |
||
263 | $encoded = json_encode($data); |
||
264 | $this->last_request['body'] = $encoded; |
||
265 | curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded); |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Decode the response and format any error messages for debugging |
||
270 | * @param array $response The response from the curl request |
||
271 | * @return array|bool The JSON decoded into an array |
||
272 | */ |
||
273 | private function formatResponse($response) |
||
274 | { |
||
275 | $this->last_response = $response; |
||
276 | |||
277 | if (!empty($response['body'])) { |
||
278 | return json_decode($response['body'], true); |
||
279 | } |
||
280 | |||
281 | return false; |
||
282 | } |
||
283 | |||
284 | /** |
||
285 | * Check if the response was successful or a failure. If it failed, store the error. |
||
286 | * @param array $response The response from the curl request |
||
287 | * @param array $formattedResponse The response body payload from the curl request |
||
288 | * @return bool If the request was successful |
||
289 | */ |
||
290 | private function determineSuccess($response, $formattedResponse) |
||
291 | { |
||
292 | $status = $this->findHTTPStatus($response, $formattedResponse); |
||
293 | |||
294 | if ($status >= 200 && $status <= 299) { |
||
295 | $this->request_successful = true; |
||
296 | return true; |
||
297 | } |
||
298 | |||
299 | if (isset($formattedResponse['detail'])) { |
||
300 | $this->last_error = sprintf('%d: %s', $formattedResponse['status'], $formattedResponse['detail']); |
||
301 | return false; |
||
302 | } |
||
303 | |||
304 | $this->last_error = 'Unknown error, call getLastResponse() to find out what happened.'; |
||
305 | return false; |
||
306 | } |
||
307 | |||
308 | /** |
||
309 | * Find the HTTP status code from the headers or API response body |
||
310 | * @param array $response The response from the curl request |
||
311 | * @param array $formattedResponse The response body payload from the curl request |
||
312 | * @return int HTTP status code |
||
313 | */ |
||
314 | private function findHTTPStatus($response, $formattedResponse) |
||
315 | { |
||
316 | if (!empty($response['body']) && isset($formattedResponse['status'])) { |
||
317 | return (int) $formattedResponse['status']; |
||
318 | } |
||
319 | |||
320 | if (!empty($response['headers']) && isset($response['headers']['http_code'])) { |
||
321 | return (int) $response['headers']['http_code']; |
||
322 | } |
||
323 | |||
324 | return 418; |
||
325 | } |
||
326 | } |
||
327 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.