Requests_Transport_cURL::request_multiple()   C
last analyzed

Complexity

Conditions 11
Paths 31

Size

Total Lines 79
Code Lines 48

Duplication

Lines 3
Ratio 3.8 %

Importance

Changes 0
Metric Value
cc 11
eloc 48
nc 31
nop 2
dl 3
loc 79
rs 5.3086
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * cURL HTTP transport
4
 *
5
 * @package Requests
6
 * @subpackage Transport
7
 */
8
9
/**
10
 * cURL HTTP transport
11
 *
12
 * @package Requests
13
 * @subpackage Transport
14
 */
15
class Requests_Transport_cURL implements Requests_Transport {
0 ignored issues
show
Coding Style introduced by
The property $response_data is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style introduced by
The property $done_headers is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style introduced by
The property $stream_handle is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style introduced by
The property $response_bytes is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style introduced by
The property $response_byte_limit is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
Coding Style introduced by
This class is not in CamelCase format.

Classes in PHP are usually named in CamelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. The whole name starts with a capital letter as well.

Thus the name database provider becomes DatabaseProvider.

Loading history...
16
	const CURL_7_10_5 = 0x070A05;
17
	const CURL_7_16_2 = 0x071002;
18
19
	/**
20
	 * Raw HTTP data
21
	 *
22
	 * @var string
23
	 */
24
	public $headers = '';
25
26
	/**
27
	 * Raw body data
28
	 *
29
	 * @var string
30
	 */
31
	public $response_data = '';
32
33
	/**
34
	 * Information on the current request
35
	 *
36
	 * @var array cURL information array, see {@see https://secure.php.net/curl_getinfo}
37
	 */
38
	public $info;
39
40
	/**
41
	 * Version string
42
	 *
43
	 * @var long
44
	 */
45
	public $version;
46
47
	/**
48
	 * cURL handle
49
	 *
50
	 * @var resource
51
	 */
52
	protected $handle;
53
54
	/**
55
	 * Hook dispatcher instance
56
	 *
57
	 * @var Requests_Hooks
58
	 */
59
	protected $hooks;
60
61
	/**
62
	 * Have we finished the headers yet?
63
	 *
64
	 * @var boolean
65
	 */
66
	protected $done_headers = false;
67
68
	/**
69
	 * If streaming to a file, keep the file pointer
70
	 *
71
	 * @var resource
72
	 */
73
	protected $stream_handle;
74
75
	/**
76
	 * How many bytes are in the response body?
77
	 *
78
	 * @var int
79
	 */
80
	protected $response_bytes;
81
82
	/**
83
	 * What's the maximum number of bytes we should keep?
84
	 *
85
	 * @var int|bool Byte count, or false if no limit.
86
	 */
87
	protected $response_byte_limit;
88
89
	/**
90
	 * Constructor
91
	 */
92
	public function __construct() {
93
		$curl = curl_version();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
94
		$this->version = $curl['version_number'];
95
		$this->handle = curl_init();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
96
97
		curl_setopt($this->handle, CURLOPT_HEADER, false);
98
		curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1);
99
		if ($this->version >= self::CURL_7_10_5) {
100
			curl_setopt($this->handle, CURLOPT_ENCODING, '');
101
		}
102
		if (defined('CURLOPT_PROTOCOLS')) {
103
			curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
104
		}
105
		if (defined('CURLOPT_REDIR_PROTOCOLS')) {
106
			curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
107
		}
108
	}
109
110
	/**
111
	 * Destructor
112
	 */
113
	public function __destruct() {
114
		if (is_resource($this->handle)) {
115
			curl_close($this->handle);
116
		}
117
	}
118
119
	/**
120
	 * Perform a request
121
	 *
122
	 * @throws Requests_Exception On a cURL error (`curlerror`)
123
	 *
124
	 * @param string $url URL to request
125
	 * @param array $headers Associative array of request headers
126
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
127
	 * @param array $options Request options, see {@see Requests::response()} for documentation
128
	 * @return string Raw HTTP result
129
	 */
130
	public function request($url, $headers = array(), $data = array(), $options = array()) {
131
		$this->hooks = $options['hooks'];
132
133
		$this->setup_handle($url, $headers, $data, $options);
134
135
		$options['hooks']->dispatch('curl.before_send', array(&$this->handle));
136
137 View Code Duplication
		if ($options['filename'] !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
138
			$this->stream_handle = fopen($options['filename'], 'wb');
139
		}
140
141
		$this->response_data = '';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
142
		$this->response_bytes = 0;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
143
		$this->response_byte_limit = false;
144
		if ($options['max_bytes'] !== false) {
145
			$this->response_byte_limit = $options['max_bytes'];
146
		}
147
148
		if (isset($options['verify'])) {
149
			if ($options['verify'] === false) {
150
				curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
151
				curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0);
152
			}
153
			elseif (is_string($options['verify'])) {
154
				curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']);
155
			}
156
		}
