Total Complexity | 109 |
Total Lines | 953 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like RequestCore 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.
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 RequestCore, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
14 | class RequestCore |
||
15 | { |
||
16 | /** |
||
17 | * The URL being requested. |
||
18 | */ |
||
19 | public $request_url; |
||
20 | |||
21 | /** |
||
22 | * The headers being sent in the request. |
||
23 | */ |
||
24 | public $request_headers; |
||
25 | |||
26 | /** |
||
27 | * The body being sent in the request. |
||
28 | */ |
||
29 | public $request_body; |
||
30 | |||
31 | /** |
||
32 | * The response returned by the request. |
||
33 | */ |
||
34 | public $response; |
||
35 | |||
36 | /** |
||
37 | * The headers returned by the request. |
||
38 | */ |
||
39 | public $response_headers; |
||
40 | |||
41 | /** |
||
42 | * The body returned by the request. |
||
43 | */ |
||
44 | public $response_body; |
||
45 | |||
46 | /** |
||
47 | * The HTTP status code returned by the request. |
||
48 | */ |
||
49 | public $response_code; |
||
50 | |||
51 | /** |
||
52 | * Additional response data. |
||
53 | */ |
||
54 | public $response_info; |
||
55 | |||
56 | /** |
||
57 | * The handle for the cURL object. |
||
58 | */ |
||
59 | public $curl_handle; |
||
60 | |||
61 | /** |
||
62 | * The method by which the request is being made. |
||
63 | */ |
||
64 | public $method; |
||
65 | |||
66 | /** |
||
67 | * Stores the proxy settings to use for the request. |
||
68 | */ |
||
69 | public $proxy = null; |
||
70 | |||
71 | /** |
||
72 | * The username to use for the request. |
||
73 | */ |
||
74 | public $username = null; |
||
75 | |||
76 | /** |
||
77 | * The password to use for the request. |
||
78 | */ |
||
79 | public $password = null; |
||
80 | |||
81 | /** |
||
82 | * Custom CURLOPT settings. |
||
83 | */ |
||
84 | public $curlopts = null; |
||
85 | |||
86 | /** |
||
87 | * The state of debug mode. |
||
88 | */ |
||
89 | public $debug_mode = false; |
||
90 | |||
91 | /** |
||
92 | * The default class to use for HTTP Requests (defaults to <RequestCore>). |
||
93 | */ |
||
94 | public $request_class = 'RequestCore'; |
||
95 | |||
96 | /** |
||
97 | * The default class to use for HTTP Responses (defaults to <ResponseCore>). |
||
98 | */ |
||
99 | public $response_class = 'ResponseCore'; |
||
100 | |||
101 | /** |
||
102 | * Default useragent string to use. |
||
103 | */ |
||
104 | public $useragent = 'RequestCore/1.4.3'; |
||
105 | |||
106 | /** |
||
107 | * File to read from while streaming up. |
||
108 | */ |
||
109 | public $read_file = null; |
||
110 | |||
111 | /** |
||
112 | * The resource to read from while streaming up. |
||
113 | */ |
||
114 | public $read_stream = null; |
||
115 | |||
116 | /** |
||
117 | * The size of the stream to read from. |
||
118 | */ |
||
119 | public $read_stream_size = null; |
||
120 | |||
121 | /** |
||
122 | * The length already read from the stream. |
||
123 | */ |
||
124 | public $read_stream_read = 0; |
||
125 | |||
126 | /** |
||
127 | * File to write to while streaming down. |
||
128 | */ |
||
129 | public $write_file = null; |
||
130 | |||
131 | /** |
||
132 | * The resource to write to while streaming down. |
||
133 | */ |
||
134 | public $write_stream = null; |
||
135 | |||
136 | /** |
||
137 | * Stores the intended starting seek position. |
||
138 | */ |
||
139 | public $seek_position = null; |
||
140 | |||
141 | /** |
||
142 | * The location of the cacert.pem file to use. |
||
143 | */ |
||
144 | public $cacert_location = false; |
||
145 | |||
146 | /** |
||
147 | * The state of SSL certificate verification. |
||
148 | */ |
||
149 | public $ssl_verification = true; |
||
150 | |||
151 | /** |
||
152 | * The user-defined callback function to call when a stream is read from. |
||
153 | */ |
||
154 | public $registered_streaming_read_callback = null; |
||
155 | |||
156 | /** |
||
157 | * The user-defined callback function to call when a stream is written to. |
||
158 | */ |
||
159 | public $registered_streaming_write_callback = null; |
||
160 | |||
161 | /*%******************************************************************************************%*/ |
||
162 | // CONSTANTS |
||
163 | |||
164 | /** |
||
165 | * GET HTTP Method |
||
166 | */ |
||
167 | const HTTP_GET = 'GET'; |
||
168 | |||
169 | /** |
||
170 | * POST HTTP Method |
||
171 | */ |
||
172 | const HTTP_POST = 'POST'; |
||
173 | |||
174 | /** |
||
175 | * PUT HTTP Method |
||
176 | */ |
||
177 | const HTTP_PUT = 'PUT'; |
||
178 | |||
179 | /** |
||
180 | * DELETE HTTP Method |
||
181 | */ |
||
182 | const HTTP_DELETE = 'DELETE'; |
||
183 | |||
184 | /** |
||
185 | * HEAD HTTP Method |
||
186 | */ |
||
187 | const HTTP_HEAD = 'HEAD'; |
||
188 | |||
189 | |||
190 | /*%******************************************************************************************%*/ |
||
191 | // CONSTRUCTOR/DESTRUCTOR |
||
192 | |||
193 | /** |
||
194 | * Constructs a new instance of this class. |
||
195 | * |
||
196 | * @param string $url (Optional) The URL to request or service endpoint to query. |
||
197 | * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` |
||
198 | * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class. |
||
199 | * @return $this A reference to the current instance. |
||
200 | */ |
||
201 | public function __construct($url = null, $proxy = null, $helpers = null) |
||
202 | { |
||
203 | // Set some default values. |
||
204 | $this->request_url = $url; |
||
205 | $this->method = self::HTTP_GET; |
||
206 | $this->request_headers = array(); |
||
207 | $this->request_body = ''; |
||
208 | |||
209 | // Set a new Request class if one was set. |
||
210 | if (isset($helpers['request']) && !empty($helpers['request'])) |
||
211 | { |
||
212 | $this->request_class = $helpers['request']; |
||
213 | } |
||
214 | |||
215 | // Set a new Request class if one was set. |
||
216 | if (isset($helpers['response']) && !empty($helpers['response'])) |
||
217 | { |
||
218 | $this->response_class = $helpers['response']; |
||
219 | } |
||
220 | |||
221 | if ($proxy) |
||
222 | { |
||
223 | $this->set_proxy($proxy); |
||
224 | } |
||
225 | |||
226 | return $this; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Destructs the instance. Closes opened file handles. |
||
231 | * |
||
232 | * @return $this A reference to the current instance. |
||
233 | */ |
||
234 | public function __destruct() |
||
235 | { |
||
236 | if (isset($this->read_file) && isset($this->read_stream)) |
||
237 | { |
||
238 | fclose($this->read_stream); |
||
239 | } |
||
240 | |||
241 | if (isset($this->write_file) && isset($this->write_stream)) |
||
242 | { |
||
243 | fclose($this->write_stream); |
||
244 | } |
||
245 | |||
246 | return $this; |
||
247 | } |
||
248 | |||
249 | |||
250 | /*%******************************************************************************************%*/ |
||
251 | // REQUEST METHODS |
||
252 | |||
253 | /** |
||
254 | * Sets the credentials to use for authentication. |
||
255 | * |
||
256 | * @param string $user (Required) The username to authenticate with. |
||
257 | * @param string $pass (Required) The password to authenticate with. |
||
258 | * @return $this A reference to the current instance. |
||
259 | */ |
||
260 | public function set_credentials($user, $pass) |
||
261 | { |
||
262 | $this->username = $user; |
||
263 | $this->password = $pass; |
||
264 | return $this; |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Adds a custom HTTP header to the cURL request. |
||
269 | * |
||
270 | * @param string $key (Required) The custom HTTP header to set. |
||
271 | * @param mixed $value (Required) The value to assign to the custom HTTP header. |
||
272 | * @return $this A reference to the current instance. |
||
273 | */ |
||
274 | public function add_header($key, $value) |
||
275 | { |
||
276 | $this->request_headers[$key] = $value; |
||
277 | return $this; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Removes an HTTP header from the cURL request. |
||
282 | * |
||
283 | * @param string $key (Required) The custom HTTP header to set. |
||
284 | * @return $this A reference to the current instance. |
||
285 | */ |
||
286 | public function remove_header($key) |
||
287 | { |
||
288 | if (isset($this->request_headers[$key])) |
||
289 | { |
||
290 | unset($this->request_headers[$key]); |
||
291 | } |
||
292 | return $this; |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Set the method type for the request. |
||
297 | * |
||
298 | * @param string $method (Required) One of the following constants: <HTTP_GET>, <HTTP_POST>, <HTTP_PUT>, <HTTP_HEAD>, <HTTP_DELETE>. |
||
299 | * @return $this A reference to the current instance. |
||
300 | */ |
||
301 | public function set_method($method) |
||
302 | { |
||
303 | $this->method = strtoupper($method); |
||
304 | return $this; |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Sets a custom useragent string for the class. |
||
309 | * |
||
310 | * @param string $ua (Required) The useragent string to use. |
||
311 | * @return $this A reference to the current instance. |
||
312 | */ |
||
313 | public function set_useragent($ua) |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Set the body to send in the request. |
||
321 | * |
||
322 | * @param string $body (Required) The textual content to send along in the body of the request. |
||
323 | * @return $this A reference to the current instance. |
||
324 | */ |
||
325 | public function set_body($body) |
||
326 | { |
||
327 | $this->request_body = $body; |
||
328 | return $this; |
||
329 | } |
||
330 | |||
331 | /** |
||
332 | * Set the URL to make the request to. |
||
333 | * |
||
334 | * @param string $url (Required) The URL to make the request to. |
||
335 | * @return $this A reference to the current instance. |
||
336 | */ |
||
337 | public function set_request_url($url) |
||
338 | { |
||
339 | $this->request_url = $url; |
||
340 | return $this; |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * Set additional CURLOPT settings. These will merge with the default settings, and override if |
||
345 | * there is a duplicate. |
||
346 | * |
||
347 | * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings. |
||
348 | * @return $this A reference to the current instance. |
||
349 | */ |
||
350 | public function set_curlopts($curlopts) |
||
351 | { |
||
352 | $this->curlopts = $curlopts; |
||
353 | return $this; |
||
354 | } |
||
355 | |||
356 | /** |
||
357 | * Sets the length in bytes to read from the stream while streaming up. |
||
358 | * |
||
359 | * @param integer $size (Required) The length in bytes to read from the stream. |
||
360 | * @return $this A reference to the current instance. |
||
361 | */ |
||
362 | public function set_read_stream_size($size) |
||
363 | { |
||
364 | $this->read_stream_size = $size; |
||
365 | |||
366 | return $this; |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * Sets the resource to read from while streaming up. Reads the stream from its current position until |
||
371 | * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by <php:fstat()> and |
||
372 | * <php:ftell()>. |
||
373 | * |
||
374 | * @param resource $resource (Required) The readable resource to read from. |
||
375 | * @param integer $size (Optional) The size of the stream to read. |
||
376 | * @return $this A reference to the current instance. |
||
377 | */ |
||
378 | public function set_read_stream($resource, $size = null) |
||
379 | { |
||
380 | if (!isset($size) || $size < 0) |
||
381 | { |
||
382 | $stats = fstat($resource); |
||
383 | |||
384 | if ($stats && $stats['size'] >= 0) |
||
|
|||
385 | { |
||
386 | $position = ftell($resource); |
||
387 | |||
388 | if ($position !== false && $position >= 0) |
||
389 | { |
||
390 | $size = $stats['size'] - $position; |
||
391 | } |
||
392 | } |
||
393 | } |
||
394 | |||
395 | $this->read_stream = $resource; |
||
396 | |||
397 | return $this->set_read_stream_size($size); |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * Sets the file to read from while streaming up. |
||
402 | * |
||
403 | * @param string $location (Required) The readable location to read from. |
||
404 | * @return $this A reference to the current instance. |
||
405 | */ |
||
406 | public function set_read_file($location) |
||
407 | { |
||
408 | $this->read_file = $location; |
||
409 | $read_file_handle = fopen($location, 'r'); |
||
410 | |||
411 | return $this->set_read_stream($read_file_handle); |
||
412 | } |
||
413 | |||
414 | /** |
||
415 | * Sets the resource to write to while streaming down. |
||
416 | * |
||
417 | * @param resource $resource (Required) The writeable resource to write to. |
||
418 | * @return $this A reference to the current instance. |
||
419 | */ |
||
420 | public function set_write_stream($resource) |
||
421 | { |
||
422 | $this->write_stream = $resource; |
||
423 | |||
424 | return $this; |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Sets the file to write to while streaming down. |
||
429 | * |
||
430 | * @param string $location (Required) The writeable location to write to. |
||
431 | * @return $this A reference to the current instance. |
||
432 | */ |
||
433 | public function set_write_file($location) |
||
434 | { |
||
435 | $this->write_file = $location; |
||
436 | $write_file_handle = fopen($location, 'w'); |
||
437 | |||
438 | return $this->set_write_stream($write_file_handle); |
||
439 | } |
||
440 | |||
441 | /** |
||
442 | * Set the proxy to use for making requests. |
||
443 | * |
||
444 | * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` |
||
445 | * @return $this A reference to the current instance. |
||
446 | */ |
||
447 | public function set_proxy($proxy) |
||
448 | { |
||
449 | $proxy = parse_url($proxy); |
||
450 | $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null; |
||
451 | $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null; |
||
452 | $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null; |
||
453 | $this->proxy = $proxy; |
||
454 | return $this; |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * Set the intended starting seek position. |
||
459 | * |
||
460 | * @param integer $position (Required) The byte-position of the stream to begin reading from. |
||
461 | * @return $this A reference to the current instance. |
||
462 | */ |
||
463 | public function set_seek_position($position) |
||
464 | { |
||
465 | $this->seek_position = isset($position) ? (integer) $position : null; |
||
466 | |||
467 | return $this; |
||
468 | } |
||
469 | |||
470 | /** |
||
471 | * Register a callback function to execute whenever a data stream is read from using |
||
472 | * <CFRequest::streaming_read_callback()>. |
||
473 | * |
||
474 | * The user-defined callback function should accept three arguments: |
||
475 | * |
||
476 | * <ul> |
||
477 | * <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li> |
||
478 | * <li><code>$file_handle</code> - <code>resource</code> - Required - The file handle resource that represents the file on the local file system.</li> |
||
479 | * <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li> |
||
480 | * </ul> |
||
481 | * |
||
482 | * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul> |
||
483 | * <li>The name of a global function to execute, passed as a string.</li> |
||
484 | * <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li> |
||
485 | * <li>An anonymous function (PHP 5.3+).</li></ul> |
||
486 | * @return $this A reference to the current instance. |
||
487 | */ |
||
488 | public function register_streaming_read_callback($callback) |
||
489 | { |
||
490 | $this->registered_streaming_read_callback = $callback; |
||
491 | |||
492 | return $this; |
||
493 | } |
||
494 | |||
495 | /** |
||
496 | * Register a callback function to execute whenever a data stream is written to using |
||
497 | * <CFRequest::streaming_write_callback()>. |
||
498 | * |
||
499 | * The user-defined callback function should accept two arguments: |
||
500 | * |
||
501 | * <ul> |
||
502 | * <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li> |
||
503 | * <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li> |
||
504 | * </ul> |
||
505 | * |
||
506 | * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul> |
||
507 | * <li>The name of a global function to execute, passed as a string.</li> |
||
508 | * <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li> |
||
509 | * <li>An anonymous function (PHP 5.3+).</li></ul> |
||
510 | * @return $this A reference to the current instance. |
||
511 | */ |
||
512 | public function register_streaming_write_callback($callback) |
||
513 | { |
||
514 | $this->registered_streaming_write_callback = $callback; |
||
515 | |||
516 | return $this; |
||
517 | } |
||
518 | |||
519 | |||
520 | /*%******************************************************************************************%*/ |
||
521 | // PREPARE, SEND, AND PROCESS REQUEST |
||
522 | |||
523 | /** |
||
524 | * A callback function that is invoked by cURL for streaming up. |
||
525 | * |
||
526 | * @param resource $curl_handle (Required) The cURL handle for the request. |
||
527 | * @param resource $file_handle (Required) The open file handle resource. |
||
528 | * @param integer $length (Required) The maximum number of bytes to read. |
||
529 | * @return binary Binary data from a stream. |
||
530 | */ |
||
531 | public function streaming_read_callback($curl_handle, $file_handle, $length) |
||
560 | } |
||
561 | |||
562 | /** |
||
563 | * A callback function that is invoked by cURL for streaming down. |
||
564 | * |
||
565 | * @param resource $curl_handle (Required) The cURL handle for the request. |
||
566 | * @param binary $data (Required) The data to write. |
||
567 | * @return integer The number of bytes written. |
||
568 | */ |
||
569 | public function streaming_write_callback($curl_handle, $data) |
||
570 | { |
||
571 | if ($this->registered_streaming_write_callback){ |
||
572 | return $this->registered_streaming_write_callback->streaming_write_callback($curl_handle,$data,$this->write_stream); |
||
573 | } |
||
574 | $length = strlen($data); |
||
575 | $written_total = 0; |
||
576 | $written_last = 0; |
||
577 | |||
578 | while ($written_total < $length) |
||
579 | { |
||
580 | $written_last = fwrite($this->write_stream, substr($data, $written_total)); |
||
581 | |||
582 | if ($written_last === false) |
||
583 | { |
||
584 | return $written_total; |
||
585 | } |
||
586 | |||
587 | $written_total += $written_last; |
||
588 | } |
||
589 | |||
590 | return $written_total; |
||
591 | } |
||
592 | |||
593 | /** |
||
594 | * Prepares and adds the details of the cURL request. This can be passed along to a <php:curl_multi_exec()> |
||
595 | * function. |
||
596 | * |
||
597 | * @return resource The handle for the cURL object. |
||
598 | */ |
||
599 | public function prep_request() |
||
600 | { |
||
601 | $curl_handle = curl_init(); |
||
602 | |||
603 | // Set default options. |
||
604 | curl_setopt($curl_handle, CURLOPT_URL, $this->request_url); |
||
605 | curl_setopt($curl_handle, CURLOPT_FILETIME, true); |
||
606 | curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false); |
||
607 | //为了兼容PHP 5.6,PHP 5.6把 CURLOPT_CLOSEPOLICY 这个变量删除了 |
||
608 | //curl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED); |
||
609 | curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5); |
||
610 | curl_setopt($curl_handle, CURLOPT_HEADER, true); |
||
611 | curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true); |
||
612 | curl_setopt($curl_handle, CURLOPT_TIMEOUT, 5184000); |
||
613 | curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 120); |
||
614 | curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true); |
||
615 | curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url); |
||
616 | curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent); |
||
617 | curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback')); |
||
618 | |||
619 | // Verification of the SSL cert |
||
620 | if ($this->ssl_verification) |
||
621 | { |
||
622 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true); |
||
623 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2); |
||
624 | } |
||
625 | else |
||
626 | { |
||
627 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false); |
||
628 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false); |
||
629 | } |
||
630 | |||
631 | // chmod the file as 0755 |
||
632 | if ($this->cacert_location === true) |
||
633 | { |
||
634 | curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem'); |
||
635 | } |
||
636 | elseif (is_string($this->cacert_location)) |
||
637 | { |
||
638 | curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location); |
||
639 | } |
||
640 | |||
641 | // Debug mode |
||
642 | if ($this->debug_mode) |
||
643 | { |
||
644 | curl_setopt($curl_handle, CURLOPT_VERBOSE, true); |
||
645 | } |
||
646 | |||
647 | // Handle open_basedir & safe mode |
||
648 | if (!ini_get('safe_mode') && !ini_get('open_basedir')) |
||
649 | { |
||
650 | curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, FALSE); |
||
651 | } |
||
652 | |||
653 | // Enable a proxy connection if requested. |
||
654 | if ($this->proxy) |
||
655 | { |
||
656 | curl_setopt($curl_handle, CURLOPT_HTTPPROXYTUNNEL, true); |
||
657 | |||
658 | $host = $this->proxy['host']; |
||
659 | $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : ''; |
||
660 | curl_setopt($curl_handle, CURLOPT_PROXY, $host); |
||
661 | |||
662 | if (isset($this->proxy['user']) && isset($this->proxy['pass'])) |
||
663 | { |
||
664 | curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']); |
||
665 | } |
||
666 | } |
||
667 | |||
668 | // Set credentials for HTTP Basic/Digest Authentication. |
||
669 | if ($this->username && $this->password) |
||
670 | { |
||
671 | curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); |
||
672 | curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password); |
||
673 | } |
||
674 | |||
675 | // Handle the encoding if we can. |
||
676 | if (extension_loaded('zlib')) |
||
677 | { |
||
678 | curl_setopt($curl_handle, CURLOPT_ENCODING, ''); |
||
679 | } |
||
680 | |||
681 | // Process custom headers |
||
682 | if (isset($this->request_headers) && count($this->request_headers)) |
||
683 | { |
||
684 | $temp_headers = array(); |
||
685 | |||
686 | foreach ($this->request_headers as $k => $v) |
||
687 | { |
||
688 | $temp_headers[] = $k . ': ' . $v; |
||
689 | } |
||
690 | |||
691 | curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers); |
||
692 | } |
||
693 | |||
694 | switch ($this->method) |
||
695 | { |
||
696 | case self::HTTP_PUT: |
||
697 | //unset($this->read_stream); |
||
698 | curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT'); |
||
699 | if (isset($this->read_stream)) |
||
700 | { |
||
701 | if (!isset($this->read_stream_size) || $this->read_stream_size < 0) |
||
702 | { |
||
703 | throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.'); |
||
704 | } |
||
705 | |||
706 | curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size); |
||
707 | curl_setopt($curl_handle, CURLOPT_UPLOAD, true); |
||
708 | } |
||
709 | else |
||
710 | { |
||
711 | curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); |
||
712 | } |
||
713 | break; |
||
714 | |||
715 | case self::HTTP_POST: |
||
716 | curl_setopt($curl_handle, CURLOPT_POST, true); |
||
717 | curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); |
||
718 | break; |
||
719 | |||
720 | case self::HTTP_HEAD: |
||
721 | curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD); |
||
722 | curl_setopt($curl_handle, CURLOPT_NOBODY, 1); |
||
723 | break; |
||
724 | |||
725 | default: // Assumed GET |
||
726 | curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method); |
||
727 | if (isset($this->write_stream)) |
||
728 | { |
||
729 | curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback')); |
||
730 | curl_setopt($curl_handle, CURLOPT_HEADER, false); |
||
731 | } |
||
732 | else |
||
733 | { |
||
734 | curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); |
||
735 | } |
||
736 | break; |
||
737 | } |
||
738 | |||
739 | // Merge in the CURLOPTs |
||
740 | if (isset($this->curlopts) && sizeof($this->curlopts) > 0) |
||
741 | { |
||
742 | foreach ($this->curlopts as $k => $v) |
||
743 | { |
||
744 | curl_setopt($curl_handle, $k, $v); |
||
745 | } |
||
746 | } |
||
747 | |||
748 | return $curl_handle; |
||
749 | } |
||
750 | |||
751 | /** |
||
752 | * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the |
||
753 | * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via |
||
754 | * parameters. |
||
755 | * |
||
756 | * @param resource $curl_handle (Optional) The reference to the already executed cURL request. |
||
757 | * @param string $response (Optional) The actual response content itself that needs to be parsed. |
||
758 | * @return ResponseCore A <ResponseCore> object containing a parsed HTTP response. |
||
759 | */ |
||
760 | public function process_response($curl_handle = null, $response = null) |
||
761 | { |
||
762 | // Accept a custom one if it's passed. |
||
763 | if ($curl_handle && $response) |
||
764 | { |
||
765 | $this->curl_handle = $curl_handle; |
||
766 | $this->response = $response; |
||
767 | } |
||
768 | |||
769 | // As long as this came back as a valid resource... |
||
770 | if (is_resource($this->curl_handle)) |
||
771 | { |
||
772 | // Determine what's what. |
||
773 | $header_size = curl_getinfo($this->curl_handle, CURLINFO_HEADER_SIZE); |
||
774 | $this->response_headers = substr($this->response, 0, $header_size); |
||
775 | $this->response_body = substr($this->response, $header_size); |
||
776 | $this->response_code = curl_getinfo($this->curl_handle, CURLINFO_HTTP_CODE); |
||
777 | $this->response_info = curl_getinfo($this->curl_handle); |
||
778 | |||
779 | // Parse out the headers |
||
780 | $this->response_headers = explode("\r\n\r\n", trim($this->response_headers)); |
||
781 | $this->response_headers = array_pop($this->response_headers); |
||
782 | $this->response_headers = explode("\r\n", $this->response_headers); |
||
783 | array_shift($this->response_headers); |
||
784 | |||
785 | // Loop through and split up the headers. |
||
786 | $header_assoc = array(); |
||
787 | foreach ($this->response_headers as $header) |
||
788 | { |
||
789 | $kv = explode(': ', $header); |
||
790 | $header_assoc[strtolower($kv[0])] = isset($kv[1])?$kv[1]:''; |
||
791 | } |
||
792 | |||
793 | // Reset the headers to the appropriate property. |
||
794 | $this->response_headers = $header_assoc; |
||
795 | $this->response_headers['_info'] = $this->response_info; |
||
796 | $this->response_headers['_info']['method'] = $this->method; |
||
797 | |||
798 | if ($curl_handle && $response) |
||
799 | { |
||
800 | return new $this->response_class($this->response_headers, $this->response_body, $this->response_code, $this->curl_handle); |
||
801 | } |
||
802 | } |
||
803 | |||
804 | // Return false |
||
805 | return false; |
||
806 | } |
||
807 | |||
808 | /** |
||
809 | * Sends the request, calling necessary utility functions to update built-in properties. |
||
810 | * |
||
811 | * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not. |
||
812 | * @return string The resulting unparsed data from the request. |
||
813 | */ |
||
814 | public function send_request($parse = false) |
||
836 | } |
||
837 | |||
838 | /** |
||
839 | * Sends the request using <php:curl_multi_exec()>, enabling parallel requests. Uses the "rolling" method. |
||
840 | * |
||
841 | * @param array $handles (Required) An indexed array of cURL handles to process simultaneously. |
||
842 | * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul> |
||
843 | * <li><code>callback</code> - <code>string|array</code> - Optional - The string name of a function to pass the response data to. If this is a method, pass an array where the <code>[0]</code> index is the class and the <code>[1]</code> index is the method name.</li> |
||
844 | * <li><code>limit</code> - <code>integer</code> - Optional - The number of simultaneous requests to make. This can be useful for scaling around slow server responses. Defaults to trusting cURLs judgement as to how many to use.</li></ul> |
||
845 | * @return array Post-processed cURL responses. |
||
846 | */ |
||
847 | public function send_multi_request($handles, $opt = null) |
||
848 | { |
||
849 | set_time_limit(0); |
||
850 | |||
851 | // Skip everything if there are no handles to process. |
||
852 | if (count($handles) === 0) return array(); |
||
853 | |||
854 | if (!$opt) $opt = array(); |
||
855 | |||
856 | // Initialize any missing options |
||
857 | $limit = isset($opt['limit']) ? $opt['limit'] : -1; |
||
858 | |||
859 | // Initialize |
||
860 | $handle_list = $handles; |
||
861 | $http = new $this->request_class(); |
||
862 | $multi_handle = curl_multi_init(); |
||
863 | $handles_post = array(); |
||
864 | $added = count($handles); |
||
865 | $last_handle = null; |
||
866 | $count = 0; |
||
867 | $i = 0; |
||
868 | |||
869 | // Loop through the cURL handles and add as many as it set by the limit parameter. |
||
870 | while ($i < $added) |
||
871 | { |
||
872 | if ($limit > 0 && $i >= $limit) break; |
||
873 | curl_multi_add_handle($multi_handle, array_shift($handles)); |
||
874 | $i++; |
||
875 | } |
||
876 | |||
877 | do |
||
878 | { |
||
879 | $active = false; |
||
880 | |||
881 | // Start executing and wait for a response. |
||
882 | while (($status = curl_multi_exec($multi_handle, $active)) === CURLM_CALL_MULTI_PERFORM) |
||
883 | { |
||
884 | // Start looking for possible responses immediately when we have to add more handles |
||
885 | if (count($handles) > 0) break; |
||
886 | } |
||
887 | |||
888 | // Figure out which requests finished. |
||
889 | $to_process = array(); |
||
890 | |||
891 | while ($done = curl_multi_info_read($multi_handle)) |
||
892 | { |
||
893 | // Since curl_errno() isn't reliable for handles that were in multirequests, we check the 'result' of the info read, which contains the curl error number, (listed here http://curl.haxx.se/libcurl/c/libcurl-errors.html ) |
||
894 | if ($done['result'] > 0) |
||
895 | { |
||
896 | throw new RequestCore_Exception('cURL resource: ' . (string) $done['handle'] . '; cURL error: ' . curl_error($done['handle']) . ' (' . $done['result'] . ')'); |
||
897 | } |
||
898 | |||
899 | // Because curl_multi_info_read() might return more than one message about a request, we check to see if this request is already in our array of completed requests |
||
900 | elseif (!isset($to_process[(int) $done['handle']])) |
||
901 | { |
||
902 | $to_process[(int) $done['handle']] = $done; |
||
903 | } |
||
904 | } |
||
905 | |||
906 | // Actually deal with the request |
||
907 | foreach ($to_process as $pkey => $done) |
||
908 | { |
||
909 | $response = $http->process_response($done['handle'], curl_multi_getcontent($done['handle'])); |
||
910 | $key = array_search($done['handle'], $handle_list, true); |
||
911 | $handles_post[$key] = $response; |
||
912 | |||
913 | if (count($handles) > 0) |
||
914 | { |
||
915 | curl_multi_add_handle($multi_handle, array_shift($handles)); |
||
916 | } |
||
917 | |||
918 | curl_multi_remove_handle($multi_handle, $done['handle']); |
||
919 | curl_close($done['handle']); |
||
920 | } |
||
921 | } |
||
922 | while ($active || count($handles_post) < $added); |
||
923 | |||
924 | curl_multi_close($multi_handle); |
||
925 | |||
926 | ksort($handles_post, SORT_NUMERIC); |
||
927 | return $handles_post; |
||
928 | } |
||
929 | |||
930 | |||
931 | /*%******************************************************************************************%*/ |
||
932 | // RESPONSE METHODS |
||
933 | |||
934 | /** |
||
935 | * Get the HTTP response headers from the request. |
||
936 | * |
||
937 | * @param string $header (Optional) A specific header value to return. Defaults to all headers. |
||
938 | * @return string|array All or selected header values. |
||
939 | */ |
||
940 | public function get_response_header($header = null) |
||
941 | { |
||
942 | if ($header) |
||
943 | { |
||
944 | return $this->response_headers[strtolower($header)]; |
||
945 | } |
||
946 | return $this->response_headers; |
||
947 | } |
||
948 | |||
949 | /** |
||
950 | * Get the HTTP response body from the request. |
||
951 | * |
||
952 | * @return string The response body. |
||
953 | */ |
||
954 | public function get_response_body() |
||
957 | } |
||
958 | |||
959 | /** |
||
960 | * Get the HTTP response code from the request. |
||
961 | * |
||
962 | * @return string The HTTP response code. |
||
963 | */ |
||
964 | public function get_response_code() |
||
965 | { |
||
966 | return $this->response_code; |
||
967 | } |
||
968 | } |
||
969 | |||
970 | |||
971 | /** |
||
972 | * Container for all response-related methods. |
||
973 | */ |
||
974 | class ResponseCore |
||
1029 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.