GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — develop ( b5e3c2...7799bc )
by
unknown
15s
created

Curl::request()   F

Complexity

Conditions 23
Paths > 20000

Size

Total Lines 151
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 58
nc 31104
nop 6
dl 0
loc 151
rs 2
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
 * Part of the Joomla Framework Http Package
4
 *
5
 * @copyright  Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
6
 * @license    GNU General Public License version 2 or later; see LICENSE
7
 */
8
9
namespace Joomla\Http\Transport;
10
11
use Composer\CaBundle\CaBundle;
12
use Joomla\Http\Exception\InvalidResponseCodeException;
13
use Joomla\Http\TransportInterface;
14
use Joomla\Http\Response;
15
use Joomla\Uri\UriInterface;
16
17
/**
18
 * HTTP transport class for using cURL.
19
 *
20
 * @since  1.0
21
 */
22
class Curl implements TransportInterface
23
{
24
	/**
25
	 * The client options.
26
	 *
27
	 * @var    array|\ArrayAccess
28
	 * @since  1.0
29
	 */
30
	protected $options;
31
32
	/**
33
	 * Constructor. CURLOPT_FOLLOWLOCATION must be disabled when open_basedir or safe_mode are enabled.
34
	 *
35
	 * @param   array|\ArrayAccess  $options  Client options array.
36
	 *
37
	 * @see     http://www.php.net/manual/en/function.curl-setopt.php
38
	 * @since   1.0
39
	 * @throws  \InvalidArgumentException
40
	 * @throws  \RuntimeException
41
	 */
42 View Code Duplication
	public function __construct($options = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
43
	{
44
		if (!function_exists('curl_init') || !is_callable('curl_init'))
45
		{
46
			throw new \RuntimeException('Cannot use a cURL transport when curl_init() is not available.');
47
		}
48
49
		if (!is_array($options) && !($options instanceof \ArrayAccess))
50
		{
51
			throw new \InvalidArgumentException(
52
				'The options param must be an array or implement the ArrayAccess interface.'
53
			);
54
		}
55
56
		$this->options = $options;
57
	}
58
59
	/**
60
	 * Send a request to the server and return a Response object with the response.
61
	 *
62
	 * @param   string        $method     The HTTP method for sending the request.
63
	 * @param   UriInterface  $uri        The URI to the resource to request.
64
	 * @param   mixed         $data       Either an associative array or a string to be sent with the request.
65
	 * @param   array         $headers    An array of request headers to send with the request.
66
	 * @param   integer       $timeout    Read timeout in seconds.
67
	 * @param   string        $userAgent  The optional user agent string to send with the request.
68
	 *
69
	 * @return  Response
70
	 *
71
	 * @since   1.0
72
	 * @throws  \RuntimeException
73
	 */
74
	public function request($method, UriInterface $uri, $data = null, array $headers = null, $timeout = null, $userAgent = null)
75
	{
76
		// Setup the cURL handle.
77
		$ch = curl_init();
78
79
		$options = array();
80
81
		// Set the request method.
82
		switch (strtoupper($method))
83
		{
84
			case 'GET':
85
				$options[CURLOPT_HTTPGET] = true;
86
				break;
87
88
			case 'POST':
89
				$options[CURLOPT_POST] = true;
90
				break;
91
92
			default:
93
				$options[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
94
				break;
95
		}
96
97
		// Don't wait for body when $method is HEAD
98
		$options[CURLOPT_NOBODY] = ($method === 'HEAD');
99
100
		// Initialize the certificate store
101
		$options[CURLOPT_CAINFO] = isset($this->options['curl.certpath']) ? $this->options['curl.certpath'] : CaBundle::getSystemCaRootBundlePath();
102
103
		// If data exists let's encode it and make sure our Content-type header is set.
104
		if (isset($data))
105
		{
106
			// If the data is a scalar value simply add it to the cURL post fields.
107
			if (is_scalar($data) || (isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'multipart/form-data') === 0))
108
			{
109
				$options[CURLOPT_POSTFIELDS] = $data;
110
			}
111
			else
112
			// Otherwise we need to encode the value first.
113
			{
114
				$options[CURLOPT_POSTFIELDS] = http_build_query($data);
115
			}
116
117
			if (!isset($headers['Content-Type']))
118
			{
119
				$headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
120
			}
121
122
			// Add the relevant headers.
123
			if (is_scalar($options[CURLOPT_POSTFIELDS]))
124
			{
125
				$headers['Content-Length'] = strlen($options[CURLOPT_POSTFIELDS]);
126
			}
127
		}
128
129
		// Build the headers string for the request.
130
		$headerArray = array();
131
132
		if (isset($headers))
133
		{
134
			foreach ($headers as $key => $value)
135
			{
136
				$headerArray[] = $key . ': ' . $value;
137
			}
138
139
			// Add the headers string into the stream context options array.
140
			$options[CURLOPT_HTTPHEADER] = $headerArray;
141
		}
142
143
		// Curl needs the accepted encoding header as option
144
		if (isset($headers['Accept-Encoding']))
145
		{
146
			$options[CURLOPT_ENCODING] = $headers['Accept-Encoding'];
147
		}
148
149
		// If an explicit timeout is given user it.
150
		if (isset($timeout))
151
		{
152
			$options[CURLOPT_TIMEOUT] = (int) $timeout;
153
			$options[CURLOPT_CONNECTTIMEOUT] = (int) $timeout;
154
		}
155
156
		// If an explicit user agent is given use it.
157
		if (isset($userAgent))
158
		{
159
			$options[CURLOPT_USERAGENT] = $userAgent;
160
		}
161
162
		// Set the request URL.
163
		$options[CURLOPT_URL] = (string) $uri;
164
165
		// We want our headers. :-)
166
		$options[CURLOPT_HEADER] = true;
167
168
		// Return it... echoing it would be tacky.
169
		$options[CURLOPT_RETURNTRANSFER] = true;
170
171
		// Override the Expect header to prevent cURL from confusing itself in its own stupidity.
172
		// Link: http://the-stickman.com/web-development/php-and-curl-disabling-100-continue-header/
173
		$options[CURLOPT_HTTPHEADER][] = 'Expect:';
174
175
		// Follow redirects if server config allows
176
		if ($this->redirectsAllowed())
177
		{
178
			$options[CURLOPT_FOLLOWLOCATION] = (bool) isset($this->options['follow_location']) ? $this->options['follow_location'] : true;
179
		}
180
181
		// Authentication, if needed
182
		if (isset($this->options['userauth']) && isset($this->options['passwordauth']))
183
		{
184
			$options[CURLOPT_USERPWD]  = $this->options['userauth'] . ':' . $this->options['passwordauth'];
185
			$options[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC;
186
		}
187
188
		// Set any custom transport options
189
		if (isset($this->options['transport.curl']))
190
		{
191
			foreach ($this->options['transport.curl'] as $key => $value)
192
			{
193
				$options[$key] = $value;
194
			}
195
		}
196
197
		// Set the cURL options.
198
		curl_setopt_array($ch, $options);
199
200
		// Execute the request and close the connection.
201
		$content = curl_exec($ch);
202
203
		// Check if the content is a string. If it is not, it must be an error.
204
		if (!is_string($content))
205
		{
206
			$message = curl_error($ch);
207
208
			if (empty($message))
209
			{
210
				// Error but nothing from cURL? Create our own
211
				$message = 'No HTTP response received';
212
			}
213
214
			throw new \RuntimeException($message);
215
		}
216
217
		// Get the request information.
218
		$info = curl_getinfo($ch);
219
220
		// Close the connection.
221
		curl_close($ch);
222
223
		return $this->getResponse($content, $info);
224
	}
225
226
	/**
227
	 * Method to get a response object from a server response.
228
	 *
229
	 * @param   string  $content  The complete server response, including headers
230
	 *                            as a string if the response has no errors.
231
	 * @param   array   $info     The cURL request information.
232
	 *
233
	 * @return  Response
234
	 *
235
	 * @since   1.0
236
	 * @throws  InvalidResponseCodeException
237
	 */
238
	protected function getResponse($content, $info)
239
	{
240
		// Create the response object.
241
		$return = new Response;
242
243
		// Get the number of redirects that occurred.
244
		$redirects = isset($info['redirect_count']) ? $info['redirect_count'] : 0;
245
246
		/*
247
		 * Split the response into headers and body. If cURL encountered redirects, the headers for the redirected requests will
248
		 * also be included. So we split the response into header + body + the number of redirects and only use the last two
249
		 * sections which should be the last set of headers and the actual body.
250
		 */
251
		$response = explode("\r\n\r\n", $content, 2 + $redirects);
252
253
		// Set the body for the response.
254
		$return->body = array_pop($response);
255
256
		// Get the last set of response headers as an array.
257
		$headers = explode("\r\n", array_pop($response));
258
259
		// Get the response code from the first offset of the response headers.
260
		preg_match('/[0-9]{3}/', array_shift($headers), $matches);
261
262
		$code = count($matches) ? $matches[0] : null;
263
264
		if (is_numeric($code))
265
		{
266
			$return->code = (int) $code;
267
		}
268
269
		// No valid response code was detected.
270
		else
271
		{
272
			throw new InvalidResponseCodeException('No HTTP response code found.');
273
		}
274
275
		// Add the response headers to the response object.
276 View Code Duplication
		foreach ($headers as $header)
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...
277
		{
278
			$pos = strpos($header, ':');
279
			$return->headers[trim(substr($header, 0, $pos))] = trim(substr($header, ($pos + 1)));
280
		}
281
282
		return $return;
283
	}
284
285
	/**
286
	 * Method to check if HTTP transport cURL is available for use
287
	 *
288
	 * @return  boolean  True if available, else false
289
	 *
290
	 * @since   1.0
291
	 */
292
	public static function isSupported()
293
	{
294
		return function_exists('curl_version') && curl_version();
295
	}
296
297
	/**
298
	 * Check if redirects are allowed
299
	 *
300
	 * @return  boolean
301
	 *
302
	 * @since   1.2.1
303
	 */
304
	private function redirectsAllowed()
305
	{
306
		// There are no issues on PHP 5.6 and later
307
		if (version_compare(PHP_VERSION, '5.6', '>='))
308
		{
309
			return true;
310
		}
311
312
		// For PHP 5.3, redirects are not allowed if safe_mode and open_basedir are enabled
313
		if (PHP_MAJOR_VERSION === 5 && PHP_MINOR_VERSION === 3)
314
		{
315
			if (!ini_get('safe_mode') && !ini_get('open_basedir'))
316
			{
317
				return true;
318
			}
319
		}
320
321
		// For PHP 5.4 and 5.5, we only need to check if open_basedir is disabled
322
		return !ini_get('open_basedir');
323
	}
324
}
325