157
158
		if (isset($options['verifyname']) && $options['verifyname'] === false) {
159
			curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
160
		}
161
162
		curl_exec($this->handle);
163
		$response = $this->response_data;
164
165
		$options['hooks']->dispatch('curl.after_send', array());
166
167
		if (curl_errno($this->handle) === 23 || curl_errno($this->handle) === 61) {
168
			// Reset encoding and try again
169
			curl_setopt($this->handle, CURLOPT_ENCODING, 'none');
170
171
			$this->response_data = '';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
172
			$this->response_bytes = 0;
173
			curl_exec($this->handle);
174
			$response = $this->response_data;
175
		}
176
177
		$this->process_response($response, $options);
178
179
		// Need to remove the $this reference from the curl handle.
180
		// Otherwise Requests_Transport_cURL wont be garbage collected and the curl_close() will never be called.
181
		curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null);
182
		curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null);
183
184
		return $this->headers;
185
	}
186
187
	/**
188
	 * Send multiple requests simultaneously
189
	 *
190
	 * @param array $requests Request data
191
	 * @param array $options Global options
192
	 * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
193
	 */
194
	public function request_multiple($requests, $options) {
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
195
		// If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
196
		if (empty($requests)) {
197
			return array();
198
		}
199
200
		$multihandle = curl_multi_init();
201
		$subrequests = array();
202
		$subhandles = array();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
203
204
		$class = get_class($this);
205
		foreach ($requests as $id => $request) {
206
			$subrequests[$id] = new $class();
207
			$subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 140 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
208
			$request['options']['hooks']->dispatch('curl.before_multi_add', array(&$subhandles[$id]));
209
			curl_multi_add_handle($multihandle, $subhandles[$id]);
210
		}
211
212
		$completed = 0;
213
		$responses = array();
214
215
		$request['options']['hooks']->dispatch('curl.before_multi_exec', array(&$multihandle));
0 ignored issues
show
Bug introduced by
The variable $request seems to be defined by a foreach iteration on line 205. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
216
217
		do {
218
			$active = false;
219
220
			do {
221
				$status = curl_multi_exec($multihandle, $active);
222
			}
223
			while ($status === CURLM_CALL_MULTI_PERFORM);
224
225
			$to_process = array();
226
227
			// Read the information as needed
228
			while ($done = curl_multi_info_read($multihandle)) {
229
				$key = array_search($done['handle'], $subhandles, true);
230
				if (!isset($to_process[$key])) {
231
					$to_process[$key] = $done;
232
				}
233
			}
234
235
			// Parse the finished requests before we start getting the new ones
236
			foreach ($to_process as $key => $done) {
237
				$options = $requests[$key]['options'];
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $options. This often makes code more readable.
Loading history...
238
				if (CURLE_OK !== $done['result']) {
239
					//get error string for handle.
240
					$reason = curl_error($done['handle']);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
241
					$exception = new Requests_Exception_Transport_cURL(
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
242
									$reason,
243
									Requests_Exception_Transport_cURL::EASY,
244
									$done['handle'],
245
									$done['result']
246
								);
247
					$responses[$key] = $exception;
248
					$options['hooks']->dispatch('transport.internal.parse_error', array(&$responses[$key], $requests[$key]));
249
				}
250
				else {
251
					$responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options);
252
253
					$options['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$key], $requests[$key]));
254
				}
255
256
				curl_multi_remove_handle($multihandle, $done['handle']);
257
				curl_close($done['handle']);
258
259 View Code Duplication
				if (!is_string($responses[$key])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
260
					$options['hooks']->dispatch('multiple.request.complete', array(&$responses[$key], $key));
261
				}
262
				$completed++;
263
			}
264
		}
265
		while ($active || $completed < count($subrequests));
266
267
		$request['options']['hooks']->dispatch('curl.after_multi_exec', array(&$multihandle));
268
269
		curl_multi_close($multihandle);
270
271
		return $responses;
272
	}
273
274
	/**
275
	 * Get the cURL handle for use in a multi-request
276
	 *
277
	 * @param string $url URL to request
278
	 * @param array $headers Associative array of request headers
279
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
280
	 * @param array $options Request options, see {@see Requests::response()} for documentation
281
	 * @return resource Subrequest's cURL handle
282
	 */
