Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Curl often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Curl, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
5 | class Curl |
||
6 | { |
||
7 | const VERSION = '6.0.0'; |
||
8 | const DEFAULT_TIMEOUT = 30; |
||
9 | |||
10 | public static $RFC2616 = array( |
||
11 | // RFC2616: "any CHAR except CTLs or separators". |
||
12 | // CHAR = <any US-ASCII character (octets 0 - 127)> |
||
13 | // CTL = <any US-ASCII control character |
||
14 | // (octets 0 - 31) and DEL (127)> |
||
|
|||
15 | // separators = "(" | ")" | "<" | ">" | "@" |
||
16 | // | "," | ";" | ":" | "\" | <"> |
||
17 | // | "/" | "[" | "]" | "?" | "=" |
||
18 | // | "{" | "}" | SP | HT |
||
19 | // SP = <US-ASCII SP, space (32)> |
||
20 | // HT = <US-ASCII HT, horizontal-tab (9)> |
||
21 | // <"> = <US-ASCII double-quote mark (34)> |
||
22 | '!', '#', '$', '%', '&', "'", '*', '+', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', |
||
23 | 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', |
||
24 | 'Y', 'Z', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', |
||
25 | 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '|', '~', |
||
26 | ); |
||
27 | public static $RFC6265 = array( |
||
28 | // RFC6265: "US-ASCII characters excluding CTLs, whitespace DQUOTE, comma, semicolon, and backslash". |
||
29 | // %x21 |
||
30 | '!', |
||
31 | // %x23-2B |
||
32 | '#', '$', '%', '&', "'", '(', ')', '*', '+', |
||
33 | // %x2D-3A |
||
34 | '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', |
||
35 | // %x3C-5B |
||
36 | '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', |
||
37 | 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', |
||
38 | // %x5D-7E |
||
39 | ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', |
||
40 | 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', |
||
41 | ); |
||
42 | |||
43 | public $curl; |
||
44 | public $id = null; |
||
45 | |||
46 | public $error = false; |
||
47 | public $errorCode = 0; |
||
48 | public $errorMessage = null; |
||
49 | |||
50 | public $curlError = false; |
||
51 | public $curlErrorCode = 0; |
||
52 | public $curlErrorMessage = null; |
||
53 | |||
54 | public $httpError = false; |
||
55 | public $httpStatusCode = 0; |
||
56 | public $httpErrorMessage = null; |
||
57 | |||
58 | public $baseUrl = null; |
||
59 | public $url = null; |
||
60 | public $requestHeaders = null; |
||
61 | public $responseHeaders = null; |
||
62 | public $rawResponseHeaders = ''; |
||
63 | public $responseCookies = array(); |
||
64 | public $response = null; |
||
65 | public $rawResponse = null; |
||
66 | |||
67 | public $beforeSendFunction = null; |
||
68 | public $downloadCompleteFunction = null; |
||
69 | public $successFunction = null; |
||
70 | public $errorFunction = null; |
||
71 | public $completeFunction = null; |
||
72 | public $fileHandle = null; |
||
73 | |||
74 | private $cookies = array(); |
||
75 | private $headers = array(); |
||
76 | private $options = array(); |
||
77 | |||
78 | private $jsonDecoder = null; |
||
79 | private $jsonPattern = '/^(?:application|text)\/(?:[a-z]+(?:[\.-][0-9a-z]+){0,}[\+\.]|x-)?json(?:-[a-z]+)?/i'; |
||
80 | private $xmlDecoder = null; |
||
81 | private $xmlPattern = '~^(?:text/|application/(?:atom\+|rss\+)?)xml~i'; |
||
82 | private $defaultDecoder = null; |
||
83 | |||
84 | private static $deferredProperties = array( |
||
85 | 'effectiveUrl', |
||
86 | 'totalTime', |
||
87 | ); |
||
88 | |||
89 | /** |
||
90 | * Construct |
||
91 | * |
||
92 | * @access public |
||
93 | * @param $base_url |
||
94 | * @throws \ErrorException |
||
95 | */ |
||
96 | public function __construct($base_url = null) |
||
97 | { |
||
98 | if (!extension_loaded('curl')) { |
||
99 | throw new \ErrorException('cURL library is not loaded'); |
||
100 | } |
||
101 | |||
102 | $this->curl = curl_init(); |
||
103 | $this->id = uniqid('', true); |
||
104 | $this->setDefaultUserAgent(); |
||
105 | $this->setDefaultJsonDecoder(); |
||
106 | $this->setDefaultXmlDecoder(); |
||
107 | $this->setDefaultTimeout(); |
||
108 | $this->setOpt(CURLINFO_HEADER_OUT, true); |
||
109 | $this->setOpt(CURLOPT_HEADERFUNCTION, array($this, 'headerCallback')); |
||
110 | $this->setOpt(CURLOPT_RETURNTRANSFER, true); |
||
111 | $this->headers = new CaseInsensitiveArray(); |
||
112 | $this->setURL($base_url); |
||
113 | $this->rfc2616 = array_fill_keys(self::$RFC2616, true); |
||
114 | $this->rfc6265 = array_fill_keys(self::$RFC6265, true); |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Before Send |
||
119 | * |
||
120 | * @access public |
||
121 | * @param $callback |
||
122 | */ |
||
123 | public function beforeSend($callback) |
||
124 | { |
||
125 | $this->beforeSendFunction = $callback; |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * Build Post Data |
||
130 | * |
||
131 | * @access public |
||
132 | * @param $data |
||
133 | * |
||
134 | * @return array|string |
||
135 | */ |
||
136 | public function buildPostData($data) |
||
137 | { |
||
138 | $binary_data = false; |
||
139 | if (is_array($data)) { |
||
140 | // Return JSON-encoded string when the request's content-type is JSON. |
||
141 | if (isset($this->headers['Content-Type']) && |
||
142 | preg_match($this->jsonPattern, $this->headers['Content-Type'])) { |
||
143 | $json_str = json_encode($data); |
||
144 | if (!($json_str === false)) { |
||
145 | $data = $json_str; |
||
146 | } |
||
147 | } else { |
||
148 | // Manually build a single-dimensional array from a multi-dimensional array as using curl_setopt($ch, |
||
149 | // CURLOPT_POSTFIELDS, $data) doesn't correctly handle multi-dimensional arrays when files are |
||
150 | // referenced. |
||
151 | if (self::is_array_multidim($data)) { |
||
152 | $data = self::array_flatten_multidim($data); |
||
153 | } |
||
154 | |||
155 | // Modify array values to ensure any referenced files are properly handled depending on the support of |
||
156 | // the @filename API or CURLFile usage. This also fixes the warning "curl_setopt(): The usage of the |
||
157 | // @filename API for file uploading is deprecated. Please use the CURLFile class instead". Ignore |
||
158 | // non-file values prefixed with the @ character. |
||
159 | foreach ($data as $key => $value) { |
||
160 | if (is_string($value) && strpos($value, '@') === 0 && is_file(substr($value, 1))) { |
||
161 | $binary_data = true; |
||
162 | if (class_exists('CURLFile')) { |
||
163 | $data[$key] = new \CURLFile(substr($value, 1)); |
||
164 | } |
||
165 | } elseif ($value instanceof \CURLFile) { |
||
166 | $binary_data = true; |
||
167 | } |
||
168 | } |
||
169 | } |
||
170 | } |
||
171 | |||
172 | if (!$binary_data && (is_array($data) || is_object($data))) { |
||
173 | $data = http_build_query($data, '', '&'); |
||
174 | } |
||
175 | |||
176 | return $data; |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Call |
||
181 | * |
||
182 | * @access public |
||
183 | */ |
||
184 | public function call() |
||
185 | { |
||
186 | $args = func_get_args(); |
||
187 | $function = array_shift($args); |
||
188 | if (is_callable($function)) { |
||
189 | array_unshift($args, $this); |
||
190 | call_user_func_array($function, $args); |
||
191 | } |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Close |
||
196 | * |
||
197 | * @access public |
||
198 | */ |
||
199 | public function close() |
||
200 | { |
||
201 | if (is_resource($this->curl)) { |
||
202 | curl_close($this->curl); |
||
203 | } |
||
204 | $this->options = null; |
||
205 | $this->jsonDecoder = null; |
||
206 | $this->xmlDecoder = null; |
||
207 | $this->defaultDecoder = null; |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * Complete |
||
212 | * |
||
213 | * @access public |
||
214 | * @param $callback |
||
215 | */ |
||
216 | public function complete($callback) |
||
217 | { |
||
218 | $this->completeFunction = $callback; |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Progress |
||
223 | * |
||
224 | * @access public |
||
225 | * @param $callback |
||
226 | */ |
||
227 | public function progress($callback) |
||
228 | { |
||
229 | $this->setOpt(CURLOPT_PROGRESSFUNCTION, $callback); |
||
230 | $this->setOpt(CURLOPT_NOPROGRESS, false); |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * Delete |
||
235 | * |
||
236 | * @access public |
||
237 | * @param $url |
||
238 | * @param $query_parameters |
||
239 | * @param $data |
||
240 | * |
||
241 | * @return string |
||
242 | */ |
||
243 | public function delete($url, $query_parameters = array(), $data = array()) |
||
244 | { |
||
245 | if (is_array($url)) { |
||
246 | $data = $query_parameters; |
||
247 | $query_parameters = $url; |
||
248 | $url = $this->baseUrl; |
||
249 | } |
||
250 | |||
251 | $this->setURL($url, $query_parameters); |
||
252 | $this->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE'); |
||
253 | $this->setOpt(CURLOPT_POSTFIELDS, $this->buildPostData($data)); |
||
254 | return $this->exec(); |
||
255 | } |
||
256 | |||
257 | /** |
||
258 | * Download Complete |
||
259 | * |
||
260 | * @access private |
||
261 | * @param $fh |
||
262 | */ |
||
263 | private function downloadComplete($fh) |
||
264 | { |
||
265 | if (!$this->error && $this->downloadCompleteFunction) { |
||
266 | rewind($fh); |
||
267 | $this->call($this->downloadCompleteFunction, $fh); |
||
268 | $this->downloadCompleteFunction = null; |
||
269 | } |
||
270 | |||
271 | if (is_resource($fh)) { |
||
272 | fclose($fh); |
||
273 | } |
||
274 | |||
275 | // Fix "PHP Notice: Use of undefined constant STDOUT" when reading the |
||
276 | // PHP script from stdin. Using null causes "Warning: curl_setopt(): |
||
277 | // supplied argument is not a valid File-Handle resource". |
||
278 | if (!defined('STDOUT')) { |
||
279 | define('STDOUT', fopen('php://stdout', 'w')); |
||
280 | } |
||
281 | |||
282 | // Reset CURLOPT_FILE with STDOUT to avoid: "curl_exec(): CURLOPT_FILE |
||
283 | // resource has gone away, resetting to default". |
||
284 | $this->setOpt(CURLOPT_FILE, STDOUT); |
||
285 | |||
286 | // Reset CURLOPT_RETURNTRANSFER to tell cURL to return subsequent |
||
287 | // responses as the return value of curl_exec(). Without this, |
||
288 | // curl_exec() will revert to returning boolean values. |
||
289 | $this->setOpt(CURLOPT_RETURNTRANSFER, true); |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Download |
||
294 | * |
||
295 | * @access public |
||
296 | * @param $url |
||
297 | * @param $mixed_filename |
||
298 | * |
||
299 | * @return boolean |
||
300 | */ |
||
301 | public function download($url, $mixed_filename) |
||
302 | { |
||
303 | if (is_callable($mixed_filename)) { |
||
304 | $this->downloadCompleteFunction = $mixed_filename; |
||
305 | $fh = tmpfile(); |
||
306 | } else { |
||
307 | $filename = $mixed_filename; |
||
308 | $fh = fopen($filename, 'wb'); |
||
309 | } |
||
310 | |||
311 | $this->setOpt(CURLOPT_FILE, $fh); |
||
312 | $this->get($url); |
||
313 | $this->downloadComplete($fh); |
||
314 | |||
315 | return ! $this->error; |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * Error |
||
320 | * |
||
321 | * @access public |
||
322 | * @param $callback |
||
323 | */ |
||
324 | public function error($callback) |
||
325 | { |
||
326 | $this->errorFunction = $callback; |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * Exec |
||
331 | * |
||
332 | * @access public |
||
333 | * @param $ch |
||
334 | * |
||
335 | * @return mixed Returns the value provided by parseResponse. |
||
336 | */ |
||
337 | public function exec($ch = null) |
||
338 | { |
||
339 | if ($ch === null) { |
||
340 | $this->responseCookies = array(); |
||
341 | $this->call($this->beforeSendFunction); |
||
342 | $this->rawResponse = curl_exec($this->curl); |
||
343 | $this->curlErrorCode = curl_errno($this->curl); |
||
344 | $this->curlErrorMessage = curl_error($this->curl); |
||
345 | } else { |
||
346 | $this->rawResponse = curl_multi_getcontent($ch); |
||
347 | $this->curlErrorMessage = curl_error($ch); |
||
348 | } |
||
349 | $this->curlError = !($this->curlErrorCode === 0); |
||
350 | |||
351 | // Include additional error code information in error message when possible. |
||
352 | if ($this->curlError && function_exists('curl_strerror')) { |
||
353 | $this->curlErrorMessage = |
||
354 | curl_strerror($this->curlErrorCode) . ( |
||
355 | empty($this->curlErrorMessage) ? '' : ': ' . $this->curlErrorMessage |
||
356 | ); |
||
357 | } |
||
358 | |||
359 | $this->httpStatusCode = $this->getInfo(CURLINFO_HTTP_CODE); |
||
360 | $this->httpError = in_array(floor($this->httpStatusCode / 100), array(4, 5)); |
||
361 | $this->error = $this->curlError || $this->httpError; |
||
362 | $this->errorCode = $this->error ? ($this->curlError ? $this->curlErrorCode : $this->httpStatusCode) : 0; |
||
363 | |||
364 | // NOTE: CURLINFO_HEADER_OUT set to true is required for requestHeaders |
||
365 | // to not be empty (e.g. $curl->setOpt(CURLINFO_HEADER_OUT, true);). |
||
366 | if ($this->getOpt(CURLINFO_HEADER_OUT) === true) { |
||
367 | $this->requestHeaders = $this->parseRequestHeaders($this->getInfo(CURLINFO_HEADER_OUT)); |
||
368 | } |
||
369 | $this->responseHeaders = $this->parseResponseHeaders($this->rawResponseHeaders); |
||
370 | $this->response = $this->parseResponse($this->responseHeaders, $this->rawResponse); |
||
371 | |||
372 | $this->httpErrorMessage = ''; |
||
373 | if ($this->error) { |
||
374 | if (isset($this->responseHeaders['Status-Line'])) { |
||
375 | $this->httpErrorMessage = $this->responseHeaders['Status-Line']; |
||
376 | } |
||
377 | } |
||
378 | $this->errorMessage = $this->curlError ? $this->curlErrorMessage : $this->httpErrorMessage; |
||
379 | |||
380 | if (!$this->error) { |
||
381 | $this->call($this->successFunction); |
||
382 | } else { |
||
383 | $this->call($this->errorFunction); |
||
384 | } |
||
385 | |||
386 | $this->call($this->completeFunction); |
||
387 | |||
388 | // Close open file handles and reset the curl instance. |
||
389 | if (!($this->fileHandle === null)) { |
||
390 | $this->downloadComplete($this->fileHandle); |
||
391 | } |
||
392 | |||
393 | return $this->response; |
||
394 | } |
||
395 | |||
396 | /** |
||
397 | * Get |
||
398 | * |
||
399 | * @access public |
||
400 | * @param $url |
||
401 | * @param $data |
||
402 | * |
||
403 | * @return mixed Returns the value provided by exec. |
||
404 | */ |
||
405 | View Code Duplication | public function get($url, $data = array()) |
|
406 | { |
||
407 | if (is_array($url)) { |
||
408 | $data = $url; |
||
409 | $url = $this->baseUrl; |
||
410 | } |
||
411 | $this->setURL($url, $data); |
||
412 | $this->setOpt(CURLOPT_CUSTOMREQUEST, 'GET'); |
||
413 | $this->setOpt(CURLOPT_HTTPGET, true); |
||
414 | return $this->exec(); |
||
415 | } |
||
416 | |||
417 | /** |
||
418 | * Get Info |
||
419 | * |
||
420 | * @access public |
||
421 | * @param $opt |
||
422 | * |
||
423 | * @return mixed |
||
424 | */ |
||
425 | public function getInfo($opt) |
||
426 | { |
||
427 | return curl_getinfo($this->curl, $opt); |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * Get Opt |
||
432 | * |
||
433 | * @access public |
||
434 | * @param $option |
||
435 | * |
||
436 | * @return mixed |
||
437 | */ |
||
438 | public function getOpt($option) |
||
439 | { |
||
440 | return isset($this->options[$option]) ? $this->options[$option] : null; |
||
441 | } |
||
442 | |||
443 | /** |
||
444 | * Head |
||
445 | * |
||
446 | * @access public |
||
447 | * @param $url |
||
448 | * @param $data |
||
449 | * |
||
450 | * @return string |
||
451 | */ |
||
452 | View Code Duplication | public function head($url, $data = array()) |
|
453 | { |
||
454 | if (is_array($url)) { |
||
455 | $data = $url; |
||
456 | $url = $this->baseUrl; |
||
457 | } |
||
458 | $this->setURL($url, $data); |
||
459 | $this->setOpt(CURLOPT_CUSTOMREQUEST, 'HEAD'); |
||
460 | $this->setOpt(CURLOPT_NOBODY, true); |
||
461 | return $this->exec(); |
||
462 | } |
||
463 | |||
464 | /** |
||
465 | * Header Callback |
||
466 | * |
||
467 | * @access public |
||
468 | * @param $ch |
||
469 | * @param $header |
||
470 | * |
||
471 | * @return integer |
||
472 | */ |
||
473 | public function headerCallback($ch, $header) |
||
474 | { |
||
475 | if (preg_match('/^Set-Cookie:\s*([^=]+)=([^;]+)/mi', $header, $cookie) === 1) { |
||
476 | $this->responseCookies[$cookie[1]] = trim($cookie[2], " \n\r\t\0\x0B"); |
||
477 | } |
||
478 | $this->rawResponseHeaders .= $header; |
||
479 | return strlen($header); |
||
480 | } |
||
481 | |||
482 | /** |
||
483 | * Options |
||
484 | * |
||
485 | * @access public |
||
486 | * @param $url |
||
487 | * @param $data |
||
488 | * |
||
489 | * @return string |
||
490 | */ |
||
491 | View Code Duplication | public function options($url, $data = array()) |
|
492 | { |
||
493 | if (is_array($url)) { |
||
494 | $data = $url; |
||
495 | $url = $this->baseUrl; |
||
496 | } |
||
497 | $this->setURL($url, $data); |
||
498 | $this->unsetHeader('Content-Length'); |
||
499 | $this->setOpt(CURLOPT_CUSTOMREQUEST, 'OPTIONS'); |
||
500 | return $this->exec(); |
||
501 | } |
||
502 | |||
503 | /** |
||
504 | * Patch |
||
505 | * |
||
506 | * @access public |
||
507 | * @param $url |
||
508 | * @param $data |
||
509 | * |
||
510 | * @return string |
||
511 | */ |
||
512 | public function patch($url, $data = array()) |
||
513 | { |
||
514 | if (is_array($url)) { |
||
515 | $data = $url; |
||
516 | $url = $this->baseUrl; |
||
517 | } |
||
518 | |||
519 | if (is_array($data) && empty($data)) { |
||
520 | $this->unsetHeader('Content-Length'); |
||
521 | } |
||
522 | |||
523 | $this->setURL($url); |
||
524 | $this->setOpt(CURLOPT_CUSTOMREQUEST, 'PATCH'); |
||
525 | $this->setOpt(CURLOPT_POSTFIELDS, $this->buildPostData($data)); |
||
526 | return $this->exec(); |
||
527 | } |
||
528 | |||
529 | /** |
||
530 | * Post |
||
531 | * |
||
532 | * @access public |
||
533 | * @param $url |
||
534 | * @param $data |
||
535 | * @param $follow_303_with_post |
||
536 | * If true, will cause 303 redirections to be followed using a POST request (default: false). |
||
537 | * Notes: |
||
538 | * - Redirections are only followed if the CURLOPT_FOLLOWLOCATION option is set to true. |
||
539 | * - According to the HTTP specs (see [1]), a 303 redirection should be followed using |
||
540 | * the GET method. 301 and 302 must not. |
||
541 | * - In order to force a 303 redirection to be performed using the same method, the |
||
542 | * underlying cURL object must be set in a special state (the CURLOPT_CURSTOMREQUEST |
||
543 | * option must be set to the method to use after the redirection). Due to a limitation |
||
544 | * of the cURL extension of PHP < 5.5.11 ([2], [3]) and of HHVM, it is not possible |
||
545 | * to reset this option. Using these PHP engines, it is therefore impossible to |
||
546 | * restore this behavior on an existing php-curl-class Curl object. |
||
547 | * |
||
548 | * @return string |
||
549 | * |
||
550 | * [1] https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2 |
||
551 | * [2] https://github.com/php/php-src/pull/531 |
||
552 | * [3] http://php.net/ChangeLog-5.php#5.5.11 |
||
553 | */ |
||
554 | public function post($url, $data = array(), $follow_303_with_post = false) |
||
555 | { |
||
556 | if (is_array($url)) { |
||
557 | $follow_303_with_post = (bool)$data; |
||
558 | $data = $url; |
||
559 | $url = $this->baseUrl; |
||
560 | } |
||
561 | |||
562 | $this->setURL($url); |
||
563 | |||
564 | if ($follow_303_with_post) { |
||
565 | $this->setOpt(CURLOPT_CUSTOMREQUEST, 'POST'); |
||
566 | } else { |
||
567 | if (isset($this->options[CURLOPT_CUSTOMREQUEST])) { |
||
568 | if ((version_compare(PHP_VERSION, '5.5.11') < 0) || defined('HHVM_VERSION')) { |
||
569 | trigger_error( |
||
570 | 'Due to technical limitations of PHP <= 5.5.11 and HHVM, it is not possible to ' |
||
571 | . 'perform a post-redirect-get request using a php-curl-class Curl object that ' |
||
572 | . 'has already been used to perform other types of requests. Either use a new ' |
||
573 | . 'php-curl-class Curl object or upgrade your PHP engine.', |
||
574 | E_USER_ERROR |
||
575 | ); |
||
576 | } else { |
||
577 | $this->setOpt(CURLOPT_CUSTOMREQUEST, null); |
||
578 | } |
||
579 | } |
||
580 | } |
||
581 | |||
582 | $this->setOpt(CURLOPT_POST, true); |
||
583 | $this->setOpt(CURLOPT_POSTFIELDS, $this->buildPostData($data)); |
||
584 | return $this->exec(); |
||
585 | } |
||
586 | |||
587 | /** |
||
588 | * Put |
||
589 | * |
||
590 | * @access public |
||
591 | * @param $url |
||
592 | * @param $data |
||
593 | * |
||
594 | * @return string |
||
595 | */ |
||
596 | View Code Duplication | public function put($url, $data = array()) |
|
597 | { |
||
598 | if (is_array($url)) { |
||
599 | $data = $url; |
||
600 | $url = $this->baseUrl; |
||
601 | } |
||
602 | $this->setURL($url); |
||
603 | $this->setOpt(CURLOPT_CUSTOMREQUEST, 'PUT'); |
||
604 | $put_data = $this->buildPostData($data); |
||
605 | if (empty($this->options[CURLOPT_INFILE]) && empty($this->options[CURLOPT_INFILESIZE])) { |
||
606 | if (is_string($put_data)) { |
||
607 | $this->setHeader('Content-Length', strlen($put_data)); |
||
608 | } |
||
609 | } |
||
610 | if (!empty($put_data)) { |
||
611 | $this->setOpt(CURLOPT_POSTFIELDS, $put_data); |
||
612 | } |
||
613 | return $this->exec(); |
||
614 | } |
||
615 | |||
616 | /** |
||
617 | * Search |
||
618 | * |
||
619 | * @access public |
||
620 | * @param $url |
||
621 | * @param $data |
||
622 | * |
||
623 | * @return string |
||
624 | */ |
||
625 | View Code Duplication | public function search($url, $data = array()) |
|
626 | { |
||
627 | if (is_array($url)) { |
||
628 | $data = $url; |
||
629 | $url = $this->baseUrl; |
||
630 | } |
||
631 | $this->setURL($url); |
||
632 | $this->setOpt(CURLOPT_CUSTOMREQUEST, 'SEARCH'); |
||
633 | $put_data = $this->buildPostData($data); |
||
634 | if (empty($this->options[CURLOPT_INFILE]) && empty($this->options[CURLOPT_INFILESIZE])) { |
||
635 | if (is_string($put_data)) { |
||
636 | $this->setHeader('Content-Length', strlen($put_data)); |
||
637 | } |
||
638 | } |
||
639 | if (!empty($put_data)) { |
||
640 | $this->setOpt(CURLOPT_POSTFIELDS, $put_data); |
||
641 | } |
||
642 | return $this->exec(); |
||
643 | } |
||
644 | |||
645 | /** |
||
646 | * Set Basic Authentication |
||
647 | * |
||
648 | * @access public |
||
649 | * @param $username |
||
650 | * @param $password |
||
651 | */ |
||
652 | public function setBasicAuthentication($username, $password = '') |
||
653 | { |
||
654 | $this->setOpt(CURLOPT_HTTPAUTH, CURLAUTH_BASIC); |
||
655 | $this->setOpt(CURLOPT_USERPWD, $username . ':' . $password); |
||
656 | } |
||
657 | |||
658 | /** |
||
659 | * Set Digest Authentication |
||
660 | * |
||
661 | * @access public |
||
662 | * @param $username |
||
663 | * @param $password |
||
664 | */ |
||
665 | public function setDigestAuthentication($username, $password = '') |
||
666 | { |
||
667 | $this->setOpt(CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); |
||
668 | $this->setOpt(CURLOPT_USERPWD, $username . ':' . $password); |
||
669 | } |
||
670 | |||
671 | /** |
||
672 | * Set Cookie |
||
673 | * |
||
674 | * @access public |
||
675 | * @param $key |
||
676 | * @param $value |
||
677 | */ |
||
678 | public function setCookie($key, $value) |
||
679 | { |
||
680 | $name_chars = array(); |
||
681 | foreach (str_split($key) as $name_char) { |
||
682 | if (!isset($this->rfc2616[$name_char])) { |
||
683 | $name_chars[] = rawurlencode($name_char); |
||
684 | } else { |
||
685 | $name_chars[] = $name_char; |
||
686 | } |
||
687 | } |
||
688 | |||
689 | $value_chars = array(); |
||
690 | foreach (str_split($value) as $value_char) { |
||
691 | if (!isset($this->rfc6265[$value_char])) { |
||
692 | $value_chars[] = rawurlencode($value_char); |
||
693 | } else { |
||
694 | $value_chars[] = $value_char; |
||
695 | } |
||
696 | } |
||
697 | |||
698 | $this->cookies[implode('', $name_chars)] = implode('', $value_chars); |
||
699 | $this->setOpt(CURLOPT_COOKIE, implode('; ', array_map(function ($k, $v) { |
||
700 | return $k . '=' . $v; |
||
701 | }, array_keys($this->cookies), array_values($this->cookies)))); |
||
702 | } |
||
703 | |||
704 | /** |
||
705 | * Get cookie. |
||
706 | * |
||
707 | * @access public |
||
708 | * @param $key |
||
709 | * |
||
710 | * @return mixed |
||
711 | */ |
||
712 | public function getCookie($key) |
||
713 | { |
||
714 | return $this->getResponseCookie($key); |
||
715 | } |
||
716 | |||
717 | /** |
||
718 | * Get response cookie. |
||
719 | * |
||
720 | * @access public |
||
721 | * @param $key |
||
722 | * |
||
723 | * @return mixed |
||
724 | */ |
||
725 | public function getResponseCookie($key) |
||
726 | { |
||
727 | return isset($this->responseCookies[$key]) ? $this->responseCookies[$key] : null; |
||
728 | } |
||
729 | |||
730 | /** |
||
731 | * Set Port |
||
732 | * |
||
733 | * @access public |
||
734 | * @param $port |
||
735 | */ |
||
736 | public function setPort($port) |
||
737 | { |
||
738 | $this->setOpt(CURLOPT_PORT, intval($port)); |
||
739 | } |
||
740 | |||
741 | /** |
||
742 | * Set Connect Timeout |
||
743 | * |
||
744 | * @access public |
||
745 | * @param $seconds |
||
746 | */ |
||
747 | public function setConnectTimeout($seconds) |
||
748 | { |
||
749 | $this->setOpt(CURLOPT_CONNECTTIMEOUT, $seconds); |
||
750 | } |
||
751 | |||
752 | /** |
||
753 | * Set Cookie String |
||
754 | * |
||
755 | * @access public |
||
756 | * @param $string |
||
757 | * |
||
758 | * @return bool |
||
759 | */ |
||
760 | public function setCookieString($string) |
||
761 | { |
||
762 | return $this->setOpt(CURLOPT_COOKIE, $string); |
||
763 | } |
||
764 | |||
765 | /** |
||
766 | * Set Cookie File |
||
767 | * |
||
768 | * @access public |
||
769 | * @param $cookie_file |
||
770 | */ |
||
771 | public function setCookieFile($cookie_file) |
||
772 | { |
||
773 | $this->setOpt(CURLOPT_COOKIEFILE, $cookie_file); |
||
774 | } |
||
775 | |||
776 | /** |
||
777 | * Set Cookie Jar |
||
778 | * |
||
779 | * @access public |
||
780 | * @param $cookie_jar |
||
781 | */ |
||
782 | public function setCookieJar($cookie_jar) |
||
783 | { |
||
784 | $this->setOpt(CURLOPT_COOKIEJAR, $cookie_jar); |
||
785 | } |
||
786 | |||
787 | /** |
||
788 | * Set Default JSON Decoder |
||
789 | * |
||
790 | * @access public |
||
791 | * @param $assoc |
||
792 | * @param $depth |
||
793 | * @param $options |
||
794 | */ |
||
795 | public function setDefaultJsonDecoder() |
||
796 | { |
||
797 | $args = func_get_args(); |
||
798 | $this->jsonDecoder = function ($response) use ($args) { |
||
799 | array_unshift($args, $response); |
||
800 | |||
801 | // Call json_decode() without the $options parameter in PHP |
||
802 | // versions less than 5.4.0 as the $options parameter was added in |
||
803 | // PHP version 5.4.0. |
||
804 | if (version_compare(PHP_VERSION, '5.4.0', '<')) { |
||
805 | $args = array_slice($args, 0, 3); |
||
806 | } |
||
807 | |||
808 | $json_obj = call_user_func_array('json_decode', $args); |
||
809 | if (!($json_obj === null)) { |
||
810 | $response = $json_obj; |
||
811 | } |
||
812 | return $response; |
||
813 | }; |
||
814 | } |
||
815 | |||
816 | /** |
||
817 | * Set Default XML Decoder |
||
818 | * |
||
819 | * @access public |
||
820 | */ |
||
821 | public function setDefaultXmlDecoder() |
||
831 | |||
832 | /** |
||
833 | * Set Default Decoder |
||
834 | * |
||
835 | * @access public |
||
836 | * @param $decoder string|callable |
||
837 | */ |
||
838 | public function setDefaultDecoder($decoder = 'json') |
||
839 | { |
||
840 | if (is_callable($decoder)) { |
||
841 | $this->defaultDecoder = $decoder; |
||
842 | } else { |
||
843 | if ($decoder === 'json') { |
||
844 | $this->defaultDecoder = $this->jsonDecoder; |
||
845 | } elseif ($decoder === 'xml') { |
||
846 | $this->defaultDecoder = $this->xmlDecoder; |
||
847 | } |
||
848 | } |
||
849 | } |
||
850 | |||
851 | /** |
||
852 | * Set Default Timeout |
||
853 | * |
||
854 | * @access public |
||
855 | */ |
||
856 | public function setDefaultTimeout() |
||
857 | { |
||
858 | $this->setTimeout(self::DEFAULT_TIMEOUT); |
||
859 | } |
||
860 | |||
861 | /** |
||
862 | * Set Default User Agent |
||
863 | * |
||
864 | * @access public |
||
865 | */ |
||
866 | public function setDefaultUserAgent() |
||
874 | |||
875 | /** |
||
876 | * Set Header |
||
877 | * |
||
878 | * @access public |
||
879 | * @param $key |
||
880 | * @param $value |
||
881 | */ |
||
882 | public function setHeader($key, $value) |
||
891 | |||
892 | /** |
||
893 | * Set JSON Decoder |
||
894 | * |
||
895 | * @access public |
||
896 | * @param $function |
||
897 | */ |
||
898 | public function setJsonDecoder($function) |
||
904 | |||
905 | /** |
||
906 | * Set XML Decoder |
||
907 | * |
||
908 | * @access public |
||
909 | * @param $function |
||
910 | */ |
||
911 | public function setXmlDecoder($function) |
||
917 | |||
918 | /** |
||
919 | * Set Opt |
||
920 | * |
||
921 | * @access public |
||
922 | * @param $option |
||
923 | * @param $value |
||
924 | * |
||
925 | * @return boolean |
||
926 | */ |
||
927 | public function setOpt($option, $value) |
||
943 | |||
944 | /** |
||
945 | * Set Opts |
||
946 | * |
||
947 | * @access public |
||
948 | * @param $options |
||
949 | * |
||
950 | * @return boolean |
||
951 | * Returns true if all options were successfully set. If an option could not be successfully set, false is |
||
952 | * immediately returned, ignoring any future options in the options array. Similar to curl_setopt_array(). |
||
953 | */ |
||
954 | public function setOpts($options) |
||
963 | |||
964 | /** |
||
965 | * Set Referer |
||
966 | * |
||
967 | * @access public |
||
968 | * @param $referer |
||
969 | */ |
||
970 | public function setReferer($referer) |
||
974 | |||
975 | /** |
||
976 | * Set Referrer |
||
977 | * |
||
978 | * @access public |
||
979 | * @param $referrer |
||
980 | */ |
||
981 | public function setReferrer($referrer) |
||
985 | |||
986 | /** |
||
987 | * Set Timeout |
||
988 | * |
||
989 | * @access public |
||
990 | * @param $seconds |
||
991 | */ |
||
992 | public function setTimeout($seconds) |
||
996 | |||
997 | /** |
||
998 | * Set Url |
||
999 | * |
||
1000 | * @access public |
||
1001 | * @param $url |
||
1002 | * @param $data |
||
1003 | */ |
||
1004 | public function setURL($url, $data = array()) |
||
1010 | |||
1011 | /** |
||
1012 | * Set User Agent |
||
1013 | * |
||
1014 | * @access public |
||
1015 | * @param $user_agent |
||
1016 | */ |
||
1017 | public function setUserAgent($user_agent) |
||
1021 | |||
1022 | /** |
||
1023 | * Success |
||
1024 | * |
||
1025 | * @access public |
||
1026 | * @param $callback |
||
1027 | */ |
||
1028 | public function success($callback) |
||
1032 | |||
1033 | /** |
||
1034 | * Unset Header |
||
1035 | * |
||
1036 | * @access public |
||
1037 | * @param $key |
||
1038 | */ |
||
1039 | public function unsetHeader($key) |
||
1044 | |||
1045 | /** |
||
1046 | * Verbose |
||
1047 | * |
||
1048 | * @access public |
||
1049 | * @param bool $on |
||
1050 | * @param resource $output |
||
1051 | */ |
||
1052 | View Code Duplication | public function verbose($on = true, $output = STDERR) |
|
1062 | |||
1063 | /** |
||
1064 | * Destruct |
||
1065 | * |
||
1066 | * @access public |
||
1067 | */ |
||
1068 | public function __destruct() |
||
1072 | |||
1073 | public function __get($name) |
||
1081 | |||
1082 | /** |
||
1083 | * Get Effective Url |
||
1084 | * |
||
1085 | * @access private |
||
1086 | */ |
||
1087 | private function __get_effectiveUrl() |
||
1091 | |||
1092 | /** |
||
1093 | * Get Total Time |
||
1094 | * |
||
1095 | * @access private |
||
1096 | */ |
||
1097 | private function __get_totalTime() |
||
1101 | |||
1102 | /** |
||
1103 | * Build Url |
||
1104 | * |
||
1105 | * @access private |
||
1106 | * @param $url |
||
1107 | * @param $data |
||
1108 | * |
||
1109 | * @return string |
||
1110 | */ |
||
1111 | private function buildURL($url, $data = array()) |
||
1115 | |||
1116 | /** |
||
1117 | * Parse Headers |
||
1118 | * |
||
1119 | * @access private |
||
1120 | * @param $raw_headers |
||
1121 | * |
||
1122 | * @return array |
||
1123 | */ |
||
1124 | private function parseHeaders($raw_headers) |
||
1144 | |||
1145 | /** |
||
1146 | * Parse Request Headers |
||
1147 | * |
||
1148 | * @access private |
||
1149 | * @param $raw_headers |
||
1150 | * |
||
1151 | * @return array |
||
1152 | */ |
||
1153 | private function parseRequestHeaders($raw_headers) |
||
1163 | |||
1164 | /** |
||
1165 | * Parse Response |
||
1166 | * |
||
1167 | * @access private |
||
1168 | * @param $response_headers |
||
1169 | * @param $raw_response |
||
1170 | * |
||
1171 | * @return mixed |
||
1172 | * Provided the content-type is determined to be json or xml: |
||
1173 | * Returns stdClass object when the default json decoder is used and the content-type is json. |
||
1174 | * Returns SimpleXMLElement object when the default xml decoder is used and the content-type is xml. |
||
1175 | */ |
||
1176 | private function parseResponse($response_headers, $raw_response) |
||
1200 | |||
1201 | /** |
||
1202 | * Parse Response Headers |
||
1203 | * |
||
1204 | * @access private |
||
1205 | * @param $raw_response_headers |
||
1206 | * |
||
1207 | * @return array |
||
1208 | */ |
||
1209 | private function parseResponseHeaders($raw_response_headers) |
||
1228 | |||
1229 | /** |
||
1230 | * Is Array Assoc |
||
1231 | * |
||
1232 | * @access public |
||
1233 | * @param $array |
||
1234 | * |
||
1235 | * @return boolean |
||
1236 | */ |
||
1237 | public static function is_array_assoc($array) |
||
1241 | |||
1242 | /** |
||
1243 | * Is Array Multidim |
||
1244 | * |
||
1245 | * @access public |
||
1246 | * @param $array |
||
1247 | * |
||
1248 | * @return boolean |
||
1249 | */ |
||
1250 | public static function is_array_multidim($array) |
||
1258 | |||
1259 | /** |
||
1260 | * Array Flatten Multidim |
||
1261 | * |
||
1262 | * @access public |
||
1263 | * @param $array |
||
1264 | * @param $prefix |
||
1265 | * |
||
1266 | * @return array |
||
1267 | */ |
||
1268 | public static function array_flatten_multidim($array, $prefix = false) |
||
1302 | } |
||
1303 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.