283
	public function &get_subrequest_handle($url, $headers, $data, $options) {
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
284
		$this->setup_handle($url, $headers, $data, $options);
285
286 View Code Duplication
		if ($options['filename'] !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
287
			$this->stream_handle = fopen($options['filename'], 'wb');
288
		}
289
290
		$this->response_data = '';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
291
		$this->response_bytes = 0;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
292
		$this->response_byte_limit = false;
293
		if ($options['max_bytes'] !== false) {
294
			$this->response_byte_limit = $options['max_bytes'];
295
		}
296
		$this->hooks = $options['hooks'];
297
298
		return $this->handle;
299
	}
300
301
	/**
302
	 * Setup the cURL handle for the given data
303
	 *
304
	 * @param string $url URL to request
305
	 * @param array $headers Associative array of request headers
306
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
307
	 * @param array $options Request options, see {@see Requests::response()} for documentation
308
	 */
309
	protected function setup_handle($url, $headers, $data, $options) {
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
310
		$options['hooks']->dispatch('curl.before_request', array(&$this->handle));
311
312
		// Force closing the connection for old versions of cURL (<7.22).
313
		if ( ! isset( $headers['Connection'] ) ) {
314
			$headers['Connection'] = 'close';
315
		}
316
317
		$headers = Requests::flatten($headers);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $headers. This often makes code more readable.
Loading history...
318
319
		if (!empty($data)) {
320
			$data_format = $options['data_format'];
321
322
			if ($data_format === 'query') {
323
				$url = self::format_get($url, $data);
0 ignored issues
show
Bug introduced by
It seems like $data defined by parameter $data on line 309 can also be of type string; however, Requests_Transport_cURL::format_get() does only seem to accept array|object, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Coding Style introduced by
Consider using a different name than the parameter $url. This often makes code more readable.
Loading history...
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
324
				$data = '';
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $data. This often makes code more readable.
Loading history...
325
			}
326
			elseif (!is_string($data)) {
327
				$data = http_build_query($data, null, '&');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $data. This often makes code more readable.
Loading history...
328
			}
329
		}
330
331
		switch ($options['type']) {
332
			case Requests::POST:
333
				curl_setopt($this->handle, CURLOPT_POST, true);
334
				curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
335
				break;
336
			case Requests::HEAD:
337
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
338
				curl_setopt($this->handle, CURLOPT_NOBODY, true);
339
				break;
340
			case Requests::TRACE:
341
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
342
				break;
343
			case Requests::PATCH:
344
			case Requests::PUT:
345
			case Requests::DELETE:
346
			case Requests::OPTIONS:
347
			default:
348
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
349
				if (!empty($data)) {
350
					curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
351
				}
352
		}
353
354
		// cURL requires a minimum timeout of 1 second when using the system
355
		// DNS resolver, as it uses `alarm()`, which is second resolution only.
356
		// There's no way to detect which DNS resolver is being used from our
357
		// end, so we need to round up regardless of the supplied timeout.
358
		//
359
		// https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609
360
		$timeout = max($options['timeout'], 1);
361
362
		if (is_int($timeout) || $this->version < self::CURL_7_16_2) {
363
			curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout));
364
		}
365
		else {
366
			curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000));
367
		}
368
369
		if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) {
370
			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout']));
371
		}
372
		else {
373
			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000));
374
		}
375
		curl_setopt($this->handle, CURLOPT_URL, $url);
376
		curl_setopt($this->handle, CURLOPT_REFERER, $url);
377
		curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
378
		if (!empty($headers)) {
379
			curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
380
		}
381
		if ($options['protocol_version'] === 1.1) {
382
			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
383
		}
384
		else {
385
			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
386
		}
387
388
		if (true === $options['blocking']) {
389
			curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, array(&$this, 'stream_headers'));
390
			curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, array(&$this, 'stream_body'));
391
			curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE);
392
		}
393
	}
394
395
	/**
396
	 * Process a response
397
	 *
398
	 * @param string $response Response data from the body
399
	 * @param array $options Request options
400
	 * @return string HTTP response data including headers
0 ignored issues
show
Documentation introduced by
Should the return type not be false|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
401
	 */
402
	public function process_response($response, $options) {
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
403
		if ($options['blocking'] === false) {
404
			$fake_headers = '';
405
			$options['hooks']->dispatch('curl.after_request', array(&$fake_headers));
406
			return false;
407
		}
408
		if ($options['filename'] !== false) {
409
			fclose($this->stream_handle);
410
			$this->headers = trim($this->headers);
411
		}
412
		else {
413
			$this->headers .= $response;
414
		}
415
416
		if (curl_errno($this->handle)) {
417
			$error = sprintf(
418
				'cURL error %s: %s',
419
				curl_errno($this->handle),
420
				curl_error($this->handle)
421
			);
422
			throw new Requests_Exception($error, 'curlerror', $this->handle);
423
		}
424
		$this->info = curl_getinfo($this->handle);
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_getinfo($this->handle) of type * is incompatible with the declared type array of property $info.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
425
426
		$options['hooks']->dispatch('curl.after_request', array(&$this->headers, &$this->info));
427
		return $this->headers;
428
	}
429
430
	/**
431
	 * Collect the headers as they are received
432
	 *
433
	 * @param resource $handle cURL resource
434
	 * @param string $headers Header string
435
	 * @return integer Length of provided header
436
	 */
437
	public function stream_headers($handle, $headers) {
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
438
		// Why do we do this? cURL will send both the final response and any
439
		// interim responses, such as a 100 Continue. We don't need that.
440
		// (We may want to keep this somewhere just in case)
441
		if ($this->done_headers) {
442
			$this->headers = '';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
443
			$this->done_headers = false;
444
		}
445
		$this->headers .= $headers;
446
447
		if ($headers === "\r\n") {
448
			$this->done_headers = true;
449
		}
450
		return strlen($headers);
451
	}
452
453
	/**
454
	 * Collect data as it's received
455
	 *
456
	 * @since 1.6.1
457
	 *
458
	 * @param resource $handle cURL resource
459
	 * @param string $data Body data
460
	 * @return integer Length of provided data
461
	 */
462
	public function stream_body($handle, $data) {
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
463
		$this->hooks->dispatch('request.progress', array($data, $this->response_bytes, $this->response_byte_limit));
464
		$data_length = strlen($data);
465
466
		// Are we limiting the response size?
467
		if ($this->response_byte_limit) {
468
			if ($this->response_bytes === $this->response_byte_limit) {
469
				// Already at maximum, move on
470
				return $data_length;
471
			}
472
473
			if (($this->response_bytes + $data_length) > $this->response_byte_limit) {
474
				// Limit the length
475
				$limited_length = ($this->response_byte_limit - $this->response_bytes);
476
				$data = substr($data, 0, $limited_length);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $data. This often makes code more readable.
Loading history...
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
477
			}
478
		}
479
480
		if ($this->stream_handle) {
481
			fwrite($this->stream_handle, $data);
482
		}
483
		else {
484
			$this->response_data .= $data;
485
		}
486
487
		$this->response_bytes += strlen($data);
488
		return $data_length;
489
	}
490
491
	/**
492
	 * Format a URL given GET data
493
	 *
494
	 * @param string $url
495
	 * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query}
496
	 * @return string URL with data
497
	 */
498
	protected static function format_get($url, $data) {
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
499
		if (!empty($data)) {
500
			$url_parts = parse_url($url);
501
			if (empty($url_parts['query'])) {
502
				$query = $url_parts['query'] = '';
503
			}
504
			else {
505
				$query = $url_parts['query'];
506
			}
507
508
			$query .= '&' . http_build_query($data, null, '&');
509
			$query = trim($query, '&');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
510
511
			if (empty($url_parts['query'])) {
512
				$url .= '?' . $query;
513
			}
514
			else {
515
				$url = str_replace($url_parts['query'], $query, $url);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $url. This often makes code more readable.
Loading history...
516
			}
517
		}
518
		return $url;
519
	}
520
521
	/**
522
	 * Whether this transport is valid
523
	 *
524
	 * @codeCoverageIgnore
525
	 * @return boolean True if the transport is valid, false otherwise.
526
	 */
527
	public static function test($capabilities = array()) {
528
		if (!function_exists('curl_init') || !function_exists('curl_exec')) {
529
			return false;
530
		}
531
532
		// If needed, check that our installed curl version supports SSL
533
		if (isset($capabilities['ssl']) && $capabilities['ssl']) {
534
			$curl_version = curl_version();
535
			if (!(CURL_VERSION_SSL & $curl_version['features'])) {
536
				return false;
537
			}
538
		}
539
540
		return true;
541
	}
542
}
0 ignored issues
show
Coding Style introduced by
As per coding style, files should not end with a newline character.

This check marks files that end in a newline character, i.e. an empy line.

Loading history...
543