Completed
Pull Request — 1.11.x (#1599)
by José
28:19
created
plugin/buycourses/src/Requests/Hooks.php 1 patch
Indentation   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -13,56 +13,56 @@
 block discarded – undo
13 13
  * @subpackage Utilities
14 14
  */
15 15
 class Requests_Hooks implements Requests_Hooker {
16
-	/**
17
-	 * Registered callbacks for each hook
18
-	 *
19
-	 * @var array
20
-	 */
21
-	protected $hooks = array();
16
+    /**
17
+     * Registered callbacks for each hook
18
+     *
19
+     * @var array
20
+     */
21
+    protected $hooks = array();
22 22
 
23
-	/**
24
-	 * Constructor
25
-	 */
26
-	public function __construct() {
27
-		// pass
28
-	}
23
+    /**
24
+     * Constructor
25
+     */
26
+    public function __construct() {
27
+        // pass
28
+    }
29 29
 
30
-	/**
31
-	 * Register a callback for a hook
32
-	 *
33
-	 * @param string $hook Hook name
34
-	 * @param callback $callback Function/method to call on event
35
-	 * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
36
-	 */
37
-	public function register($hook, $callback, $priority = 0) {
38
-		if (!isset($this->hooks[$hook])) {
39
-			$this->hooks[$hook] = array();
40
-		}
41
-		if (!isset($this->hooks[$hook][$priority])) {
42
-			$this->hooks[$hook][$priority] = array();
43
-		}
30
+    /**
31
+     * Register a callback for a hook
32
+     *
33
+     * @param string $hook Hook name
34
+     * @param callback $callback Function/method to call on event
35
+     * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
36
+     */
37
+    public function register($hook, $callback, $priority = 0) {
38
+        if (!isset($this->hooks[$hook])) {
39
+            $this->hooks[$hook] = array();
40
+        }
41
+        if (!isset($this->hooks[$hook][$priority])) {
42
+            $this->hooks[$hook][$priority] = array();
43
+        }
44 44
 
45
-		$this->hooks[$hook][$priority][] = $callback;
46
-	}
45
+        $this->hooks[$hook][$priority][] = $callback;
46
+    }
47 47
 
48
-	/**
49
-	 * Dispatch a message
50
-	 *
51
-	 * @param string $hook Hook name
52
-	 * @param array $parameters Parameters to pass to callbacks
53
-	 * @return boolean Successfulness
54
-	 */
55
-	public function dispatch($hook, $parameters = array()) {
56
-		if (empty($this->hooks[$hook])) {
57
-			return false;
58
-		}
48
+    /**
49
+     * Dispatch a message
50
+     *
51
+     * @param string $hook Hook name
52
+     * @param array $parameters Parameters to pass to callbacks
53
+     * @return boolean Successfulness
54
+     */
55
+    public function dispatch($hook, $parameters = array()) {
56
+        if (empty($this->hooks[$hook])) {
57
+            return false;
58
+        }
59 59
 
60
-		foreach ($this->hooks[$hook] as $priority => $hooked) {
61
-			foreach ($hooked as $callback) {
62
-				call_user_func_array($callback, $parameters);
63
-			}
64
-		}
60
+        foreach ($this->hooks[$hook] as $priority => $hooked) {
61
+            foreach ($hooked as $callback) {
62
+                call_user_func_array($callback, $parameters);
63
+            }
64
+        }
65 65
 
66
-		return true;
67
-	}
66
+        return true;
67
+    }
68 68
 }
69 69
\ No newline at end of file
Please login to merge, or discard this patch.
plugin/buycourses/src/Requests/Transport.php 1 patch
Indentation   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -13,29 +13,29 @@
 block discarded – undo
13 13
  * @subpackage Transport
14 14
  */
15 15
 interface Requests_Transport {
16
-	/**
17
-	 * Perform a request
18
-	 *
19
-	 * @param string $url URL to request
20
-	 * @param array $headers Associative array of request headers
21
-	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
22
-	 * @param array $options Request options, see {@see Requests::response()} for documentation
23
-	 * @return string Raw HTTP result
24
-	 */
25
-	public function request($url, $headers = array(), $data = array(), $options = array());
16
+    /**
17
+     * Perform a request
18
+     *
19
+     * @param string $url URL to request
20
+     * @param array $headers Associative array of request headers
21
+     * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
22
+     * @param array $options Request options, see {@see Requests::response()} for documentation
23
+     * @return string Raw HTTP result
24
+     */
25
+    public function request($url, $headers = array(), $data = array(), $options = array());
26 26
 
27
-	/**
28
-	 * Send multiple requests simultaneously
29
-	 *
30
-	 * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request}
31
-	 * @param array $options Global options, see {@see Requests::response()} for documentation
32
-	 * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
33
-	 */
34
-	public function request_multiple($requests, $options);
27
+    /**
28
+     * Send multiple requests simultaneously
29
+     *
30
+     * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request}
31
+     * @param array $options Global options, see {@see Requests::response()} for documentation
32
+     * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
33
+     */
34
+    public function request_multiple($requests, $options);
35 35
 
36
-	/**
37
-	 * Self-test whether the transport can be used
38
-	 * @return bool
39
-	 */
40
-	public static function test();
36
+    /**
37
+     * Self-test whether the transport can be used
38
+     * @return bool
39
+     */
40
+    public static function test();
41 41
 }
42 42
\ No newline at end of file
Please login to merge, or discard this patch.
plugin/buycourses/src/Requests/IRI.php 1 patch
Indentation   +1017 added lines, -1017 removed lines patch added patch discarded remove patch
@@ -64,1021 +64,1021 @@
 block discarded – undo
64 64
  * @property string $ifragment Fragment part of the IRI (after '#')
65 65
  */
66 66
 class Requests_IRI {
67
-	/**
68
-	 * Scheme
69
-	 *
70
-	 * @var string
71
-	 */
72
-	protected $scheme = null;
73
-
74
-	/**
75
-	 * User Information
76
-	 *
77
-	 * @var string
78
-	 */
79
-	protected $iuserinfo = null;
80
-
81
-	/**
82
-	 * ihost
83
-	 *
84
-	 * @var string
85
-	 */
86
-	protected $ihost = null;
87
-
88
-	/**
89
-	 * Port
90
-	 *
91
-	 * @var string
92
-	 */
93
-	protected $port = null;
94
-
95
-	/**
96
-	 * ipath
97
-	 *
98
-	 * @var string
99
-	 */
100
-	protected $ipath = '';
101
-
102
-	/**
103
-	 * iquery
104
-	 *
105
-	 * @var string
106
-	 */
107
-	protected $iquery = null;
108
-
109
-	/**
110
-	 * ifragment
111
-	 *
112
-	 * @var string
113
-	 */
114
-	protected $ifragment = null;
115
-
116
-	/**
117
-	 * Normalization database
118
-	 *
119
-	 * Each key is the scheme, each value is an array with each key as the IRI
120
-	 * part and value as the default value for that part.
121
-	 */
122
-	protected $normalization = array(
123
-		'acap' => array(
124
-			'port' => 674
125
-		),
126
-		'dict' => array(
127
-			'port' => 2628
128
-		),
129
-		'file' => array(
130
-			'ihost' => 'localhost'
131
-		),
132
-		'http' => array(
133
-			'port' => 80,
134
-		),
135
-		'https' => array(
136
-			'port' => 443,
137
-		),
138
-	);
139
-
140
-	/**
141
-	 * Return the entire IRI when you try and read the object as a string
142
-	 *
143
-	 * @return string
144
-	 */
145
-	public function __toString() {
146
-		return $this->get_iri();
147
-	}
148
-
149
-	/**
150
-	 * Overload __set() to provide access via properties
151
-	 *
152
-	 * @param string $name Property name
153
-	 * @param mixed $value Property value
154
-	 */
155
-	public function __set($name, $value) {
156
-		if (method_exists($this, 'set_' . $name)) {
157
-			call_user_func(array($this, 'set_' . $name), $value);
158
-		}
159
-		elseif (
160
-			   $name === 'iauthority'
161
-			|| $name === 'iuserinfo'
162
-			|| $name === 'ihost'
163
-			|| $name === 'ipath'
164
-			|| $name === 'iquery'
165
-			|| $name === 'ifragment'
166
-		) {
167
-			call_user_func(array($this, 'set_' . substr($name, 1)), $value);
168
-		}
169
-	}
170
-
171
-	/**
172
-	 * Overload __get() to provide access via properties
173
-	 *
174
-	 * @param string $name Property name
175
-	 * @return mixed
176
-	 */
177
-	public function __get($name) {
178
-		// isset() returns false for null, we don't want to do that
179
-		// Also why we use array_key_exists below instead of isset()
180
-		$props = get_object_vars($this);
181
-
182
-		if (
183
-			$name === 'iri' ||
184
-			$name === 'uri' ||
185
-			$name === 'iauthority' ||
186
-			$name === 'authority'
187
-		) {
188
-			$method = 'get_' . $name;
189
-			$return = $this->$method();
190
-		}
191
-		elseif (array_key_exists($name, $props)) {
192
-			$return = $this->$name;
193
-		}
194
-		// host -> ihost
195
-		elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) {
196
-			$name = $prop;
197
-			$return = $this->$prop;
198
-		}
199
-		// ischeme -> scheme
200
-		elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) {
201
-			$name = $prop;
202
-			$return = $this->$prop;
203
-		}
204
-		else {
205
-			trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
206
-			$return = null;
207
-		}
208
-
209
-		if ($return === null && isset($this->normalization[$this->scheme][$name])) {
210
-			return $this->normalization[$this->scheme][$name];
211
-		}
212
-		else {
213
-			return $return;
214
-		}
215
-	}
216
-
217
-	/**
218
-	 * Overload __isset() to provide access via properties
219
-	 *
220
-	 * @param string $name Property name
221
-	 * @return bool
222
-	 */
223
-	public function __isset($name) {
224
-		return (method_exists($this, 'get_' . $name) || isset($this->$name));
225
-	}
226
-
227
-	/**
228
-	 * Overload __unset() to provide access via properties
229
-	 *
230
-	 * @param string $name Property name
231
-	 */
232
-	public function __unset($name) {
233
-		if (method_exists($this, 'set_' . $name)) {
234
-			call_user_func(array($this, 'set_' . $name), '');
235
-		}
236
-	}
237
-
238
-	/**
239
-	 * Create a new IRI object, from a specified string
240
-	 *
241
-	 * @param string|null $iri
242
-	 */
243
-	public function __construct($iri = null) {
244
-		$this->set_iri($iri);
245
-	}
246
-
247
-	/**
248
-	 * Create a new IRI object by resolving a relative IRI
249
-	 *
250
-	 * Returns false if $base is not absolute, otherwise an IRI.
251
-	 *
252
-	 * @param IRI|string $base (Absolute) Base IRI
253
-	 * @param IRI|string $relative Relative IRI
254
-	 * @return IRI|false
255
-	 */
256
-	public static function absolutize($base, $relative) {
257
-		if (!($relative instanceof Requests_IRI)) {
258
-			$relative = new Requests_IRI($relative);
259
-		}
260
-		if (!$relative->is_valid()) {
261
-			return false;
262
-		}
263
-		elseif ($relative->scheme !== null) {
264
-			return clone $relative;
265
-		}
266
-
267
-		if (!($base instanceof Requests_IRI)) {
268
-			$base = new Requests_IRI($base);
269
-		}
270
-		if ($base->scheme === null || !$base->is_valid()) {
271
-			return false;
272
-		}
273
-
274
-		if ($relative->get_iri() !== '') {
275
-			if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) {
276
-				$target = clone $relative;
277
-				$target->scheme = $base->scheme;
278
-			}
279
-			else {
280
-				$target = new Requests_IRI;
281
-				$target->scheme = $base->scheme;
282
-				$target->iuserinfo = $base->iuserinfo;
283
-				$target->ihost = $base->ihost;
284
-				$target->port = $base->port;
285
-				if ($relative->ipath !== '') {
286
-					if ($relative->ipath[0] === '/') {
287
-						$target->ipath = $relative->ipath;
288
-					}
289
-					elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') {
290
-						$target->ipath = '/' . $relative->ipath;
291
-					}
292
-					elseif (($last_segment = strrpos($base->ipath, '/')) !== false) {
293
-						$target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
294
-					}
295
-					else {
296
-						$target->ipath = $relative->ipath;
297
-					}
298
-					$target->ipath = $target->remove_dot_segments($target->ipath);
299
-					$target->iquery = $relative->iquery;
300
-				}
301
-				else {
302
-					$target->ipath = $base->ipath;
303
-					if ($relative->iquery !== null) {
304
-						$target->iquery = $relative->iquery;
305
-					}
306
-					elseif ($base->iquery !== null) {
307
-						$target->iquery = $base->iquery;
308
-					}
309
-				}
310
-				$target->ifragment = $relative->ifragment;
311
-			}
312
-		}
313
-		else {
314
-			$target = clone $base;
315
-			$target->ifragment = null;
316
-		}
317
-		$target->scheme_normalization();
318
-		return $target;
319
-	}
320
-
321
-	/**
322
-	 * Parse an IRI into scheme/authority/path/query/fragment segments
323
-	 *
324
-	 * @param string $iri
325
-	 * @return array
326
-	 */
327
-	protected function parse_iri($iri) {
328
-		$iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
329
-		$has_match = preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match);
330
-		if (!$has_match) {
331
-			throw new Requests_Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri);
332
-		}
333
-
334
-		if ($match[1] === '') {
335
-			$match['scheme'] = null;
336
-		}
337
-		if (!isset($match[3]) || $match[3] === '') {
338
-			$match['authority'] = null;
339
-		}
340
-		if (!isset($match[5])) {
341
-			$match['path'] = '';
342
-		}
343
-		if (!isset($match[6]) || $match[6] === '') {
344
-			$match['query'] = null;
345
-		}
346
-		if (!isset($match[8]) || $match[8] === '') {
347
-			$match['fragment'] = null;
348
-		}
349
-		return $match;
350
-	}
351
-
352
-	/**
353
-	 * Remove dot segments from a path
354
-	 *
355
-	 * @param string $input
356
-	 * @return string
357
-	 */
358
-	protected function remove_dot_segments($input) {
359
-		$output = '';
360
-		while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') {
361
-			// A: If the input buffer begins with a prefix of "../" or "./",
362
-			// then remove that prefix from the input buffer; otherwise,
363
-			if (strpos($input, '../') === 0) {
364
-				$input = substr($input, 3);
365
-			}
366
-			elseif (strpos($input, './') === 0) {
367
-				$input = substr($input, 2);
368
-			}
369
-			// B: if the input buffer begins with a prefix of "/./" or "/.",
370
-			// where "." is a complete path segment, then replace that prefix
371
-			// with "/" in the input buffer; otherwise,
372
-			elseif (strpos($input, '/./') === 0) {
373
-				$input = substr($input, 2);
374
-			}
375
-			elseif ($input === '/.') {
376
-				$input = '/';
377
-			}
378
-			// C: if the input buffer begins with a prefix of "/../" or "/..",
379
-			// where ".." is a complete path segment, then replace that prefix
380
-			// with "/" in the input buffer and remove the last segment and its
381
-			// preceding "/" (if any) from the output buffer; otherwise,
382
-			elseif (strpos($input, '/../') === 0) {
383
-				$input = substr($input, 3);
384
-				$output = substr_replace($output, '', strrpos($output, '/'));
385
-			}
386
-			elseif ($input === '/..') {
387
-				$input = '/';
388
-				$output = substr_replace($output, '', strrpos($output, '/'));
389
-			}
390
-			// D: if the input buffer consists only of "." or "..", then remove
391
-			// that from the input buffer; otherwise,
392
-			elseif ($input === '.' || $input === '..') {
393
-				$input = '';
394
-			}
395
-			// E: move the first path segment in the input buffer to the end of
396
-			// the output buffer, including the initial "/" character (if any)
397
-			// and any subsequent characters up to, but not including, the next
398
-			// "/" character or the end of the input buffer
399
-			elseif (($pos = strpos($input, '/', 1)) !== false) {
400
-				$output .= substr($input, 0, $pos);
401
-				$input = substr_replace($input, '', 0, $pos);
402
-			}
403
-			else {
404
-				$output .= $input;
405
-				$input = '';
406
-			}
407
-		}
408
-		return $output . $input;
409
-	}
410
-
411
-	/**
412
-	 * Replace invalid character with percent encoding
413
-	 *
414
-	 * @param string $string Input string
415
-	 * @param string $extra_chars Valid characters not in iunreserved or
416
-	 *                            iprivate (this is ASCII-only)
417
-	 * @param bool $iprivate Allow iprivate
418
-	 * @return string
419
-	 */
420
-	protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) {
421
-		// Normalize as many pct-encoded sections as possible
422
-		$string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string);
423
-
424
-		// Replace invalid percent characters
425
-		$string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
426
-
427
-		// Add unreserved and % to $extra_chars (the latter is safe because all
428
-		// pct-encoded sections are now valid).
429
-		$extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
430
-
431
-		// Now replace any bytes that aren't allowed with their pct-encoded versions
432
-		$position = 0;
433
-		$strlen = strlen($string);
434
-		while (($position += strspn($string, $extra_chars, $position)) < $strlen) {
435
-			$value = ord($string[$position]);
436
-
437
-			// Start position
438
-			$start = $position;
439
-
440
-			// By default we are valid
441
-			$valid = true;
442
-
443
-			// No one byte sequences are valid due to the while.
444
-			// Two byte sequence:
445
-			if (($value & 0xE0) === 0xC0) {
446
-				$character = ($value & 0x1F) << 6;
447
-				$length = 2;
448
-				$remaining = 1;
449
-			}
450
-			// Three byte sequence:
451
-			elseif (($value & 0xF0) === 0xE0) {
452
-				$character = ($value & 0x0F) << 12;
453
-				$length = 3;
454
-				$remaining = 2;
455
-			}
456
-			// Four byte sequence:
457
-			elseif (($value & 0xF8) === 0xF0) {
458
-				$character = ($value & 0x07) << 18;
459
-				$length = 4;
460
-				$remaining = 3;
461
-			}
462
-			// Invalid byte:
463
-			else {
464
-				$valid = false;
465
-				$length = 1;
466
-				$remaining = 0;
467
-			}
468
-
469
-			if ($remaining) {
470
-				if ($position + $length <= $strlen) {
471
-					for ($position++; $remaining; $position++) {
472
-						$value = ord($string[$position]);
473
-
474
-						// Check that the byte is valid, then add it to the character:
475
-						if (($value & 0xC0) === 0x80) {
476
-							$character |= ($value & 0x3F) << (--$remaining * 6);
477
-						}
478
-						// If it is invalid, count the sequence as invalid and reprocess the current byte:
479
-						else {
480
-							$valid = false;
481
-							$position--;
482
-							break;
483
-						}
484
-					}
485
-				}
486
-				else {
487
-					$position = $strlen - 1;
488
-					$valid = false;
489
-				}
490
-			}
491
-
492
-			// Percent encode anything invalid or not in ucschar
493
-			if (
494
-				// Invalid sequences
495
-				!$valid
496
-				// Non-shortest form sequences are invalid
497
-				|| $length > 1 && $character <= 0x7F
498
-				|| $length > 2 && $character <= 0x7FF
499
-				|| $length > 3 && $character <= 0xFFFF
500
-				// Outside of range of ucschar codepoints
501
-				// Noncharacters
502
-				|| ($character & 0xFFFE) === 0xFFFE
503
-				|| $character >= 0xFDD0 && $character <= 0xFDEF
504
-				|| (
505
-					// Everything else not in ucschar
506
-					   $character > 0xD7FF && $character < 0xF900
507
-					|| $character < 0xA0
508
-					|| $character > 0xEFFFD
509
-				)
510
-				&& (
511
-					// Everything not in iprivate, if it applies
512
-					   !$iprivate
513
-					|| $character < 0xE000
514
-					|| $character > 0x10FFFD
515
-				)
516
-			) {
517
-				// If we were a character, pretend we weren't, but rather an error.
518
-				if ($valid) {
519
-					$position--;
520
-				}
521
-
522
-				for ($j = $start; $j <= $position; $j++) {
523
-					$string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
524
-					$j += 2;
525
-					$position += 2;
526
-					$strlen += 2;
527
-				}
528
-			}
529
-		}
530
-
531
-		return $string;
532
-	}
533
-
534
-	/**
535
-	 * Callback function for preg_replace_callback.
536
-	 *
537
-	 * Removes sequences of percent encoded bytes that represent UTF-8
538
-	 * encoded characters in iunreserved
539
-	 *
540
-	 * @param array $match PCRE match
541
-	 * @return string Replacement
542
-	 */
543
-	protected function remove_iunreserved_percent_encoded($match) {
544
-		// As we just have valid percent encoded sequences we can just explode
545
-		// and ignore the first member of the returned array (an empty string).
546
-		$bytes = explode('%', $match[0]);
547
-
548
-		// Initialize the new string (this is what will be returned) and that
549
-		// there are no bytes remaining in the current sequence (unsurprising
550
-		// at the first byte!).
551
-		$string = '';
552
-		$remaining = 0;
553
-
554
-		// Loop over each and every byte, and set $value to its value
555
-		for ($i = 1, $len = count($bytes); $i < $len; $i++) {
556
-			$value = hexdec($bytes[$i]);
557
-
558
-			// If we're the first byte of sequence:
559
-			if (!$remaining) {
560
-				// Start position
561
-				$start = $i;
562
-
563
-				// By default we are valid
564
-				$valid = true;
565
-
566
-				// One byte sequence:
567
-				if ($value <= 0x7F) {
568
-					$character = $value;
569
-					$length = 1;
570
-				}
571
-				// Two byte sequence:
572
-				elseif (($value & 0xE0) === 0xC0) {
573
-					$character = ($value & 0x1F) << 6;
574
-					$length = 2;
575
-					$remaining = 1;
576
-				}
577
-				// Three byte sequence:
578
-				elseif (($value & 0xF0) === 0xE0) {
579
-					$character = ($value & 0x0F) << 12;
580
-					$length = 3;
581
-					$remaining = 2;
582
-				}
583
-				// Four byte sequence:
584
-				elseif (($value & 0xF8) === 0xF0) {
585
-					$character = ($value & 0x07) << 18;
586
-					$length = 4;
587
-					$remaining = 3;
588
-				}
589
-				// Invalid byte:
590
-				else {
591
-					$valid = false;
592
-					$remaining = 0;
593
-				}
594
-			}
595
-			// Continuation byte:
596
-			else {
597
-				// Check that the byte is valid, then add it to the character:
598
-				if (($value & 0xC0) === 0x80) {
599
-					$remaining--;
600
-					$character |= ($value & 0x3F) << ($remaining * 6);
601
-				}
602
-				// If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
603
-				else {
604
-					$valid = false;
605
-					$remaining = 0;
606
-					$i--;
607
-				}
608
-			}
609
-
610
-			// If we've reached the end of the current byte sequence, append it to Unicode::$data
611
-			if (!$remaining) {
612
-				// Percent encode anything invalid or not in iunreserved
613
-				if (
614
-					// Invalid sequences
615
-					!$valid
616
-					// Non-shortest form sequences are invalid
617
-					|| $length > 1 && $character <= 0x7F
618
-					|| $length > 2 && $character <= 0x7FF
619
-					|| $length > 3 && $character <= 0xFFFF
620
-					// Outside of range of iunreserved codepoints
621
-					|| $character < 0x2D
622
-					|| $character > 0xEFFFD
623
-					// Noncharacters
624
-					|| ($character & 0xFFFE) === 0xFFFE
625
-					|| $character >= 0xFDD0 && $character <= 0xFDEF
626
-					// Everything else not in iunreserved (this is all BMP)
627
-					|| $character === 0x2F
628
-					|| $character > 0x39 && $character < 0x41
629
-					|| $character > 0x5A && $character < 0x61
630
-					|| $character > 0x7A && $character < 0x7E
631
-					|| $character > 0x7E && $character < 0xA0
632
-					|| $character > 0xD7FF && $character < 0xF900
633
-				) {
634
-					for ($j = $start; $j <= $i; $j++) {
635
-						$string .= '%' . strtoupper($bytes[$j]);
636
-					}
637
-				}
638
-				else {
639
-					for ($j = $start; $j <= $i; $j++) {
640
-						$string .= chr(hexdec($bytes[$j]));
641
-					}
642
-				}
643
-			}
644
-		}
645
-
646
-		// If we have any bytes left over they are invalid (i.e., we are
647
-		// mid-way through a multi-byte sequence)
648
-		if ($remaining) {
649
-			for ($j = $start; $j < $len; $j++) {
650
-				$string .= '%' . strtoupper($bytes[$j]);
651
-			}
652
-		}
653
-
654
-		return $string;
655
-	}
656
-
657
-	protected function scheme_normalization() {
658
-		if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) {
659
-			$this->iuserinfo = null;
660
-		}
661
-		if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) {
662
-			$this->ihost = null;
663
-		}
664
-		if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) {
665
-			$this->port = null;
666
-		}
667
-		if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) {
668
-			$this->ipath = '';
669
-		}
670
-		if (isset($this->ihost) && empty($this->ipath)) {
671
-			$this->ipath = '/';
672
-		}
673
-		if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) {
674
-			$this->iquery = null;
675
-		}
676
-		if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) {
677
-			$this->ifragment = null;
678
-		}
679
-	}
680
-
681
-	/**
682
-	 * Check if the object represents a valid IRI. This needs to be done on each
683
-	 * call as some things change depending on another part of the IRI.
684
-	 *
685
-	 * @return bool
686
-	 */
687
-	public function is_valid() {
688
-		$isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
689
-		if ($this->ipath !== '' &&
690
-			(
691
-				$isauthority && $this->ipath[0] !== '/' ||
692
-				(
693
-					$this->scheme === null &&
694
-					!$isauthority &&
695
-					strpos($this->ipath, ':') !== false &&
696
-					(strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
697
-				)
698
-			)
699
-		) {
700
-			return false;
701
-		}
702
-
703
-		return true;
704
-	}
705
-
706
-	/**
707
-	 * Set the entire IRI. Returns true on success, false on failure (if there
708
-	 * are any invalid characters).
709
-	 *
710
-	 * @param string $iri
711
-	 * @return bool
712
-	 */
713
-	protected function set_iri($iri) {
714
-		static $cache;
715
-		if (!$cache) {
716
-			$cache = array();
717
-		}
718
-
719
-		if ($iri === null) {
720
-			return true;
721
-		}
722
-		if (isset($cache[$iri])) {
723
-			list($this->scheme,
724
-				 $this->iuserinfo,
725
-				 $this->ihost,
726
-				 $this->port,
727
-				 $this->ipath,
728
-				 $this->iquery,
729
-				 $this->ifragment,
730
-				 $return) = $cache[$iri];
731
-			return $return;
732
-		}
733
-
734
-		$parsed = $this->parse_iri((string) $iri);
735
-
736
-		$return = $this->set_scheme($parsed['scheme'])
737
-			&& $this->set_authority($parsed['authority'])
738
-			&& $this->set_path($parsed['path'])
739
-			&& $this->set_query($parsed['query'])
740
-			&& $this->set_fragment($parsed['fragment']);
741
-
742
-		$cache[$iri] = array($this->scheme,
743
-							 $this->iuserinfo,
744
-							 $this->ihost,
745
-							 $this->port,
746
-							 $this->ipath,
747
-							 $this->iquery,
748
-							 $this->ifragment,
749
-							 $return);
750
-		return $return;
751
-	}
752
-
753
-	/**
754
-	 * Set the scheme. Returns true on success, false on failure (if there are
755
-	 * any invalid characters).
756
-	 *
757
-	 * @param string $scheme
758
-	 * @return bool
759
-	 */
760
-	protected function set_scheme($scheme) {
761
-		if ($scheme === null) {
762
-			$this->scheme = null;
763
-		}
764
-		elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) {
765
-			$this->scheme = null;
766
-			return false;
767
-		}
768
-		else {
769
-			$this->scheme = strtolower($scheme);
770
-		}
771
-		return true;
772
-	}
773
-
774
-	/**
775
-	 * Set the authority. Returns true on success, false on failure (if there are
776
-	 * any invalid characters).
777
-	 *
778
-	 * @param string $authority
779
-	 * @return bool
780
-	 */
781
-	protected function set_authority($authority) {
782
-		static $cache;
783
-		if (!$cache) {
784
-			$cache = array();
785
-		}
786
-
787
-		if ($authority === null) {
788
-			$this->iuserinfo = null;
789
-			$this->ihost = null;
790
-			$this->port = null;
791
-			return true;
792
-		}
793
-		if (isset($cache[$authority])) {
794
-			list($this->iuserinfo,
795
-				 $this->ihost,
796
-				 $this->port,
797
-				 $return) = $cache[$authority];
798
-
799
-			return $return;
800
-		}
801
-
802
-		$remaining = $authority;
803
-		if (($iuserinfo_end = strrpos($remaining, '@')) !== false) {
804
-			$iuserinfo = substr($remaining, 0, $iuserinfo_end);
805
-			$remaining = substr($remaining, $iuserinfo_end + 1);
806
-		}
807
-		else {
808
-			$iuserinfo = null;
809
-		}
810
-		if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) {
811
-			$port = substr($remaining, $port_start + 1);
812
-			if ($port === false || $port === '') {
813
-				$port = null;
814
-			}
815
-			$remaining = substr($remaining, 0, $port_start);
816
-		}
817
-		else {
818
-			$port = null;
819
-		}
820
-
821
-		$return = $this->set_userinfo($iuserinfo) &&
822
-				  $this->set_host($remaining) &&
823
-				  $this->set_port($port);
824
-
825
-		$cache[$authority] = array($this->iuserinfo,
826
-								   $this->ihost,
827
-								   $this->port,
828
-								   $return);
829
-
830
-		return $return;
831
-	}
832
-
833
-	/**
834
-	 * Set the iuserinfo.
835
-	 *
836
-	 * @param string $iuserinfo
837
-	 * @return bool
838
-	 */
839
-	protected function set_userinfo($iuserinfo) {
840
-		if ($iuserinfo === null) {
841
-			$this->iuserinfo = null;
842
-		}
843
-		else {
844
-			$this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
845
-			$this->scheme_normalization();
846
-		}
847
-
848
-		return true;
849
-	}
850
-
851
-	/**
852
-	 * Set the ihost. Returns true on success, false on failure (if there are
853
-	 * any invalid characters).
854
-	 *
855
-	 * @param string $ihost
856
-	 * @return bool
857
-	 */
858
-	protected function set_host($ihost) {
859
-		if ($ihost === null) {
860
-			$this->ihost = null;
861
-			return true;
862
-		}
863
-		if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') {
864
-			if (Requests_IPv6::check_ipv6(substr($ihost, 1, -1))) {
865
-				$this->ihost = '[' . Requests_IPv6::compress(substr($ihost, 1, -1)) . ']';
866
-			}
867
-			else {
868
-				$this->ihost = null;
869
-				return false;
870
-			}
871
-		}
872
-		else {
873
-			$ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
874
-
875
-			// Lowercase, but ignore pct-encoded sections (as they should
876
-			// remain uppercase). This must be done after the previous step
877
-			// as that can add unescaped characters.
878
-			$position = 0;
879
-			$strlen = strlen($ihost);
880
-			while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) {
881
-				if ($ihost[$position] === '%') {
882
-					$position += 3;
883
-				}
884
-				else {
885
-					$ihost[$position] = strtolower($ihost[$position]);
886
-					$position++;
887
-				}
888
-			}
889
-
890
-			$this->ihost = $ihost;
891
-		}
892
-
893
-		$this->scheme_normalization();
894
-
895
-		return true;
896
-	}
897
-
898
-	/**
899
-	 * Set the port. Returns true on success, false on failure (if there are
900
-	 * any invalid characters).
901
-	 *
902
-	 * @param string $port
903
-	 * @return bool
904
-	 */
905
-	protected function set_port($port) {
906
-		if ($port === null) {
907
-			$this->port = null;
908
-			return true;
909
-		}
910
-
911
-		if (strspn($port, '0123456789') === strlen($port)) {
912
-			$this->port = (int) $port;
913
-			$this->scheme_normalization();
914
-			return true;
915
-		}
916
-
917
-		$this->port = null;
918
-		return false;
919
-	}
920
-
921
-	/**
922
-	 * Set the ipath.
923
-	 *
924
-	 * @param string $ipath
925
-	 * @return bool
926
-	 */
927
-	protected function set_path($ipath) {
928
-		static $cache;
929
-		if (!$cache) {
930
-			$cache = array();
931
-		}
932
-
933
-		$ipath = (string) $ipath;
934
-
935
-		if (isset($cache[$ipath])) {
936
-			$this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
937
-		}
938
-		else {
939
-			$valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
940
-			$removed = $this->remove_dot_segments($valid);
941
-
942
-			$cache[$ipath] = array($valid, $removed);
943
-			$this->ipath = ($this->scheme !== null) ? $removed : $valid;
944
-		}
945
-		$this->scheme_normalization();
946
-		return true;
947
-	}
948
-
949
-	/**
950
-	 * Set the iquery.
951
-	 *
952
-	 * @param string $iquery
953
-	 * @return bool
954
-	 */
955
-	protected function set_query($iquery) {
956
-		if ($iquery === null) {
957
-			$this->iquery = null;
958
-		}
959
-		else {
960
-			$this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
961
-			$this->scheme_normalization();
962
-		}
963
-		return true;
964
-	}
965
-
966
-	/**
967
-	 * Set the ifragment.
968
-	 *
969
-	 * @param string $ifragment
970
-	 * @return bool
971
-	 */
972
-	protected function set_fragment($ifragment) {
973
-		if ($ifragment === null) {
974
-			$this->ifragment = null;
975
-		}
976
-		else {
977
-			$this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
978
-			$this->scheme_normalization();
979
-		}
980
-		return true;
981
-	}
982
-
983
-	/**
984
-	 * Convert an IRI to a URI (or parts thereof)
985
-	 *
986
-	 * @param string|bool IRI to convert (or false from {@see get_iri})
987
-	 * @return string|false URI if IRI is valid, false otherwise.
988
-	 */
989
-	protected function to_uri($string) {
990
-		if (!is_string($string)) {
991
-			return false;
992
-		}
993
-
994
-		static $non_ascii;
995
-		if (!$non_ascii) {
996
-			$non_ascii = implode('', range("\x80", "\xFF"));
997
-		}
998
-
999
-		$position = 0;
1000
-		$strlen = strlen($string);
1001
-		while (($position += strcspn($string, $non_ascii, $position)) < $strlen) {
1002
-			$string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
1003
-			$position += 3;
1004
-			$strlen += 2;
1005
-		}
1006
-
1007
-		return $string;
1008
-	}
1009
-
1010
-	/**
1011
-	 * Get the complete IRI
1012
-	 *
1013
-	 * @return string
1014
-	 */
1015
-	protected function get_iri() {
1016
-		if (!$this->is_valid()) {
1017
-			return false;
1018
-		}
1019
-
1020
-		$iri = '';
1021
-		if ($this->scheme !== null) {
1022
-			$iri .= $this->scheme . ':';
1023
-		}
1024
-		if (($iauthority = $this->get_iauthority()) !== null) {
1025
-			$iri .= '//' . $iauthority;
1026
-		}
1027
-		$iri .= $this->ipath;
1028
-		if ($this->iquery !== null) {
1029
-			$iri .= '?' . $this->iquery;
1030
-		}
1031
-		if ($this->ifragment !== null) {
1032
-			$iri .= '#' . $this->ifragment;
1033
-		}
1034
-
1035
-		return $iri;
1036
-	}
1037
-
1038
-	/**
1039
-	 * Get the complete URI
1040
-	 *
1041
-	 * @return string
1042
-	 */
1043
-	protected function get_uri() {
1044
-		return $this->to_uri($this->get_iri());
1045
-	}
1046
-
1047
-	/**
1048
-	 * Get the complete iauthority
1049
-	 *
1050
-	 * @return string
1051
-	 */
1052
-	protected function get_iauthority() {
1053
-		if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) {
1054
-			return null;
1055
-		}
1056
-
1057
-		$iauthority = '';
1058
-		if ($this->iuserinfo !== null) {
1059
-			$iauthority .= $this->iuserinfo . '@';
1060
-		}
1061
-		if ($this->ihost !== null) {
1062
-			$iauthority .= $this->ihost;
1063
-		}
1064
-		if ($this->port !== null) {
1065
-			$iauthority .= ':' . $this->port;
1066
-		}
1067
-		return $iauthority;
1068
-	}
1069
-
1070
-	/**
1071
-	 * Get the complete authority
1072
-	 *
1073
-	 * @return string
1074
-	 */
1075
-	protected function get_authority() {
1076
-		$iauthority = $this->get_iauthority();
1077
-		if (is_string($iauthority)) {
1078
-			return $this->to_uri($iauthority);
1079
-		}
1080
-		else {
1081
-			return $iauthority;
1082
-		}
1083
-	}
67
+    /**
68
+     * Scheme
69
+     *
70
+     * @var string
71
+     */
72
+    protected $scheme = null;
73
+
74
+    /**
75
+     * User Information
76
+     *
77
+     * @var string
78
+     */
79
+    protected $iuserinfo = null;
80
+
81
+    /**
82
+     * ihost
83
+     *
84
+     * @var string
85
+     */
86
+    protected $ihost = null;
87
+
88
+    /**
89
+     * Port
90
+     *
91
+     * @var string
92
+     */
93
+    protected $port = null;
94
+
95
+    /**
96
+     * ipath
97
+     *
98
+     * @var string
99
+     */
100
+    protected $ipath = '';
101
+
102
+    /**
103
+     * iquery
104
+     *
105
+     * @var string
106
+     */
107
+    protected $iquery = null;
108
+
109
+    /**
110
+     * ifragment
111
+     *
112
+     * @var string
113
+     */
114
+    protected $ifragment = null;
115
+
116
+    /**
117
+     * Normalization database
118
+     *
119
+     * Each key is the scheme, each value is an array with each key as the IRI
120
+     * part and value as the default value for that part.
121
+     */
122
+    protected $normalization = array(
123
+        'acap' => array(
124
+            'port' => 674
125
+        ),
126
+        'dict' => array(
127
+            'port' => 2628
128
+        ),
129
+        'file' => array(
130
+            'ihost' => 'localhost'
131
+        ),
132
+        'http' => array(
133
+            'port' => 80,
134
+        ),
135
+        'https' => array(
136
+            'port' => 443,
137
+        ),
138
+    );
139
+
140
+    /**
141
+     * Return the entire IRI when you try and read the object as a string
142
+     *
143
+     * @return string
144
+     */
145
+    public function __toString() {
146
+        return $this->get_iri();
147
+    }
148
+
149
+    /**
150
+     * Overload __set() to provide access via properties
151
+     *
152
+     * @param string $name Property name
153
+     * @param mixed $value Property value
154
+     */
155
+    public function __set($name, $value) {
156
+        if (method_exists($this, 'set_' . $name)) {
157
+            call_user_func(array($this, 'set_' . $name), $value);
158
+        }
159
+        elseif (
160
+                $name === 'iauthority'
161
+            || $name === 'iuserinfo'
162
+            || $name === 'ihost'
163
+            || $name === 'ipath'
164
+            || $name === 'iquery'
165
+            || $name === 'ifragment'
166
+        ) {
167
+            call_user_func(array($this, 'set_' . substr($name, 1)), $value);
168
+        }
169
+    }
170
+
171
+    /**
172
+     * Overload __get() to provide access via properties
173
+     *
174
+     * @param string $name Property name
175
+     * @return mixed
176
+     */
177
+    public function __get($name) {
178
+        // isset() returns false for null, we don't want to do that
179
+        // Also why we use array_key_exists below instead of isset()
180
+        $props = get_object_vars($this);
181
+
182
+        if (
183
+            $name === 'iri' ||
184
+            $name === 'uri' ||
185
+            $name === 'iauthority' ||
186
+            $name === 'authority'
187
+        ) {
188
+            $method = 'get_' . $name;
189
+            $return = $this->$method();
190
+        }
191
+        elseif (array_key_exists($name, $props)) {
192
+            $return = $this->$name;
193
+        }
194
+        // host -> ihost
195
+        elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) {
196
+            $name = $prop;
197
+            $return = $this->$prop;
198
+        }
199
+        // ischeme -> scheme
200
+        elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) {
201
+            $name = $prop;
202
+            $return = $this->$prop;
203
+        }
204
+        else {
205
+            trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
206
+            $return = null;
207
+        }
208
+
209
+        if ($return === null && isset($this->normalization[$this->scheme][$name])) {
210
+            return $this->normalization[$this->scheme][$name];
211
+        }
212
+        else {
213
+            return $return;
214
+        }
215
+    }
216
+
217
+    /**
218
+     * Overload __isset() to provide access via properties
219
+     *
220
+     * @param string $name Property name
221
+     * @return bool
222
+     */
223
+    public function __isset($name) {
224
+        return (method_exists($this, 'get_' . $name) || isset($this->$name));
225
+    }
226
+
227
+    /**
228
+     * Overload __unset() to provide access via properties
229
+     *
230
+     * @param string $name Property name
231
+     */
232
+    public function __unset($name) {
233
+        if (method_exists($this, 'set_' . $name)) {
234
+            call_user_func(array($this, 'set_' . $name), '');
235
+        }
236
+    }
237
+
238
+    /**
239
+     * Create a new IRI object, from a specified string
240
+     *
241
+     * @param string|null $iri
242
+     */
243
+    public function __construct($iri = null) {
244
+        $this->set_iri($iri);
245
+    }
246
+
247
+    /**
248
+     * Create a new IRI object by resolving a relative IRI
249
+     *
250
+     * Returns false if $base is not absolute, otherwise an IRI.
251
+     *
252
+     * @param IRI|string $base (Absolute) Base IRI
253
+     * @param IRI|string $relative Relative IRI
254
+     * @return IRI|false
255
+     */
256
+    public static function absolutize($base, $relative) {
257
+        if (!($relative instanceof Requests_IRI)) {
258
+            $relative = new Requests_IRI($relative);
259
+        }
260
+        if (!$relative->is_valid()) {
261
+            return false;
262
+        }
263
+        elseif ($relative->scheme !== null) {
264
+            return clone $relative;
265
+        }
266
+
267
+        if (!($base instanceof Requests_IRI)) {
268
+            $base = new Requests_IRI($base);
269
+        }
270
+        if ($base->scheme === null || !$base->is_valid()) {
271
+            return false;
272
+        }
273
+
274
+        if ($relative->get_iri() !== '') {
275
+            if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) {
276
+                $target = clone $relative;
277
+                $target->scheme = $base->scheme;
278
+            }
279
+            else {
280
+                $target = new Requests_IRI;
281
+                $target->scheme = $base->scheme;
282
+                $target->iuserinfo = $base->iuserinfo;
283
+                $target->ihost = $base->ihost;
284
+                $target->port = $base->port;
285
+                if ($relative->ipath !== '') {
286
+                    if ($relative->ipath[0] === '/') {
287
+                        $target->ipath = $relative->ipath;
288
+                    }
289
+                    elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') {
290
+                        $target->ipath = '/' . $relative->ipath;
291
+                    }
292
+                    elseif (($last_segment = strrpos($base->ipath, '/')) !== false) {
293
+                        $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
294
+                    }
295
+                    else {
296
+                        $target->ipath = $relative->ipath;
297
+                    }
298
+                    $target->ipath = $target->remove_dot_segments($target->ipath);
299
+                    $target->iquery = $relative->iquery;
300
+                }
301
+                else {
302
+                    $target->ipath = $base->ipath;
303
+                    if ($relative->iquery !== null) {
304
+                        $target->iquery = $relative->iquery;
305
+                    }
306
+                    elseif ($base->iquery !== null) {
307
+                        $target->iquery = $base->iquery;
308
+                    }
309
+                }
310
+                $target->ifragment = $relative->ifragment;
311
+            }
312
+        }
313
+        else {
314
+            $target = clone $base;
315
+            $target->ifragment = null;
316
+        }
317
+        $target->scheme_normalization();
318
+        return $target;
319
+    }
320
+
321
+    /**
322
+     * Parse an IRI into scheme/authority/path/query/fragment segments
323
+     *
324
+     * @param string $iri
325
+     * @return array
326
+     */
327
+    protected function parse_iri($iri) {
328
+        $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
329
+        $has_match = preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match);
330
+        if (!$has_match) {
331
+            throw new Requests_Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri);
332
+        }
333
+
334
+        if ($match[1] === '') {
335
+            $match['scheme'] = null;
336
+        }
337
+        if (!isset($match[3]) || $match[3] === '') {
338
+            $match['authority'] = null;
339
+        }
340
+        if (!isset($match[5])) {
341
+            $match['path'] = '';
342
+        }
343
+        if (!isset($match[6]) || $match[6] === '') {
344
+            $match['query'] = null;
345
+        }
346
+        if (!isset($match[8]) || $match[8] === '') {
347
+            $match['fragment'] = null;
348
+        }
349
+        return $match;
350
+    }
351
+
352
+    /**
353
+     * Remove dot segments from a path
354
+     *
355
+     * @param string $input
356
+     * @return string
357
+     */
358
+    protected function remove_dot_segments($input) {
359
+        $output = '';
360
+        while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') {
361
+            // A: If the input buffer begins with a prefix of "../" or "./",
362
+            // then remove that prefix from the input buffer; otherwise,
363
+            if (strpos($input, '../') === 0) {
364
+                $input = substr($input, 3);
365
+            }
366
+            elseif (strpos($input, './') === 0) {
367
+                $input = substr($input, 2);
368
+            }
369
+            // B: if the input buffer begins with a prefix of "/./" or "/.",
370
+            // where "." is a complete path segment, then replace that prefix
371
+            // with "/" in the input buffer; otherwise,
372
+            elseif (strpos($input, '/./') === 0) {
373
+                $input = substr($input, 2);
374
+            }
375
+            elseif ($input === '/.') {
376
+                $input = '/';
377
+            }
378
+            // C: if the input buffer begins with a prefix of "/../" or "/..",
379
+            // where ".." is a complete path segment, then replace that prefix
380
+            // with "/" in the input buffer and remove the last segment and its
381
+            // preceding "/" (if any) from the output buffer; otherwise,
382
+            elseif (strpos($input, '/../') === 0) {
383
+                $input = substr($input, 3);
384
+                $output = substr_replace($output, '', strrpos($output, '/'));
385
+            }
386
+            elseif ($input === '/..') {
387
+                $input = '/';
388
+                $output = substr_replace($output, '', strrpos($output, '/'));
389
+            }
390
+            // D: if the input buffer consists only of "." or "..", then remove
391
+            // that from the input buffer; otherwise,
392
+            elseif ($input === '.' || $input === '..') {
393
+                $input = '';
394
+            }
395
+            // E: move the first path segment in the input buffer to the end of
396
+            // the output buffer, including the initial "/" character (if any)
397
+            // and any subsequent characters up to, but not including, the next
398
+            // "/" character or the end of the input buffer
399
+            elseif (($pos = strpos($input, '/', 1)) !== false) {
400
+                $output .= substr($input, 0, $pos);
401
+                $input = substr_replace($input, '', 0, $pos);
402
+            }
403
+            else {
404
+                $output .= $input;
405
+                $input = '';
406
+            }
407
+        }
408
+        return $output . $input;
409
+    }
410
+
411
+    /**
412
+     * Replace invalid character with percent encoding
413
+     *
414
+     * @param string $string Input string
415
+     * @param string $extra_chars Valid characters not in iunreserved or
416
+     *                            iprivate (this is ASCII-only)
417
+     * @param bool $iprivate Allow iprivate
418
+     * @return string
419
+     */
420
+    protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) {
421
+        // Normalize as many pct-encoded sections as possible
422
+        $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string);
423
+
424
+        // Replace invalid percent characters
425
+        $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
426
+
427
+        // Add unreserved and % to $extra_chars (the latter is safe because all
428
+        // pct-encoded sections are now valid).
429
+        $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
430
+
431
+        // Now replace any bytes that aren't allowed with their pct-encoded versions
432
+        $position = 0;
433
+        $strlen = strlen($string);
434
+        while (($position += strspn($string, $extra_chars, $position)) < $strlen) {
435
+            $value = ord($string[$position]);
436
+
437
+            // Start position
438
+            $start = $position;
439
+
440
+            // By default we are valid
441
+            $valid = true;
442
+
443
+            // No one byte sequences are valid due to the while.
444
+            // Two byte sequence:
445
+            if (($value & 0xE0) === 0xC0) {
446
+                $character = ($value & 0x1F) << 6;
447
+                $length = 2;
448
+                $remaining = 1;
449
+            }
450
+            // Three byte sequence:
451
+            elseif (($value & 0xF0) === 0xE0) {
452
+                $character = ($value & 0x0F) << 12;
453
+                $length = 3;
454
+                $remaining = 2;
455
+            }
456
+            // Four byte sequence:
457
+            elseif (($value & 0xF8) === 0xF0) {
458
+                $character = ($value & 0x07) << 18;
459
+                $length = 4;
460
+                $remaining = 3;
461
+            }
462
+            // Invalid byte:
463
+            else {
464
+                $valid = false;
465
+                $length = 1;
466
+                $remaining = 0;
467
+            }
468
+
469
+            if ($remaining) {
470
+                if ($position + $length <= $strlen) {
471
+                    for ($position++; $remaining; $position++) {
472
+                        $value = ord($string[$position]);
473
+
474
+                        // Check that the byte is valid, then add it to the character:
475
+                        if (($value & 0xC0) === 0x80) {
476
+                            $character |= ($value & 0x3F) << (--$remaining * 6);
477
+                        }
478
+                        // If it is invalid, count the sequence as invalid and reprocess the current byte:
479
+                        else {
480
+                            $valid = false;
481
+                            $position--;
482
+                            break;
483
+                        }
484
+                    }
485
+                }
486
+                else {
487
+                    $position = $strlen - 1;
488
+                    $valid = false;
489
+                }
490
+            }
491
+
492
+            // Percent encode anything invalid or not in ucschar
493
+            if (
494
+                // Invalid sequences
495
+                !$valid
496
+                // Non-shortest form sequences are invalid
497
+                || $length > 1 && $character <= 0x7F
498
+                || $length > 2 && $character <= 0x7FF
499
+                || $length > 3 && $character <= 0xFFFF
500
+                // Outside of range of ucschar codepoints
501
+                // Noncharacters
502
+                || ($character & 0xFFFE) === 0xFFFE
503
+                || $character >= 0xFDD0 && $character <= 0xFDEF
504
+                || (
505
+                    // Everything else not in ucschar
506
+                        $character > 0xD7FF && $character < 0xF900
507
+                    || $character < 0xA0
508
+                    || $character > 0xEFFFD
509
+                )
510
+                && (
511
+                    // Everything not in iprivate, if it applies
512
+                        !$iprivate
513
+                    || $character < 0xE000
514
+                    || $character > 0x10FFFD
515
+                )
516
+            ) {
517
+                // If we were a character, pretend we weren't, but rather an error.
518
+                if ($valid) {
519
+                    $position--;
520
+                }
521
+
522
+                for ($j = $start; $j <= $position; $j++) {
523
+                    $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
524
+                    $j += 2;
525
+                    $position += 2;
526
+                    $strlen += 2;
527
+                }
528
+            }
529
+        }
530
+
531
+        return $string;
532
+    }
533
+
534
+    /**
535
+     * Callback function for preg_replace_callback.
536
+     *
537
+     * Removes sequences of percent encoded bytes that represent UTF-8
538
+     * encoded characters in iunreserved
539
+     *
540
+     * @param array $match PCRE match
541
+     * @return string Replacement
542
+     */
543
+    protected function remove_iunreserved_percent_encoded($match) {
544
+        // As we just have valid percent encoded sequences we can just explode
545
+        // and ignore the first member of the returned array (an empty string).
546
+        $bytes = explode('%', $match[0]);
547
+
548
+        // Initialize the new string (this is what will be returned) and that
549
+        // there are no bytes remaining in the current sequence (unsurprising
550
+        // at the first byte!).
551
+        $string = '';
552
+        $remaining = 0;
553
+
554
+        // Loop over each and every byte, and set $value to its value
555
+        for ($i = 1, $len = count($bytes); $i < $len; $i++) {
556
+            $value = hexdec($bytes[$i]);
557
+
558
+            // If we're the first byte of sequence:
559
+            if (!$remaining) {
560
+                // Start position
561
+                $start = $i;
562
+
563
+                // By default we are valid
564
+                $valid = true;
565
+
566
+                // One byte sequence:
567
+                if ($value <= 0x7F) {
568
+                    $character = $value;
569
+                    $length = 1;
570
+                }
571
+                // Two byte sequence:
572
+                elseif (($value & 0xE0) === 0xC0) {
573
+                    $character = ($value & 0x1F) << 6;
574
+                    $length = 2;
575
+                    $remaining = 1;
576
+                }
577
+                // Three byte sequence:
578
+                elseif (($value & 0xF0) === 0xE0) {
579
+                    $character = ($value & 0x0F) << 12;
580
+                    $length = 3;
581
+                    $remaining = 2;
582
+                }
583
+                // Four byte sequence:
584
+                elseif (($value & 0xF8) === 0xF0) {
585
+                    $character = ($value & 0x07) << 18;
586
+                    $length = 4;
587
+                    $remaining = 3;
588
+                }
589
+                // Invalid byte:
590
+                else {
591
+                    $valid = false;
592
+                    $remaining = 0;
593
+                }
594
+            }
595
+            // Continuation byte:
596
+            else {
597
+                // Check that the byte is valid, then add it to the character:
598
+                if (($value & 0xC0) === 0x80) {
599
+                    $remaining--;
600
+                    $character |= ($value & 0x3F) << ($remaining * 6);
601
+                }
602
+                // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
603
+                else {
604
+                    $valid = false;
605
+                    $remaining = 0;
606
+                    $i--;
607
+                }
608
+            }
609
+
610
+            // If we've reached the end of the current byte sequence, append it to Unicode::$data
611
+            if (!$remaining) {
612
+                // Percent encode anything invalid or not in iunreserved
613
+                if (
614
+                    // Invalid sequences
615
+                    !$valid
616
+                    // Non-shortest form sequences are invalid
617
+                    || $length > 1 && $character <= 0x7F
618
+                    || $length > 2 && $character <= 0x7FF
619
+                    || $length > 3 && $character <= 0xFFFF
620
+                    // Outside of range of iunreserved codepoints
621
+                    || $character < 0x2D
622
+                    || $character > 0xEFFFD
623
+                    // Noncharacters
624
+                    || ($character & 0xFFFE) === 0xFFFE
625
+                    || $character >= 0xFDD0 && $character <= 0xFDEF
626
+                    // Everything else not in iunreserved (this is all BMP)
627
+                    || $character === 0x2F
628
+                    || $character > 0x39 && $character < 0x41
629
+                    || $character > 0x5A && $character < 0x61
630
+                    || $character > 0x7A && $character < 0x7E
631
+                    || $character > 0x7E && $character < 0xA0
632
+                    || $character > 0xD7FF && $character < 0xF900
633
+                ) {
634
+                    for ($j = $start; $j <= $i; $j++) {
635
+                        $string .= '%' . strtoupper($bytes[$j]);
636
+                    }
637
+                }
638
+                else {
639
+                    for ($j = $start; $j <= $i; $j++) {
640
+                        $string .= chr(hexdec($bytes[$j]));
641
+                    }
642
+                }
643
+            }
644
+        }
645
+
646
+        // If we have any bytes left over they are invalid (i.e., we are
647
+        // mid-way through a multi-byte sequence)
648
+        if ($remaining) {
649
+            for ($j = $start; $j < $len; $j++) {
650
+                $string .= '%' . strtoupper($bytes[$j]);
651
+            }
652
+        }
653
+
654
+        return $string;
655
+    }
656
+
657
+    protected function scheme_normalization() {
658
+        if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) {
659
+            $this->iuserinfo = null;
660
+        }
661
+        if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) {
662
+            $this->ihost = null;
663
+        }
664
+        if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) {
665
+            $this->port = null;
666
+        }
667
+        if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) {
668
+            $this->ipath = '';
669
+        }
670
+        if (isset($this->ihost) && empty($this->ipath)) {
671
+            $this->ipath = '/';
672
+        }
673
+        if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) {
674
+            $this->iquery = null;
675
+        }
676
+        if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) {
677
+            $this->ifragment = null;
678
+        }
679
+    }
680
+
681
+    /**
682
+     * Check if the object represents a valid IRI. This needs to be done on each
683
+     * call as some things change depending on another part of the IRI.
684
+     *
685
+     * @return bool
686
+     */
687
+    public function is_valid() {
688
+        $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
689
+        if ($this->ipath !== '' &&
690
+            (
691
+                $isauthority && $this->ipath[0] !== '/' ||
692
+                (
693
+                    $this->scheme === null &&
694
+                    !$isauthority &&
695
+                    strpos($this->ipath, ':') !== false &&
696
+                    (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
697
+                )
698
+            )
699
+        ) {
700
+            return false;
701
+        }
702
+
703
+        return true;
704
+    }
705
+
706
+    /**
707
+     * Set the entire IRI. Returns true on success, false on failure (if there
708
+     * are any invalid characters).
709
+     *
710
+     * @param string $iri
711
+     * @return bool
712
+     */
713
+    protected function set_iri($iri) {
714
+        static $cache;
715
+        if (!$cache) {
716
+            $cache = array();
717
+        }
718
+
719
+        if ($iri === null) {
720
+            return true;
721
+        }
722
+        if (isset($cache[$iri])) {
723
+            list($this->scheme,
724
+                    $this->iuserinfo,
725
+                    $this->ihost,
726
+                    $this->port,
727
+                    $this->ipath,
728
+                    $this->iquery,
729
+                    $this->ifragment,
730
+                    $return) = $cache[$iri];
731
+            return $return;
732
+        }
733
+
734
+        $parsed = $this->parse_iri((string) $iri);
735
+
736
+        $return = $this->set_scheme($parsed['scheme'])
737
+            && $this->set_authority($parsed['authority'])
738
+            && $this->set_path($parsed['path'])
739
+            && $this->set_query($parsed['query'])
740
+            && $this->set_fragment($parsed['fragment']);
741
+
742
+        $cache[$iri] = array($this->scheme,
743
+                                $this->iuserinfo,
744
+                                $this->ihost,
745
+                                $this->port,
746
+                                $this->ipath,
747
+                                $this->iquery,
748
+                                $this->ifragment,
749
+                                $return);
750
+        return $return;
751
+    }
752
+
753
+    /**
754
+     * Set the scheme. Returns true on success, false on failure (if there are
755
+     * any invalid characters).
756
+     *
757
+     * @param string $scheme
758
+     * @return bool
759
+     */
760
+    protected function set_scheme($scheme) {
761
+        if ($scheme === null) {
762
+            $this->scheme = null;
763
+        }
764
+        elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) {
765
+            $this->scheme = null;
766
+            return false;
767
+        }
768
+        else {
769
+            $this->scheme = strtolower($scheme);
770
+        }
771
+        return true;
772
+    }
773
+
774
+    /**
775
+     * Set the authority. Returns true on success, false on failure (if there are
776
+     * any invalid characters).
777
+     *
778
+     * @param string $authority
779
+     * @return bool
780
+     */
781
+    protected function set_authority($authority) {
782
+        static $cache;
783
+        if (!$cache) {
784
+            $cache = array();
785
+        }
786
+
787
+        if ($authority === null) {
788
+            $this->iuserinfo = null;
789
+            $this->ihost = null;
790
+            $this->port = null;
791
+            return true;
792
+        }
793
+        if (isset($cache[$authority])) {
794
+            list($this->iuserinfo,
795
+                    $this->ihost,
796
+                    $this->port,
797
+                    $return) = $cache[$authority];
798
+
799
+            return $return;
800
+        }
801
+
802
+        $remaining = $authority;
803
+        if (($iuserinfo_end = strrpos($remaining, '@')) !== false) {
804
+            $iuserinfo = substr($remaining, 0, $iuserinfo_end);
805
+            $remaining = substr($remaining, $iuserinfo_end + 1);
806
+        }
807
+        else {
808
+            $iuserinfo = null;
809
+        }
810
+        if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) {
811
+            $port = substr($remaining, $port_start + 1);
812
+            if ($port === false || $port === '') {
813
+                $port = null;
814
+            }
815
+            $remaining = substr($remaining, 0, $port_start);
816
+        }
817
+        else {
818
+            $port = null;
819
+        }
820
+
821
+        $return = $this->set_userinfo($iuserinfo) &&
822
+                  $this->set_host($remaining) &&
823
+                  $this->set_port($port);
824
+
825
+        $cache[$authority] = array($this->iuserinfo,
826
+                                    $this->ihost,
827
+                                    $this->port,
828
+                                    $return);
829
+
830
+        return $return;
831
+    }
832
+
833
+    /**
834
+     * Set the iuserinfo.
835
+     *
836
+     * @param string $iuserinfo
837
+     * @return bool
838
+     */
839
+    protected function set_userinfo($iuserinfo) {
840
+        if ($iuserinfo === null) {
841
+            $this->iuserinfo = null;
842
+        }
843
+        else {
844
+            $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
845
+            $this->scheme_normalization();
846
+        }
847
+
848
+        return true;
849
+    }
850
+
851
+    /**
852
+     * Set the ihost. Returns true on success, false on failure (if there are
853
+     * any invalid characters).
854
+     *
855
+     * @param string $ihost
856
+     * @return bool
857
+     */
858
+    protected function set_host($ihost) {
859
+        if ($ihost === null) {
860
+            $this->ihost = null;
861
+            return true;
862
+        }
863
+        if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') {
864
+            if (Requests_IPv6::check_ipv6(substr($ihost, 1, -1))) {
865
+                $this->ihost = '[' . Requests_IPv6::compress(substr($ihost, 1, -1)) . ']';
866
+            }
867
+            else {
868
+                $this->ihost = null;
869
+                return false;
870
+            }
871
+        }
872
+        else {
873
+            $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
874
+
875
+            // Lowercase, but ignore pct-encoded sections (as they should
876
+            // remain uppercase). This must be done after the previous step
877
+            // as that can add unescaped characters.
878
+            $position = 0;
879
+            $strlen = strlen($ihost);
880
+            while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) {
881
+                if ($ihost[$position] === '%') {
882
+                    $position += 3;
883
+                }
884
+                else {
885
+                    $ihost[$position] = strtolower($ihost[$position]);
886
+                    $position++;
887
+                }
888
+            }
889
+
890
+            $this->ihost = $ihost;
891
+        }
892
+
893
+        $this->scheme_normalization();
894
+
895
+        return true;
896
+    }
897
+
898
+    /**
899
+     * Set the port. Returns true on success, false on failure (if there are
900
+     * any invalid characters).
901
+     *
902
+     * @param string $port
903
+     * @return bool
904
+     */
905
+    protected function set_port($port) {
906
+        if ($port === null) {
907
+            $this->port = null;
908
+            return true;
909
+        }
910
+
911
+        if (strspn($port, '0123456789') === strlen($port)) {
912
+            $this->port = (int) $port;
913
+            $this->scheme_normalization();
914
+            return true;
915
+        }
916
+
917
+        $this->port = null;
918
+        return false;
919
+    }
920
+
921
+    /**
922
+     * Set the ipath.
923
+     *
924
+     * @param string $ipath
925
+     * @return bool
926
+     */
927
+    protected function set_path($ipath) {
928
+        static $cache;
929
+        if (!$cache) {
930
+            $cache = array();
931
+        }
932
+
933
+        $ipath = (string) $ipath;
934
+
935
+        if (isset($cache[$ipath])) {
936
+            $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
937
+        }
938
+        else {
939
+            $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
940
+            $removed = $this->remove_dot_segments($valid);
941
+
942
+            $cache[$ipath] = array($valid, $removed);
943
+            $this->ipath = ($this->scheme !== null) ? $removed : $valid;
944
+        }
945
+        $this->scheme_normalization();
946
+        return true;
947
+    }
948
+
949
+    /**
950
+     * Set the iquery.
951
+     *
952
+     * @param string $iquery
953
+     * @return bool
954
+     */
955
+    protected function set_query($iquery) {
956
+        if ($iquery === null) {
957
+            $this->iquery = null;
958
+        }
959
+        else {
960
+            $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
961
+            $this->scheme_normalization();
962
+        }
963
+        return true;
964
+    }
965
+
966
+    /**
967
+     * Set the ifragment.
968
+     *
969
+     * @param string $ifragment
970
+     * @return bool
971
+     */
972
+    protected function set_fragment($ifragment) {
973
+        if ($ifragment === null) {
974
+            $this->ifragment = null;
975
+        }
976
+        else {
977
+            $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
978
+            $this->scheme_normalization();
979
+        }
980
+        return true;
981
+    }
982
+
983
+    /**
984
+     * Convert an IRI to a URI (or parts thereof)
985
+     *
986
+     * @param string|bool IRI to convert (or false from {@see get_iri})
987
+     * @return string|false URI if IRI is valid, false otherwise.
988
+     */
989
+    protected function to_uri($string) {
990
+        if (!is_string($string)) {
991
+            return false;
992
+        }
993
+
994
+        static $non_ascii;
995
+        if (!$non_ascii) {
996
+            $non_ascii = implode('', range("\x80", "\xFF"));
997
+        }
998
+
999
+        $position = 0;
1000
+        $strlen = strlen($string);
1001
+        while (($position += strcspn($string, $non_ascii, $position)) < $strlen) {
1002
+            $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
1003
+            $position += 3;
1004
+            $strlen += 2;
1005
+        }
1006
+
1007
+        return $string;
1008
+    }
1009
+
1010
+    /**
1011
+     * Get the complete IRI
1012
+     *
1013
+     * @return string
1014
+     */
1015
+    protected function get_iri() {
1016
+        if (!$this->is_valid()) {
1017
+            return false;
1018
+        }
1019
+
1020
+        $iri = '';
1021
+        if ($this->scheme !== null) {
1022
+            $iri .= $this->scheme . ':';
1023
+        }
1024
+        if (($iauthority = $this->get_iauthority()) !== null) {
1025
+            $iri .= '//' . $iauthority;
1026
+        }
1027
+        $iri .= $this->ipath;
1028
+        if ($this->iquery !== null) {
1029
+            $iri .= '?' . $this->iquery;
1030
+        }
1031
+        if ($this->ifragment !== null) {
1032
+            $iri .= '#' . $this->ifragment;
1033
+        }
1034
+
1035
+        return $iri;
1036
+    }
1037
+
1038
+    /**
1039
+     * Get the complete URI
1040
+     *
1041
+     * @return string
1042
+     */
1043
+    protected function get_uri() {
1044
+        return $this->to_uri($this->get_iri());
1045
+    }
1046
+
1047
+    /**
1048
+     * Get the complete iauthority
1049
+     *
1050
+     * @return string
1051
+     */
1052
+    protected function get_iauthority() {
1053
+        if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) {
1054
+            return null;
1055
+        }
1056
+
1057
+        $iauthority = '';
1058
+        if ($this->iuserinfo !== null) {
1059
+            $iauthority .= $this->iuserinfo . '@';
1060
+        }
1061
+        if ($this->ihost !== null) {
1062
+            $iauthority .= $this->ihost;
1063
+        }
1064
+        if ($this->port !== null) {
1065
+            $iauthority .= ':' . $this->port;
1066
+        }
1067
+        return $iauthority;
1068
+    }
1069
+
1070
+    /**
1071
+     * Get the complete authority
1072
+     *
1073
+     * @return string
1074
+     */
1075
+    protected function get_authority() {
1076
+        $iauthority = $this->get_iauthority();
1077
+        if (is_string($iauthority)) {
1078
+            return $this->to_uri($iauthority);
1079
+        }
1080
+        else {
1081
+            return $iauthority;
1082
+        }
1083
+    }
1084 1084
 }
Please login to merge, or discard this patch.
plugin/buycourses/src/Requests/IPv6.php 1 patch
Indentation   +159 added lines, -159 removed lines patch added patch discarded remove patch
@@ -16,175 +16,175 @@
 block discarded – undo
16 16
  * @subpackage Utilities
17 17
  */
18 18
 class Requests_IPv6 {
19
-	/**
20
-	 * Uncompresses an IPv6 address
21
-	 *
22
-	 * RFC 4291 allows you to compress consecutive zero pieces in an address to
23
-	 * '::'. This method expects a valid IPv6 address and expands the '::' to
24
-	 * the required number of zero pieces.
25
-	 *
26
-	 * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
27
-	 *           ::1         ->  0:0:0:0:0:0:0:1
28
-	 *
29
-	 * @author Alexander Merz <[email protected]>
30
-	 * @author elfrink at introweb dot nl
31
-	 * @author Josh Peck <jmp at joshpeck dot org>
32
-	 * @copyright 2003-2005 The PHP Group
33
-	 * @license http://www.opensource.org/licenses/bsd-license.php
34
-	 * @param string $ip An IPv6 address
35
-	 * @return string The uncompressed IPv6 address
36
-	 */
37
-	public static function uncompress($ip) {
38
-		if (substr_count($ip, '::') !== 1) {
39
-			return $ip;
40
-		}
19
+    /**
20
+     * Uncompresses an IPv6 address
21
+     *
22
+     * RFC 4291 allows you to compress consecutive zero pieces in an address to
23
+     * '::'. This method expects a valid IPv6 address and expands the '::' to
24
+     * the required number of zero pieces.
25
+     *
26
+     * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
27
+     *           ::1         ->  0:0:0:0:0:0:0:1
28
+     *
29
+     * @author Alexander Merz <[email protected]>
30
+     * @author elfrink at introweb dot nl
31
+     * @author Josh Peck <jmp at joshpeck dot org>
32
+     * @copyright 2003-2005 The PHP Group
33
+     * @license http://www.opensource.org/licenses/bsd-license.php
34
+     * @param string $ip An IPv6 address
35
+     * @return string The uncompressed IPv6 address
36
+     */
37
+    public static function uncompress($ip) {
38
+        if (substr_count($ip, '::') !== 1) {
39
+            return $ip;
40
+        }
41 41
 
42
-		list($ip1, $ip2) = explode('::', $ip);
43
-		$c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':');
44
-		$c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':');
42
+        list($ip1, $ip2) = explode('::', $ip);
43
+        $c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':');
44
+        $c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':');
45 45
 
46
-		if (strpos($ip2, '.') !== false) {
47
-			$c2++;
48
-		}
49
-		// ::
50
-		if ($c1 === -1 && $c2 === -1) {
51
-			$ip = '0:0:0:0:0:0:0:0';
52
-		}
53
-		// ::xxx
54
-		else if ($c1 === -1) {
55
-			$fill = str_repeat('0:', 7 - $c2);
56
-			$ip = str_replace('::', $fill, $ip);
57
-		}
58
-		// xxx::
59
-		else if ($c2 === -1) {
60
-			$fill = str_repeat(':0', 7 - $c1);
61
-			$ip = str_replace('::', $fill, $ip);
62
-		}
63
-		// xxx::xxx
64
-		else {
65
-			$fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
66
-			$ip = str_replace('::', $fill, $ip);
67
-		}
68
-		return $ip;
69
-	}
46
+        if (strpos($ip2, '.') !== false) {
47
+            $c2++;
48
+        }
49
+        // ::
50
+        if ($c1 === -1 && $c2 === -1) {
51
+            $ip = '0:0:0:0:0:0:0:0';
52
+        }
53
+        // ::xxx
54
+        else if ($c1 === -1) {
55
+            $fill = str_repeat('0:', 7 - $c2);
56
+            $ip = str_replace('::', $fill, $ip);
57
+        }
58
+        // xxx::
59
+        else if ($c2 === -1) {
60
+            $fill = str_repeat(':0', 7 - $c1);
61
+            $ip = str_replace('::', $fill, $ip);
62
+        }
63
+        // xxx::xxx
64
+        else {
65
+            $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
66
+            $ip = str_replace('::', $fill, $ip);
67
+        }
68
+        return $ip;
69
+    }
70 70
 
71
-	/**
72
-	 * Compresses an IPv6 address
73
-	 *
74
-	 * RFC 4291 allows you to compress consecutive zero pieces in an address to
75
-	 * '::'. This method expects a valid IPv6 address and compresses consecutive
76
-	 * zero pieces to '::'.
77
-	 *
78
-	 * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
79
-	 *           0:0:0:0:0:0:0:1        ->  ::1
80
-	 *
81
-	 * @see uncompress()
82
-	 * @param string $ip An IPv6 address
83
-	 * @return string The compressed IPv6 address
84
-	 */
85
-	public static function compress($ip) {
86
-		// Prepare the IP to be compressed
87
-		$ip = self::uncompress($ip);
88
-		$ip_parts = self::split_v6_v4($ip);
71
+    /**
72
+     * Compresses an IPv6 address
73
+     *
74
+     * RFC 4291 allows you to compress consecutive zero pieces in an address to
75
+     * '::'. This method expects a valid IPv6 address and compresses consecutive
76
+     * zero pieces to '::'.
77
+     *
78
+     * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
79
+     *           0:0:0:0:0:0:0:1        ->  ::1
80
+     *
81
+     * @see uncompress()
82
+     * @param string $ip An IPv6 address
83
+     * @return string The compressed IPv6 address
84
+     */
85
+    public static function compress($ip) {
86
+        // Prepare the IP to be compressed
87
+        $ip = self::uncompress($ip);
88
+        $ip_parts = self::split_v6_v4($ip);
89 89
 
90
-		// Replace all leading zeros
91
-		$ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
90
+        // Replace all leading zeros
91
+        $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
92 92
 
93
-		// Find bunches of zeros
94
-		if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
95
-			$max = 0;
96
-			$pos = null;
97
-			foreach ($matches[0] as $match) {
98
-				if (strlen($match[0]) > $max) {
99
-					$max = strlen($match[0]);
100
-					$pos = $match[1];
101
-				}
102
-			}
93
+        // Find bunches of zeros
94
+        if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
95
+            $max = 0;
96
+            $pos = null;
97
+            foreach ($matches[0] as $match) {
98
+                if (strlen($match[0]) > $max) {
99
+                    $max = strlen($match[0]);
100
+                    $pos = $match[1];
101
+                }
102
+            }
103 103
 
104
-			$ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
105
-		}
104
+            $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
105
+        }
106 106
 
107
-		if ($ip_parts[1] !== '') {
108
-			return implode(':', $ip_parts);
109
-		}
110
-		else {
111
-			return $ip_parts[0];
112
-		}
113
-	}
107
+        if ($ip_parts[1] !== '') {
108
+            return implode(':', $ip_parts);
109
+        }
110
+        else {
111
+            return $ip_parts[0];
112
+        }
113
+    }
114 114
 
115
-	/**
116
-	 * Splits an IPv6 address into the IPv6 and IPv4 representation parts
117
-	 *
118
-	 * RFC 4291 allows you to represent the last two parts of an IPv6 address
119
-	 * using the standard IPv4 representation
120
-	 *
121
-	 * Example:  0:0:0:0:0:0:13.1.68.3
122
-	 *           0:0:0:0:0:FFFF:129.144.52.38
123
-	 *
124
-	 * @param string $ip An IPv6 address
125
-	 * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
126
-	 */
127
-	protected static function split_v6_v4($ip) {
128
-		if (strpos($ip, '.') !== false) {
129
-			$pos = strrpos($ip, ':');
130
-			$ipv6_part = substr($ip, 0, $pos);
131
-			$ipv4_part = substr($ip, $pos + 1);
132
-			return array($ipv6_part, $ipv4_part);
133
-		}
134
-		else {
135
-			return array($ip, '');
136
-		}
137
-	}
115
+    /**
116
+     * Splits an IPv6 address into the IPv6 and IPv4 representation parts
117
+     *
118
+     * RFC 4291 allows you to represent the last two parts of an IPv6 address
119
+     * using the standard IPv4 representation
120
+     *
121
+     * Example:  0:0:0:0:0:0:13.1.68.3
122
+     *           0:0:0:0:0:FFFF:129.144.52.38
123
+     *
124
+     * @param string $ip An IPv6 address
125
+     * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
126
+     */
127
+    protected static function split_v6_v4($ip) {
128
+        if (strpos($ip, '.') !== false) {
129
+            $pos = strrpos($ip, ':');
130
+            $ipv6_part = substr($ip, 0, $pos);
131
+            $ipv4_part = substr($ip, $pos + 1);
132
+            return array($ipv6_part, $ipv4_part);
133
+        }
134
+        else {
135
+            return array($ip, '');
136
+        }
137
+    }
138 138
 
139
-	/**
140
-	 * Checks an IPv6 address
141
-	 *
142
-	 * Checks if the given IP is a valid IPv6 address
143
-	 *
144
-	 * @param string $ip An IPv6 address
145
-	 * @return bool true if $ip is a valid IPv6 address
146
-	 */
147
-	public static function check_ipv6($ip) {
148
-		$ip = self::uncompress($ip);
149
-		list($ipv6, $ipv4) = self::split_v6_v4($ip);
150
-		$ipv6 = explode(':', $ipv6);
151
-		$ipv4 = explode('.', $ipv4);
152
-		if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
153
-			foreach ($ipv6 as $ipv6_part) {
154
-				// The section can't be empty
155
-				if ($ipv6_part === '') {
156
-					return false;
157
-				}
139
+    /**
140
+     * Checks an IPv6 address
141
+     *
142
+     * Checks if the given IP is a valid IPv6 address
143
+     *
144
+     * @param string $ip An IPv6 address
145
+     * @return bool true if $ip is a valid IPv6 address
146
+     */
147
+    public static function check_ipv6($ip) {
148
+        $ip = self::uncompress($ip);
149
+        list($ipv6, $ipv4) = self::split_v6_v4($ip);
150
+        $ipv6 = explode(':', $ipv6);
151
+        $ipv4 = explode('.', $ipv4);
152
+        if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
153
+            foreach ($ipv6 as $ipv6_part) {
154
+                // The section can't be empty
155
+                if ($ipv6_part === '') {
156
+                    return false;
157
+                }
158 158
 
159
-				// Nor can it be over four characters
160
-				if (strlen($ipv6_part) > 4) {
161
-					return false;
162
-				}
159
+                // Nor can it be over four characters
160
+                if (strlen($ipv6_part) > 4) {
161
+                    return false;
162
+                }
163 163
 
164
-				// Remove leading zeros (this is safe because of the above)
165
-				$ipv6_part = ltrim($ipv6_part, '0');
166
-				if ($ipv6_part === '') {
167
-					$ipv6_part = '0';
168
-				}
164
+                // Remove leading zeros (this is safe because of the above)
165
+                $ipv6_part = ltrim($ipv6_part, '0');
166
+                if ($ipv6_part === '') {
167
+                    $ipv6_part = '0';
168
+                }
169 169
 
170
-				// Check the value is valid
171
-				$value = hexdec($ipv6_part);
172
-				if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
173
-					return false;
174
-				}
175
-			}
176
-			if (count($ipv4) === 4) {
177
-				foreach ($ipv4 as $ipv4_part) {
178
-					$value = (int) $ipv4_part;
179
-					if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
180
-						return false;
181
-					}
182
-				}
183
-			}
184
-			return true;
185
-		}
186
-		else {
187
-			return false;
188
-		}
189
-	}
170
+                // Check the value is valid
171
+                $value = hexdec($ipv6_part);
172
+                if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
173
+                    return false;
174
+                }
175
+            }
176
+            if (count($ipv4) === 4) {
177
+                foreach ($ipv4 as $ipv4_part) {
178
+                    $value = (int) $ipv4_part;
179
+                    if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
180
+                        return false;
181
+                    }
182
+                }
183
+            }
184
+            return true;
185
+        }
186
+        else {
187
+            return false;
188
+        }
189
+    }
190 190
 }
Please login to merge, or discard this patch.
plugin/buycourses/src/Requests/Proxy.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -21,15 +21,15 @@
 block discarded – undo
21 21
  * @since 1.6
22 22
  */
23 23
 interface Requests_Proxy {
24
-	/**
25
-	 * Register hooks as needed
26
-	 *
27
-	 * This method is called in {@see Requests::request} when the user has set
28
-	 * an instance as the 'auth' option. Use this callback to register all the
29
-	 * hooks you'll need.
30
-	 *
31
-	 * @see Requests_Hooks::register
32
-	 * @param Requests_Hooks $hooks Hook system
33
-	 */
34
-	public function register(Requests_Hooks &$hooks);
24
+    /**
25
+     * Register hooks as needed
26
+     *
27
+     * This method is called in {@see Requests::request} when the user has set
28
+     * an instance as the 'auth' option. Use this callback to register all the
29
+     * hooks you'll need.
30
+     *
31
+     * @see Requests_Hooks::register
32
+     * @param Requests_Hooks $hooks Hook system
33
+     */
34
+    public function register(Requests_Hooks &$hooks);
35 35
 }
36 36
\ No newline at end of file
Please login to merge, or discard this patch.
plugin/buycourses/src/Requests/Exception.php 1 patch
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -11,52 +11,52 @@
 block discarded – undo
11 11
  * @package Requests
12 12
  */
13 13
 class Requests_Exception extends Exception {
14
-	/**
15
-	 * Type of exception
16
-	 *
17
-	 * @var string
18
-	 */
19
-	protected $type;
14
+    /**
15
+     * Type of exception
16
+     *
17
+     * @var string
18
+     */
19
+    protected $type;
20 20
 
21
-	/**
22
-	 * Data associated with the exception
23
-	 *
24
-	 * @var mixed
25
-	 */
26
-	protected $data;
21
+    /**
22
+     * Data associated with the exception
23
+     *
24
+     * @var mixed
25
+     */
26
+    protected $data;
27 27
 
28
-	/**
29
-	 * Create a new exception
30
-	 *
31
-	 * @param string $message Exception message
32
-	 * @param string $type Exception type
33
-	 * @param mixed $data Associated data
34
-	 * @param integer $code Exception numerical code, if applicable
35
-	 */
36
-	public function __construct($message, $type, $data = null, $code = 0) {
37
-		parent::__construct($message, $code);
28
+    /**
29
+     * Create a new exception
30
+     *
31
+     * @param string $message Exception message
32
+     * @param string $type Exception type
33
+     * @param mixed $data Associated data
34
+     * @param integer $code Exception numerical code, if applicable
35
+     */
36
+    public function __construct($message, $type, $data = null, $code = 0) {
37
+        parent::__construct($message, $code);
38 38
 
39
-		$this->type = $type;
40
-		$this->data = $data;
41
-	}
39
+        $this->type = $type;
40
+        $this->data = $data;
41
+    }
42 42
 
43
-	/**
44
-	 * Like {@see getCode()}, but a string code.
45
-	 *
46
-	 * @codeCoverageIgnore
47
-	 * @return string
48
-	 */
49
-	public function getType() {
50
-		return $this->type;
51
-	}
43
+    /**
44
+     * Like {@see getCode()}, but a string code.
45
+     *
46
+     * @codeCoverageIgnore
47
+     * @return string
48
+     */
49
+    public function getType() {
50
+        return $this->type;
51
+    }
52 52
 
53
-	/**
54
-	 * Gives any relevant data
55
-	 *
56
-	 * @codeCoverageIgnore
57
-	 * @return mixed
58
-	 */
59
-	public function getData() {
60
-		return $this->data;
61
-	}
53
+    /**
54
+     * Gives any relevant data
55
+     *
56
+     * @codeCoverageIgnore
57
+     * @return mixed
58
+     */
59
+    public function getData() {
60
+        return $this->data;
61
+    }
62 62
 }
63 63
\ No newline at end of file
Please login to merge, or discard this patch.
plugin/buycourses/src/Requests.php 1 patch
Indentation   +945 added lines, -945 removed lines patch added patch discarded remove patch
@@ -19,241 +19,241 @@  discard block
 block discarded – undo
19 19
  * @package Requests
20 20
  */
21 21
 class Requests {
22
-	/**
23
-	 * POST method
24
-	 *
25
-	 * @var string
26
-	 */
27
-	const POST = 'POST';
28
-
29
-	/**
30
-	 * PUT method
31
-	 *
32
-	 * @var string
33
-	 */
34
-	const PUT = 'PUT';
35
-
36
-	/**
37
-	 * GET method
38
-	 *
39
-	 * @var string
40
-	 */
41
-	const GET = 'GET';
42
-
43
-	/**
44
-	 * HEAD method
45
-	 *
46
-	 * @var string
47
-	 */
48
-	const HEAD = 'HEAD';
49
-
50
-	/**
51
-	 * DELETE method
52
-	 *
53
-	 * @var string
54
-	 */
55
-	const DELETE = 'DELETE';
56
-
57
-	/**
58
-	 * OPTIONS method
59
-	 *
60
-	 * @var string
61
-	 */
62
-	const OPTIONS = 'OPTIONS';
63
-
64
-	/**
65
-	 * TRACE method
66
-	 *
67
-	 * @var string
68
-	 */
69
-	const TRACE = 'TRACE';
70
-
71
-	/**
72
-	 * PATCH method
73
-	 *
74
-	 * @link https://tools.ietf.org/html/rfc5789
75
-	 * @var string
76
-	 */
77
-	const PATCH = 'PATCH';
78
-
79
-	/**
80
-	 * Default size of buffer size to read streams
81
-	 *
82
-	 * @var integer
83
-	 */
84
-	const BUFFER_SIZE = 1160;
85
-
86
-	/**
87
-	 * Current version of Requests
88
-	 *
89
-	 * @var string
90
-	 */
91
-	const VERSION = '1.7';
92
-
93
-	/**
94
-	 * Registered transport classes
95
-	 *
96
-	 * @var array
97
-	 */
98
-	protected static $transports = array();
99
-
100
-	/**
101
-	 * Selected transport name
102
-	 *
103
-	 * Use {@see get_transport()} instead
104
-	 *
105
-	 * @var array
106
-	 */
107
-	public static $transport = array();
108
-
109
-	/**
110
-	 * Default certificate path.
111
-	 *
112
-	 * @see Requests::get_certificate_path()
113
-	 * @see Requests::set_certificate_path()
114
-	 *
115
-	 * @var string
116
-	 */
117
-	protected static $certificate_path;
118
-
119
-	/**
120
-	 * This is a static class, do not instantiate it
121
-	 *
122
-	 * @codeCoverageIgnore
123
-	 */
124
-	private function __construct() {}
125
-
126
-	/**
127
-	 * Autoloader for Requests
128
-	 *
129
-	 * Register this with {@see register_autoloader()} if you'd like to avoid
130
-	 * having to create your own.
131
-	 *
132
-	 * (You can also use `spl_autoload_register` directly if you'd prefer.)
133
-	 *
134
-	 * @codeCoverageIgnore
135
-	 *
136
-	 * @param string $class Class name to load
137
-	 */
138
-	public static function autoloader($class) {
139
-		// Check that the class starts with "Requests"
140
-		if (strpos($class, 'Requests') !== 0) {
141
-			return;
142
-		}
143
-
144
-		$file = str_replace('_', '/', $class);
145
-		if (file_exists(dirname(__FILE__) . '/' . $file . '.php')) {
146
-			require_once(dirname(__FILE__) . '/' . $file . '.php');
147
-		}
148
-	}
149
-
150
-	/**
151
-	 * Register the built-in autoloader
152
-	 *
153
-	 * @codeCoverageIgnore
154
-	 */
155
-	public static function register_autoloader() {
156
-		spl_autoload_register(array('Requests', 'autoloader'));
157
-	}
158
-
159
-	/**
160
-	 * Register a transport
161
-	 *
162
-	 * @param string $transport Transport class to add, must support the Requests_Transport interface
163
-	 */
164
-	public static function add_transport($transport) {
165
-		if (empty(self::$transports)) {
166
-			self::$transports = array(
167
-				'Requests_Transport_cURL',
168
-				'Requests_Transport_fsockopen',
169
-			);
170
-		}
171
-
172
-		self::$transports = array_merge(self::$transports, array($transport));
173
-	}
174
-
175
-	/**
176
-	 * Get a working transport
177
-	 *
178
-	 * @throws Requests_Exception If no valid transport is found (`notransport`)
179
-	 * @return Requests_Transport
180
-	 */
181
-	protected static function get_transport($capabilities = array()) {
182
-		// Caching code, don't bother testing coverage
183
-		// @codeCoverageIgnoreStart
184
-		// array of capabilities as a string to be used as an array key
185
-		ksort($capabilities);
186
-		$cap_string = serialize($capabilities);
187
-
188
-		// Don't search for a transport if it's already been done for these $capabilities
189
-		if (isset(self::$transport[$cap_string]) && self::$transport[$cap_string] !== null) {
190
-			return new self::$transport[$cap_string]();
191
-		}
192
-		// @codeCoverageIgnoreEnd
193
-
194
-		if (empty(self::$transports)) {
195
-			self::$transports = array(
196
-				'Requests_Transport_cURL',
197
-				'Requests_Transport_fsockopen',
198
-			);
199
-		}
200
-
201
-		// Find us a working transport
202
-		foreach (self::$transports as $class) {
203
-			if (!class_exists($class)) {
204
-				continue;
205
-			}
206
-
207
-			$result = call_user_func(array($class, 'test'), $capabilities);
208
-			if ($result) {
209
-				self::$transport[$cap_string] = $class;
210
-				break;
211
-			}
212
-		}
213
-		if (self::$transport[$cap_string] === null) {
214
-			throw new Requests_Exception('No working transports found', 'notransport', self::$transports);
215
-		}
216
-
217
-		return new self::$transport[$cap_string]();
218
-	}
219
-
220
-	/**#@+
22
+    /**
23
+     * POST method
24
+     *
25
+     * @var string
26
+     */
27
+    const POST = 'POST';
28
+
29
+    /**
30
+     * PUT method
31
+     *
32
+     * @var string
33
+     */
34
+    const PUT = 'PUT';
35
+
36
+    /**
37
+     * GET method
38
+     *
39
+     * @var string
40
+     */
41
+    const GET = 'GET';
42
+
43
+    /**
44
+     * HEAD method
45
+     *
46
+     * @var string
47
+     */
48
+    const HEAD = 'HEAD';
49
+
50
+    /**
51
+     * DELETE method
52
+     *
53
+     * @var string
54
+     */
55
+    const DELETE = 'DELETE';
56
+
57
+    /**
58
+     * OPTIONS method
59
+     *
60
+     * @var string
61
+     */
62
+    const OPTIONS = 'OPTIONS';
63
+
64
+    /**
65
+     * TRACE method
66
+     *
67
+     * @var string
68
+     */
69
+    const TRACE = 'TRACE';
70
+
71
+    /**
72
+     * PATCH method
73
+     *
74
+     * @link https://tools.ietf.org/html/rfc5789
75
+     * @var string
76
+     */
77
+    const PATCH = 'PATCH';
78
+
79
+    /**
80
+     * Default size of buffer size to read streams
81
+     *
82
+     * @var integer
83
+     */
84
+    const BUFFER_SIZE = 1160;
85
+
86
+    /**
87
+     * Current version of Requests
88
+     *
89
+     * @var string
90
+     */
91
+    const VERSION = '1.7';
92
+
93
+    /**
94
+     * Registered transport classes
95
+     *
96
+     * @var array
97
+     */
98
+    protected static $transports = array();
99
+
100
+    /**
101
+     * Selected transport name
102
+     *
103
+     * Use {@see get_transport()} instead
104
+     *
105
+     * @var array
106
+     */
107
+    public static $transport = array();
108
+
109
+    /**
110
+     * Default certificate path.
111
+     *
112
+     * @see Requests::get_certificate_path()
113
+     * @see Requests::set_certificate_path()
114
+     *
115
+     * @var string
116
+     */
117
+    protected static $certificate_path;
118
+
119
+    /**
120
+     * This is a static class, do not instantiate it
121
+     *
122
+     * @codeCoverageIgnore
123
+     */
124
+    private function __construct() {}
125
+
126
+    /**
127
+     * Autoloader for Requests
128
+     *
129
+     * Register this with {@see register_autoloader()} if you'd like to avoid
130
+     * having to create your own.
131
+     *
132
+     * (You can also use `spl_autoload_register` directly if you'd prefer.)
133
+     *
134
+     * @codeCoverageIgnore
135
+     *
136
+     * @param string $class Class name to load
137
+     */
138
+    public static function autoloader($class) {
139
+        // Check that the class starts with "Requests"
140
+        if (strpos($class, 'Requests') !== 0) {
141
+            return;
142
+        }
143
+
144
+        $file = str_replace('_', '/', $class);
145
+        if (file_exists(dirname(__FILE__) . '/' . $file . '.php')) {
146
+            require_once(dirname(__FILE__) . '/' . $file . '.php');
147
+        }
148
+    }
149
+
150
+    /**
151
+     * Register the built-in autoloader
152
+     *
153
+     * @codeCoverageIgnore
154
+     */
155
+    public static function register_autoloader() {
156
+        spl_autoload_register(array('Requests', 'autoloader'));
157
+    }
158
+
159
+    /**
160
+     * Register a transport
161
+     *
162
+     * @param string $transport Transport class to add, must support the Requests_Transport interface
163
+     */
164
+    public static function add_transport($transport) {
165
+        if (empty(self::$transports)) {
166
+            self::$transports = array(
167
+                'Requests_Transport_cURL',
168
+                'Requests_Transport_fsockopen',
169
+            );
170
+        }
171
+
172
+        self::$transports = array_merge(self::$transports, array($transport));
173
+    }
174
+
175
+    /**
176
+     * Get a working transport
177
+     *
178
+     * @throws Requests_Exception If no valid transport is found (`notransport`)
179
+     * @return Requests_Transport
180
+     */
181
+    protected static function get_transport($capabilities = array()) {
182
+        // Caching code, don't bother testing coverage
183
+        // @codeCoverageIgnoreStart
184
+        // array of capabilities as a string to be used as an array key
185
+        ksort($capabilities);
186
+        $cap_string = serialize($capabilities);
187
+
188
+        // Don't search for a transport if it's already been done for these $capabilities
189
+        if (isset(self::$transport[$cap_string]) && self::$transport[$cap_string] !== null) {
190
+            return new self::$transport[$cap_string]();
191
+        }
192
+        // @codeCoverageIgnoreEnd
193
+
194
+        if (empty(self::$transports)) {
195
+            self::$transports = array(
196
+                'Requests_Transport_cURL',
197
+                'Requests_Transport_fsockopen',
198
+            );
199
+        }
200
+
201
+        // Find us a working transport
202
+        foreach (self::$transports as $class) {
203
+            if (!class_exists($class)) {
204
+                continue;
205
+            }
206
+
207
+            $result = call_user_func(array($class, 'test'), $capabilities);
208
+            if ($result) {
209
+                self::$transport[$cap_string] = $class;
210
+                break;
211
+            }
212
+        }
213
+        if (self::$transport[$cap_string] === null) {
214
+            throw new Requests_Exception('No working transports found', 'notransport', self::$transports);
215
+        }
216
+
217
+        return new self::$transport[$cap_string]();
218
+    }
219
+
220
+    /**#@+
221 221
 	 * @see request()
222 222
 	 * @param string $url
223 223
 	 * @param array $headers
224 224
 	 * @param array $options
225 225
 	 * @return Requests_Response
226 226
 	 */
227
-	/**
228
-	 * Send a GET request
229
-	 */
230
-	public static function get($url, $headers = array(), $options = array()) {
231
-		return self::request($url, $headers, null, self::GET, $options);
232
-	}
233
-
234
-	/**
235
-	 * Send a HEAD request
236
-	 */
237
-	public static function head($url, $headers = array(), $options = array()) {
238
-		return self::request($url, $headers, null, self::HEAD, $options);
239
-	}
240
-
241
-	/**
242
-	 * Send a DELETE request
243
-	 */
244
-	public static function delete($url, $headers = array(), $options = array()) {
245
-		return self::request($url, $headers, null, self::DELETE, $options);
246
-	}
247
-
248
-	/**
249
-	 * Send a TRACE request
250
-	 */
251
-	public static function trace($url, $headers = array(), $options = array()) {
252
-		return self::request($url, $headers, null, self::TRACE, $options);
253
-	}
254
-	/**#@-*/
255
-
256
-	/**#@+
227
+    /**
228
+     * Send a GET request
229
+     */
230
+    public static function get($url, $headers = array(), $options = array()) {
231
+        return self::request($url, $headers, null, self::GET, $options);
232
+    }
233
+
234
+    /**
235
+     * Send a HEAD request
236
+     */
237
+    public static function head($url, $headers = array(), $options = array()) {
238
+        return self::request($url, $headers, null, self::HEAD, $options);
239
+    }
240
+
241
+    /**
242
+     * Send a DELETE request
243
+     */
244
+    public static function delete($url, $headers = array(), $options = array()) {
245
+        return self::request($url, $headers, null, self::DELETE, $options);
246
+    }
247
+
248
+    /**
249
+     * Send a TRACE request
250
+     */
251
+    public static function trace($url, $headers = array(), $options = array()) {
252
+        return self::request($url, $headers, null, self::TRACE, $options);
253
+    }
254
+    /**#@-*/
255
+
256
+    /**#@+
257 257
 	 * @see request()
258 258
 	 * @param string $url
259 259
 	 * @param array $headers
@@ -261,720 +261,720 @@  discard block
 block discarded – undo
261 261
 	 * @param array $options
262 262
 	 * @return Requests_Response
263 263
 	 */
264
-	/**
265
-	 * Send a POST request
266
-	 */
267
-	public static function post($url, $headers = array(), $data = array(), $options = array()) {
268
-		return self::request($url, $headers, $data, self::POST, $options);
269
-	}
270
-	/**
271
-	 * Send a PUT request
272
-	 */
273
-	public static function put($url, $headers = array(), $data = array(), $options = array()) {
274
-		return self::request($url, $headers, $data, self::PUT, $options);
275
-	}
276
-
277
-	/**
278
-	 * Send an OPTIONS request
279
-	 */
280
-	public static function options($url, $headers = array(), $data = array(), $options = array()) {
281
-		return self::request($url, $headers, $data, self::OPTIONS, $options);
282
-	}
283
-
284
-	/**
285
-	 * Send a PATCH request
286
-	 *
287
-	 * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
288
-	 * specification recommends that should send an ETag
289
-	 *
290
-	 * @link https://tools.ietf.org/html/rfc5789
291
-	 */
292
-	public static function patch($url, $headers, $data = array(), $options = array()) {
293
-		return self::request($url, $headers, $data, self::PATCH, $options);
294
-	}
295
-	/**#@-*/
296
-
297
-	/**
298
-	 * Main interface for HTTP requests
299
-	 *
300
-	 * This method initiates a request and sends it via a transport before
301
-	 * parsing.
302
-	 *
303
-	 * The `$options` parameter takes an associative array with the following
304
-	 * options:
305
-	 *
306
-	 * - `timeout`: How long should we wait for a response?
307
-	 *    Note: for cURL, a minimum of 1 second applies, as DNS resolution
308
-	 *    operates at second-resolution only.
309
-	 *    (float, seconds with a millisecond precision, default: 10, example: 0.01)
310
-	 * - `connect_timeout`: How long should we wait while trying to connect?
311
-	 *    (float, seconds with a millisecond precision, default: 10, example: 0.01)
312
-	 * - `useragent`: Useragent to send to the server
313
-	 *    (string, default: php-requests/$version)
314
-	 * - `follow_redirects`: Should we follow 3xx redirects?
315
-	 *    (boolean, default: true)
316
-	 * - `redirects`: How many times should we redirect before erroring?
317
-	 *    (integer, default: 10)
318
-	 * - `blocking`: Should we block processing on this request?
319
-	 *    (boolean, default: true)
320
-	 * - `filename`: File to stream the body to instead.
321
-	 *    (string|boolean, default: false)
322
-	 * - `auth`: Authentication handler or array of user/password details to use
323
-	 *    for Basic authentication
324
-	 *    (Requests_Auth|array|boolean, default: false)
325
-	 * - `proxy`: Proxy details to use for proxy by-passing and authentication
326
-	 *    (Requests_Proxy|array|string|boolean, default: false)
327
-	 * - `max_bytes`: Limit for the response body size.
328
-	 *    (integer|boolean, default: false)
329
-	 * - `idn`: Enable IDN parsing
330
-	 *    (boolean, default: true)
331
-	 * - `transport`: Custom transport. Either a class name, or a
332
-	 *    transport object. Defaults to the first working transport from
333
-	 *    {@see getTransport()}
334
-	 *    (string|Requests_Transport, default: {@see getTransport()})
335
-	 * - `hooks`: Hooks handler.
336
-	 *    (Requests_Hooker, default: new Requests_Hooks())
337
-	 * - `verify`: Should we verify SSL certificates? Allows passing in a custom
338
-	 *    certificate file as a string. (Using true uses the system-wide root
339
-	 *    certificate store instead, but this may have different behaviour
340
-	 *    across transports.)
341
-	 *    (string|boolean, default: library/Requests/Transport/cacert.pem)
342
-	 * - `verifyname`: Should we verify the common name in the SSL certificate?
343
-	 *    (boolean: default, true)
344
-	 * - `data_format`: How should we send the `$data` parameter?
345
-	 *    (string, one of 'query' or 'body', default: 'query' for
346
-	 *    HEAD/GET/DELETE, 'body' for POST/PUT/OPTIONS/PATCH)
347
-	 *
348
-	 * @throws Requests_Exception On invalid URLs (`nonhttp`)
349
-	 *
350
-	 * @param string $url URL to request
351
-	 * @param array $headers Extra headers to send with the request
352
-	 * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
353
-	 * @param string $type HTTP request type (use Requests constants)
354
-	 * @param array $options Options for the request (see description for more information)
355
-	 * @return Requests_Response
356
-	 */
357
-	public static function request($url, $headers = array(), $data = array(), $type = self::GET, $options = array()) {
358
-		if (empty($options['type'])) {
359
-			$options['type'] = $type;
360
-		}
361
-		$options = array_merge(self::get_default_options(), $options);
362
-
363
-		self::set_defaults($url, $headers, $data, $type, $options);
364
-
365
-		$options['hooks']->dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options));
366
-
367
-		if (!empty($options['transport'])) {
368
-			$transport = $options['transport'];
369
-
370
-			if (is_string($options['transport'])) {
371
-				$transport = new $transport();
372
-			}
373
-		}
374
-		else {
375
-			$need_ssl = (0 === stripos($url, 'https://'));
376
-			$capabilities = array('ssl' => $need_ssl);
377
-			$transport = self::get_transport($capabilities);
378
-		}
379
-		$response = $transport->request($url, $headers, $data, $options);
380
-
381
-		$options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options));
382
-
383
-		return self::parse_response($response, $url, $headers, $data, $options);
384
-	}
385
-
386
-	/**
387
-	 * Send multiple HTTP requests simultaneously
388
-	 *
389
-	 * The `$requests` parameter takes an associative or indexed array of
390
-	 * request fields. The key of each request can be used to match up the
391
-	 * request with the returned data, or with the request passed into your
392
-	 * `multiple.request.complete` callback.
393
-	 *
394
-	 * The request fields value is an associative array with the following keys:
395
-	 *
396
-	 * - `url`: Request URL Same as the `$url` parameter to
397
-	 *    {@see Requests::request}
398
-	 *    (string, required)
399
-	 * - `headers`: Associative array of header fields. Same as the `$headers`
400
-	 *    parameter to {@see Requests::request}
401
-	 *    (array, default: `array()`)
402
-	 * - `data`: Associative array of data fields or a string. Same as the
403
-	 *    `$data` parameter to {@see Requests::request}
404
-	 *    (array|string, default: `array()`)
405
-	 * - `type`: HTTP request type (use Requests constants). Same as the `$type`
406
-	 *    parameter to {@see Requests::request}
407
-	 *    (string, default: `Requests::GET`)
408
-	 * - `cookies`: Associative array of cookie name to value, or cookie jar.
409
-	 *    (array|Requests_Cookie_Jar)
410
-	 *
411
-	 * If the `$options` parameter is specified, individual requests will
412
-	 * inherit options from it. This can be used to use a single hooking system,
413
-	 * or set all the types to `Requests::POST`, for example.
414
-	 *
415
-	 * In addition, the `$options` parameter takes the following global options:
416
-	 *
417
-	 * - `complete`: A callback for when a request is complete. Takes two
418
-	 *    parameters, a Requests_Response/Requests_Exception reference, and the
419
-	 *    ID from the request array (Note: this can also be overridden on a
420
-	 *    per-request basis, although that's a little silly)
421
-	 *    (callback)
422
-	 *
423
-	 * @param array $requests Requests data (see description for more information)
424
-	 * @param array $options Global and default options (see {@see Requests::request})
425
-	 * @return array Responses (either Requests_Response or a Requests_Exception object)
426
-	 */
427
-	public static function request_multiple($requests, $options = array()) {
428
-		$options = array_merge(self::get_default_options(true), $options);
429
-
430
-		if (!empty($options['hooks'])) {
431
-			$options['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
432
-			if (!empty($options['complete'])) {
433
-				$options['hooks']->register('multiple.request.complete', $options['complete']);
434
-			}
435
-		}
436
-
437
-		foreach ($requests as $id => &$request) {
438
-			if (!isset($request['headers'])) {
439
-				$request['headers'] = array();
440
-			}
441
-			if (!isset($request['data'])) {
442
-				$request['data'] = array();
443
-			}
444
-			if (!isset($request['type'])) {
445
-				$request['type'] = self::GET;
446
-			}
447
-			if (!isset($request['options'])) {
448
-				$request['options'] = $options;
449
-				$request['options']['type'] = $request['type'];
450
-			}
451
-			else {
452
-				if (empty($request['options']['type'])) {
453
-					$request['options']['type'] = $request['type'];
454
-				}
455
-				$request['options'] = array_merge($options, $request['options']);
456
-			}
457
-
458
-			self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']);
459
-
460
-			// Ensure we only hook in once
461
-			if ($request['options']['hooks'] !== $options['hooks']) {
462
-				$request['options']['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
463
-				if (!empty($request['options']['complete'])) {
464
-					$request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']);
465
-				}
466
-			}
467
-		}
468
-		unset($request);
469
-
470
-		if (!empty($options['transport'])) {
471
-			$transport = $options['transport'];
472
-
473
-			if (is_string($options['transport'])) {
474
-				$transport = new $transport();
475
-			}
476
-		}
477
-		else {
478
-			$transport = self::get_transport();
479
-		}
480
-		$responses = $transport->request_multiple($requests, $options);
481
-
482
-		foreach ($responses as $id => &$response) {
483
-			// If our hook got messed with somehow, ensure we end up with the
484
-			// correct response
485
-			if (is_string($response)) {
486
-				$request = $requests[$id];
487
-				self::parse_multiple($response, $request);
488
-				$request['options']['hooks']->dispatch('multiple.request.complete', array(&$response, $id));
489
-			}
490
-		}
491
-
492
-		return $responses;
493
-	}
494
-
495
-	/**
496
-	 * Get the default options
497
-	 *
498
-	 * @see Requests::request() for values returned by this method
499
-	 * @param boolean $multirequest Is this a multirequest?
500
-	 * @return array Default option values
501
-	 */
502
-	protected static function get_default_options($multirequest = false) {
503
-		$defaults = array(
504
-			'timeout' => 10,
505
-			'connect_timeout' => 10,
506
-			'useragent' => 'php-requests/' . self::VERSION,
507
-			'protocol_version' => 1.1,
508
-			'redirected' => 0,
509
-			'redirects' => 10,
510
-			'follow_redirects' => true,
511
-			'blocking' => true,
512
-			'type' => self::GET,
513
-			'filename' => false,
514
-			'auth' => false,
515
-			'proxy' => false,
516
-			'cookies' => false,
517
-			'max_bytes' => false,
518
-			'idn' => true,
519
-			'hooks' => null,
520
-			'transport' => null,
521
-			'verify' => Requests::get_certificate_path(),
522
-			'verifyname' => true,
523
-		);
524
-		if ($multirequest !== false) {
525
-			$defaults['complete'] = null;
526
-		}
527
-		return $defaults;
528
-	}
529
-
530
-	/**
531
-	 * Get default certificate path.
532
-	 *
533
-	 * @return string Default certificate path.
534
-	 */
535
-	public static function get_certificate_path() {
536
-		if ( ! empty( Requests::$certificate_path ) ) {
537
-			return Requests::$certificate_path;
538
-		}
539
-
540
-		return dirname(__FILE__) . '/Requests/Transport/cacert.pem';
541
-	}
542
-
543
-	/**
544
-	 * Set default certificate path.
545
-	 *
546
-	 * @param string $path Certificate path, pointing to a PEM file.
547
-	 */
548
-	public static function set_certificate_path( $path ) {
549
-		Requests::$certificate_path = $path;
550
-	}
551
-
552
-	/**
553
-	 * Set the default values
554
-	 *
555
-	 * @param string $url URL to request
556
-	 * @param array $headers Extra headers to send with the request
557
-	 * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
558
-	 * @param string $type HTTP request type
559
-	 * @param array $options Options for the request
560
-	 * @return array $options
561
-	 */
562
-	protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) {
563
-		if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) {
564
-			throw new Requests_Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url);
565
-		}
566
-
567
-		if (empty($options['hooks'])) {
568
-			$options['hooks'] = new Requests_Hooks();
569
-		}
570
-
571
-		if (is_array($options['auth'])) {
572
-			$options['auth'] = new Requests_Auth_Basic($options['auth']);
573
-		}
574
-		if ($options['auth'] !== false) {
575
-			$options['auth']->register($options['hooks']);
576
-		}
577
-
578
-		if (is_string($options['proxy']) || is_array($options['proxy'])) {
579
-			$options['proxy'] = new Requests_Proxy_HTTP($options['proxy']);
580
-		}
581
-		if ($options['proxy'] !== false) {
582
-			$options['proxy']->register($options['hooks']);
583
-		}
584
-
585
-		if (is_array($options['cookies'])) {
586
-			$options['cookies'] = new Requests_Cookie_Jar($options['cookies']);
587
-		}
588
-		elseif (empty($options['cookies'])) {
589
-			$options['cookies'] = new Requests_Cookie_Jar();
590
-		}
591
-		if ($options['cookies'] !== false) {
592
-			$options['cookies']->register($options['hooks']);
593
-		}
594
-
595
-		if ($options['idn'] !== false) {
596
-			$iri = new Requests_IRI($url);
597
-			$iri->host = Requests_IDNAEncoder::encode($iri->ihost);
598
-			$url = $iri->uri;
599
-		}
600
-
601
-		// Massage the type to ensure we support it.
602
-		$type = strtoupper($type);
603
-
604
-		if (!isset($options['data_format'])) {
605
-			if (in_array($type, array(self::HEAD, self::GET, self::DELETE))) {
606
-				$options['data_format'] = 'query';
607
-			}
608
-			else {
609
-				$options['data_format'] = 'body';
610
-			}
611
-		}
612
-	}
613
-
614
-	/**
615
-	 * HTTP response parser
616
-	 *
617
-	 * @throws Requests_Exception On missing head/body separator (`requests.no_crlf_separator`)
618
-	 * @throws Requests_Exception On missing head/body separator (`noversion`)
619
-	 * @throws Requests_Exception On missing head/body separator (`toomanyredirects`)
620
-	 *
621
-	 * @param string $headers Full response text including headers and body
622
-	 * @param string $url Original request URL
623
-	 * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects
624
-	 * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects
625
-	 * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects
626
-	 * @return Requests_Response
627
-	 */
628
-	protected static function parse_response($headers, $url, $req_headers, $req_data, $options) {
629
-		$return = new Requests_Response();
630
-		if (!$options['blocking']) {
631
-			return $return;
632
-		}
633
-
634
-		$return->raw = $headers;
635
-		$return->url = $url;
636
-
637
-		if (!$options['filename']) {
638
-			if (($pos = strpos($headers, "\r\n\r\n")) === false) {
639
-				// Crap!
640
-				throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator');
641
-			}
642
-
643
-			$headers = substr($return->raw, 0, $pos);
644
-			$return->body = substr($return->raw, $pos + strlen("\n\r\n\r"));
645
-		}
646
-		else {
647
-			$return->body = '';
648
-		}
649
-		// Pretend CRLF = LF for compatibility (RFC 2616, section 19.3)
650
-		$headers = str_replace("\r\n", "\n", $headers);
651
-		// Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2)
652
-		$headers = preg_replace('/\n[ \t]/', ' ', $headers);
653
-		$headers = explode("\n", $headers);
654
-		preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches);
655
-		if (empty($matches)) {
656
-			throw new Requests_Exception('Response could not be parsed', 'noversion', $headers);
657
-		}
658
-		$return->protocol_version = (float) $matches[1];
659
-		$return->status_code = (int) $matches[2];
660
-		if ($return->status_code >= 200 && $return->status_code < 300) {
661
-			$return->success = true;
662
-		}
663
-
664
-		foreach ($headers as $header) {
665
-			list($key, $value) = explode(':', $header, 2);
666
-			$value = trim($value);
667
-			preg_replace('#(\s+)#i', ' ', $value);
668
-			$return->headers[$key] = $value;
669
-		}
670
-		if (isset($return->headers['transfer-encoding'])) {
671
-			$return->body = self::decode_chunked($return->body);
672
-			unset($return->headers['transfer-encoding']);
673
-		}
674
-		if (isset($return->headers['content-encoding'])) {
675
-			$return->body = self::decompress($return->body);
676
-		}
677
-
678
-		//fsockopen and cURL compatibility
679
-		if (isset($return->headers['connection'])) {
680
-			unset($return->headers['connection']);
681
-		}
682
-
683
-		$options['hooks']->dispatch('requests.before_redirect_check', array(&$return, $req_headers, $req_data, $options));
684
-
685
-		if ($return->is_redirect() && $options['follow_redirects'] === true) {
686
-			if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) {
687
-				if ($return->status_code === 303) {
688
-					$options['type'] = self::GET;
689
-				}
690
-				$options['redirected']++;
691
-				$location = $return->headers['location'];
692
-				if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) {
693
-					// relative redirect, for compatibility make it absolute
694
-					$location = Requests_IRI::absolutize($url, $location);
695
-					$location = $location->uri;
696
-				}
697
-
698
-				$hook_args = array(
699
-					&$location,
700
-					&$req_headers,
701
-					&$req_data,
702
-					&$options,
703
-					$return
704
-				);
705
-				$options['hooks']->dispatch('requests.before_redirect', $hook_args);
706
-				$redirected = self::request($location, $req_headers, $req_data, $options['type'], $options);
707
-				$redirected->history[] = $return;
708
-				return $redirected;
709
-			}
710
-			elseif ($options['redirected'] >= $options['redirects']) {
711
-				throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return);
712
-			}
713
-		}
714
-
715
-		$return->redirects = $options['redirected'];
716
-
717
-		$options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options));
718
-		return $return;
719
-	}
720
-
721
-	/**
722
-	 * Callback for `transport.internal.parse_response`
723
-	 *
724
-	 * Internal use only. Converts a raw HTTP response to a Requests_Response
725
-	 * while still executing a multiple request.
726
-	 *
727
-	 * @param string $response Full response text including headers and body (will be overwritten with Response instance)
728
-	 * @param array $request Request data as passed into {@see Requests::request_multiple()}
729
-	 * @return null `$response` is either set to a Requests_Response instance, or a Requests_Exception object
730
-	 */
731
-	public static function parse_multiple(&$response, $request) {
732
-		try {
733
-			$url = $request['url'];
734
-			$headers = $request['headers'];
735
-			$data = $request['data'];
736
-			$options = $request['options'];
737
-			$response = self::parse_response($response, $url, $headers, $data, $options);
738
-		}
739
-		catch (Requests_Exception $e) {
740
-			$response = $e;
741
-		}
742
-	}
743
-
744
-	/**
745
-	 * Decoded a chunked body as per RFC 2616
746
-	 *
747
-	 * @see https://tools.ietf.org/html/rfc2616#section-3.6.1
748
-	 * @param string $data Chunked body
749
-	 * @return string Decoded body
750
-	 */
751
-	protected static function decode_chunked($data) {
752
-		if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) {
753
-			return $data;
754
-		}
755
-
756
-
757
-
758
-		$decoded = '';
759
-		$encoded = $data;
760
-
761
-		while (true) {
762
-			$is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches);
763
-			if (!$is_chunked) {
764
-				// Looks like it's not chunked after all
765
-				return $data;
766
-			}
767
-
768
-			$length = hexdec(trim($matches[1]));
769
-			if ($length === 0) {
770
-				// Ignore trailer headers
771
-				return $decoded;
772
-			}
773
-
774
-			$chunk_length = strlen($matches[0]);
775
-			$decoded .= substr($encoded, $chunk_length, $length);
776
-			$encoded = substr($encoded, $chunk_length + $length + 2);
777
-
778
-			if (trim($encoded) === '0' || empty($encoded)) {
779
-				return $decoded;
780
-			}
781
-		}
782
-
783
-		// We'll never actually get down here
784
-		// @codeCoverageIgnoreStart
785
-	}
786
-	// @codeCoverageIgnoreEnd
787
-
788
-	/**
789
-	 * Convert a key => value array to a 'key: value' array for headers
790
-	 *
791
-	 * @param array $array Dictionary of header values
792
-	 * @return array List of headers
793
-	 */
794
-	public static function flatten($array) {
795
-		$return = array();
796
-		foreach ($array as $key => $value) {
797
-			$return[] = sprintf('%s: %s', $key, $value);
798
-		}
799
-		return $return;
800
-	}
801
-
802
-	/**
803
-	 * Convert a key => value array to a 'key: value' array for headers
804
-	 *
805
-	 * @codeCoverageIgnore
806
-	 * @deprecated Misspelling of {@see Requests::flatten}
807
-	 * @param array $array Dictionary of header values
808
-	 * @return array List of headers
809
-	 */
810
-	public static function flattern($array) {
811
-		return self::flatten($array);
812
-	}
813
-
814
-	/**
815
-	 * Decompress an encoded body
816
-	 *
817
-	 * Implements gzip, compress and deflate. Guesses which it is by attempting
818
-	 * to decode.
819
-	 *
820
-	 * @param string $data Compressed data in one of the above formats
821
-	 * @return string Decompressed string
822
-	 */
823
-	public static function decompress($data) {
824
-		if (substr($data, 0, 2) !== "\x1f\x8b" && substr($data, 0, 2) !== "\x78\x9c") {
825
-			// Not actually compressed. Probably cURL ruining this for us.
826
-			return $data;
827
-		}
828
-
829
-		if (function_exists('gzdecode') && ($decoded = @gzdecode($data)) !== false) {
830
-			return $decoded;
831
-		}
832
-		elseif (function_exists('gzinflate') && ($decoded = @gzinflate($data)) !== false) {
833
-			return $decoded;
834
-		}
835
-		elseif (($decoded = self::compatible_gzinflate($data)) !== false) {
836
-			return $decoded;
837
-		}
838
-		elseif (function_exists('gzuncompress') && ($decoded = @gzuncompress($data)) !== false) {
839
-			return $decoded;
840
-		}
841
-
842
-		return $data;
843
-	}
844
-
845
-	/**
846
-	 * Decompression of deflated string while staying compatible with the majority of servers.
847
-	 *
848
-	 * Certain Servers will return deflated data with headers which PHP's gzinflate()
849
-	 * function cannot handle out of the box. The following function has been created from
850
-	 * various snippets on the gzinflate() PHP documentation.
851
-	 *
852
-	 * Warning: Magic numbers within. Due to the potential different formats that the compressed
853
-	 * data may be returned in, some "magic offsets" are needed to ensure proper decompression
854
-	 * takes place. For a simple progmatic way to determine the magic offset in use, see:
855
-	 * https://core.trac.wordpress.org/ticket/18273
856
-	 *
857
-	 * @since 2.8.1
858
-	 * @link https://core.trac.wordpress.org/ticket/18273
859
-	 * @link https://secure.php.net/manual/en/function.gzinflate.php#70875
860
-	 * @link https://secure.php.net/manual/en/function.gzinflate.php#77336
861
-	 *
862
-	 * @param string $gzData String to decompress.
863
-	 * @return string|bool False on failure.
864
-	 */
865
-	public static function compatible_gzinflate($gzData) {
866
-		// Compressed data might contain a full zlib header, if so strip it for
867
-		// gzinflate()
868
-		if (substr($gzData, 0, 3) == "\x1f\x8b\x08") {
869
-			$i = 10;
870
-			$flg = ord(substr($gzData, 3, 1));
871
-			if ($flg > 0) {
872
-				if ($flg & 4) {
873
-					list($xlen) = unpack('v', substr($gzData, $i, 2));
874
-					$i = $i + 2 + $xlen;
875
-				}
876
-				if ($flg & 8) {
877
-					$i = strpos($gzData, "\0", $i) + 1;
878
-				}
879
-				if ($flg & 16) {
880
-					$i = strpos($gzData, "\0", $i) + 1;
881
-				}
882
-				if ($flg & 2) {
883
-					$i = $i + 2;
884
-				}
885
-			}
886
-			$decompressed = self::compatible_gzinflate(substr($gzData, $i));
887
-			if (false !== $decompressed) {
888
-				return $decompressed;
889
-			}
890
-		}
891
-
892
-		// If the data is Huffman Encoded, we must first strip the leading 2
893
-		// byte Huffman marker for gzinflate()
894
-		// The response is Huffman coded by many compressors such as
895
-		// java.util.zip.Deflater, Ruby’s Zlib::Deflate, and .NET's
896
-		// System.IO.Compression.DeflateStream.
897
-		//
898
-		// See https://decompres.blogspot.com/ for a quick explanation of this
899
-		// data type
900
-		$huffman_encoded = false;
901
-
902
-		// low nibble of first byte should be 0x08
903
-		list(, $first_nibble)    = unpack('h', $gzData);
904
-
905
-		// First 2 bytes should be divisible by 0x1F
906
-		list(, $first_two_bytes) = unpack('n', $gzData);
907
-
908
-		if (0x08 == $first_nibble && 0 == ($first_two_bytes % 0x1F)) {
909
-			$huffman_encoded = true;
910
-		}
911
-
912
-		if ($huffman_encoded) {
913
-			if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) {
914
-				return $decompressed;
915
-			}
916
-		}
917
-
918
-		if ("\x50\x4b\x03\x04" == substr($gzData, 0, 4)) {
919
-			// ZIP file format header
920
-			// Offset 6: 2 bytes, General-purpose field
921
-			// Offset 26: 2 bytes, filename length
922
-			// Offset 28: 2 bytes, optional field length
923
-			// Offset 30: Filename field, followed by optional field, followed
924
-			// immediately by data
925
-			list(, $general_purpose_flag) = unpack('v', substr($gzData, 6, 2));
926
-
927
-			// If the file has been compressed on the fly, 0x08 bit is set of
928
-			// the general purpose field. We can use this to differentiate
929
-			// between a compressed document, and a ZIP file
930
-			$zip_compressed_on_the_fly = (0x08 == (0x08 & $general_purpose_flag));
931
-
932
-			if (!$zip_compressed_on_the_fly) {
933
-				// Don't attempt to decode a compressed zip file
934
-				return $gzData;
935
-			}
936
-
937
-			// Determine the first byte of data, based on the above ZIP header
938
-			// offsets:
939
-			$first_file_start = array_sum(unpack('v2', substr($gzData, 26, 4)));
940
-			if (false !== ($decompressed = @gzinflate(substr($gzData, 30 + $first_file_start)))) {
941
-				return $decompressed;
942
-			}
943
-			return false;
944
-		}
945
-
946
-		// Finally fall back to straight gzinflate
947
-		if (false !== ($decompressed = @gzinflate($gzData))) {
948
-			return $decompressed;
949
-		}
950
-
951
-		// Fallback for all above failing, not expected, but included for
952
-		// debugging and preventing regressions and to track stats
953
-		if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) {
954
-			return $decompressed;
955
-		}
956
-
957
-		return false;
958
-	}
959
-
960
-	public static function match_domain($host, $reference) {
961
-		// Check for a direct match
962
-		if ($host === $reference) {
963
-			return true;
964
-		}
965
-
966
-		// Calculate the valid wildcard match if the host is not an IP address
967
-		// Also validates that the host has 3 parts or more, as per Firefox's
968
-		// ruleset.
969
-		$parts = explode('.', $host);
970
-		if (ip2long($host) === false && count($parts) >= 3) {
971
-			$parts[0] = '*';
972
-			$wildcard = implode('.', $parts);
973
-			if ($wildcard === $reference) {
974
-				return true;
975
-			}
976
-		}
977
-
978
-		return false;
979
-	}
264
+    /**
265
+     * Send a POST request
266
+     */
267
+    public static function post($url, $headers = array(), $data = array(), $options = array()) {
268
+        return self::request($url, $headers, $data, self::POST, $options);
269
+    }
270
+    /**
271
+     * Send a PUT request
272
+     */
273
+    public static function put($url, $headers = array(), $data = array(), $options = array()) {
274
+        return self::request($url, $headers, $data, self::PUT, $options);
275
+    }
276
+
277
+    /**
278
+     * Send an OPTIONS request
279
+     */
280
+    public static function options($url, $headers = array(), $data = array(), $options = array()) {
281
+        return self::request($url, $headers, $data, self::OPTIONS, $options);
282
+    }
283
+
284
+    /**
285
+     * Send a PATCH request
286
+     *
287
+     * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
288
+     * specification recommends that should send an ETag
289
+     *
290
+     * @link https://tools.ietf.org/html/rfc5789
291
+     */
292
+    public static function patch($url, $headers, $data = array(), $options = array()) {
293
+        return self::request($url, $headers, $data, self::PATCH, $options);
294
+    }
295
+    /**#@-*/
296
+
297
+    /**
298
+     * Main interface for HTTP requests
299
+     *
300
+     * This method initiates a request and sends it via a transport before
301
+     * parsing.
302
+     *
303
+     * The `$options` parameter takes an associative array with the following
304
+     * options:
305
+     *
306
+     * - `timeout`: How long should we wait for a response?
307
+     *    Note: for cURL, a minimum of 1 second applies, as DNS resolution
308
+     *    operates at second-resolution only.
309
+     *    (float, seconds with a millisecond precision, default: 10, example: 0.01)
310
+     * - `connect_timeout`: How long should we wait while trying to connect?
311
+     *    (float, seconds with a millisecond precision, default: 10, example: 0.01)
312
+     * - `useragent`: Useragent to send to the server
313
+     *    (string, default: php-requests/$version)
314
+     * - `follow_redirects`: Should we follow 3xx redirects?
315
+     *    (boolean, default: true)
316
+     * - `redirects`: How many times should we redirect before erroring?
317
+     *    (integer, default: 10)
318
+     * - `blocking`: Should we block processing on this request?
319
+     *    (boolean, default: true)
320
+     * - `filename`: File to stream the body to instead.
321
+     *    (string|boolean, default: false)
322
+     * - `auth`: Authentication handler or array of user/password details to use
323
+     *    for Basic authentication
324
+     *    (Requests_Auth|array|boolean, default: false)
325
+     * - `proxy`: Proxy details to use for proxy by-passing and authentication
326
+     *    (Requests_Proxy|array|string|boolean, default: false)
327
+     * - `max_bytes`: Limit for the response body size.
328
+     *    (integer|boolean, default: false)
329
+     * - `idn`: Enable IDN parsing
330
+     *    (boolean, default: true)
331
+     * - `transport`: Custom transport. Either a class name, or a
332
+     *    transport object. Defaults to the first working transport from
333
+     *    {@see getTransport()}
334
+     *    (string|Requests_Transport, default: {@see getTransport()})
335
+     * - `hooks`: Hooks handler.
336
+     *    (Requests_Hooker, default: new Requests_Hooks())
337
+     * - `verify`: Should we verify SSL certificates? Allows passing in a custom
338
+     *    certificate file as a string. (Using true uses the system-wide root
339
+     *    certificate store instead, but this may have different behaviour
340
+     *    across transports.)
341
+     *    (string|boolean, default: library/Requests/Transport/cacert.pem)
342
+     * - `verifyname`: Should we verify the common name in the SSL certificate?
343
+     *    (boolean: default, true)
344
+     * - `data_format`: How should we send the `$data` parameter?
345
+     *    (string, one of 'query' or 'body', default: 'query' for
346
+     *    HEAD/GET/DELETE, 'body' for POST/PUT/OPTIONS/PATCH)
347
+     *
348
+     * @throws Requests_Exception On invalid URLs (`nonhttp`)
349
+     *
350
+     * @param string $url URL to request
351
+     * @param array $headers Extra headers to send with the request
352
+     * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
353
+     * @param string $type HTTP request type (use Requests constants)
354
+     * @param array $options Options for the request (see description for more information)
355
+     * @return Requests_Response
356
+     */
357
+    public static function request($url, $headers = array(), $data = array(), $type = self::GET, $options = array()) {
358
+        if (empty($options['type'])) {
359
+            $options['type'] = $type;
360
+        }
361
+        $options = array_merge(self::get_default_options(), $options);
362
+
363
+        self::set_defaults($url, $headers, $data, $type, $options);
364
+
365
+        $options['hooks']->dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options));
366
+
367
+        if (!empty($options['transport'])) {
368
+            $transport = $options['transport'];
369
+
370
+            if (is_string($options['transport'])) {
371
+                $transport = new $transport();
372
+            }
373
+        }
374
+        else {
375
+            $need_ssl = (0 === stripos($url, 'https://'));
376
+            $capabilities = array('ssl' => $need_ssl);
377
+            $transport = self::get_transport($capabilities);
378
+        }
379
+        $response = $transport->request($url, $headers, $data, $options);
380
+
381
+        $options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options));
382
+
383
+        return self::parse_response($response, $url, $headers, $data, $options);
384
+    }
385
+
386
+    /**
387
+     * Send multiple HTTP requests simultaneously
388
+     *
389
+     * The `$requests` parameter takes an associative or indexed array of
390
+     * request fields. The key of each request can be used to match up the
391
+     * request with the returned data, or with the request passed into your
392
+     * `multiple.request.complete` callback.
393
+     *
394
+     * The request fields value is an associative array with the following keys:
395
+     *
396
+     * - `url`: Request URL Same as the `$url` parameter to
397
+     *    {@see Requests::request}
398
+     *    (string, required)
399
+     * - `headers`: Associative array of header fields. Same as the `$headers`
400
+     *    parameter to {@see Requests::request}
401
+     *    (array, default: `array()`)
402
+     * - `data`: Associative array of data fields or a string. Same as the
403
+     *    `$data` parameter to {@see Requests::request}
404
+     *    (array|string, default: `array()`)
405
+     * - `type`: HTTP request type (use Requests constants). Same as the `$type`
406
+     *    parameter to {@see Requests::request}
407
+     *    (string, default: `Requests::GET`)
408
+     * - `cookies`: Associative array of cookie name to value, or cookie jar.
409
+     *    (array|Requests_Cookie_Jar)
410
+     *
411
+     * If the `$options` parameter is specified, individual requests will
412
+     * inherit options from it. This can be used to use a single hooking system,
413
+     * or set all the types to `Requests::POST`, for example.
414
+     *
415
+     * In addition, the `$options` parameter takes the following global options:
416
+     *
417
+     * - `complete`: A callback for when a request is complete. Takes two
418
+     *    parameters, a Requests_Response/Requests_Exception reference, and the
419
+     *    ID from the request array (Note: this can also be overridden on a
420
+     *    per-request basis, although that's a little silly)
421
+     *    (callback)
422
+     *
423
+     * @param array $requests Requests data (see description for more information)
424
+     * @param array $options Global and default options (see {@see Requests::request})
425
+     * @return array Responses (either Requests_Response or a Requests_Exception object)
426
+     */
427
+    public static function request_multiple($requests, $options = array()) {
428
+        $options = array_merge(self::get_default_options(true), $options);
429
+
430
+        if (!empty($options['hooks'])) {
431
+            $options['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
432
+            if (!empty($options['complete'])) {
433
+                $options['hooks']->register('multiple.request.complete', $options['complete']);
434
+            }
435
+        }
436
+
437
+        foreach ($requests as $id => &$request) {
438
+            if (!isset($request['headers'])) {
439
+                $request['headers'] = array();
440
+            }
441
+            if (!isset($request['data'])) {
442
+                $request['data'] = array();
443
+            }
444
+            if (!isset($request['type'])) {
445
+                $request['type'] = self::GET;
446
+            }
447
+            if (!isset($request['options'])) {
448
+                $request['options'] = $options;
449
+                $request['options']['type'] = $request['type'];
450
+            }
451
+            else {
452
+                if (empty($request['options']['type'])) {
453
+                    $request['options']['type'] = $request['type'];
454
+                }
455
+                $request['options'] = array_merge($options, $request['options']);
456
+            }
457
+
458
+            self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']);
459
+
460
+            // Ensure we only hook in once
461
+            if ($request['options']['hooks'] !== $options['hooks']) {
462
+                $request['options']['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
463
+                if (!empty($request['options']['complete'])) {
464
+                    $request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']);
465
+                }
466
+            }
467
+        }
468
+        unset($request);
469
+
470
+        if (!empty($options['transport'])) {
471
+            $transport = $options['transport'];
472
+
473
+            if (is_string($options['transport'])) {
474
+                $transport = new $transport();
475
+            }
476
+        }
477
+        else {
478
+            $transport = self::get_transport();
479
+        }
480
+        $responses = $transport->request_multiple($requests, $options);
481
+
482
+        foreach ($responses as $id => &$response) {
483
+            // If our hook got messed with somehow, ensure we end up with the
484
+            // correct response
485
+            if (is_string($response)) {
486
+                $request = $requests[$id];
487
+                self::parse_multiple($response, $request);
488
+                $request['options']['hooks']->dispatch('multiple.request.complete', array(&$response, $id));
489
+            }
490
+        }
491
+
492
+        return $responses;
493
+    }
494
+
495
+    /**
496
+     * Get the default options
497
+     *
498
+     * @see Requests::request() for values returned by this method
499
+     * @param boolean $multirequest Is this a multirequest?
500
+     * @return array Default option values
501
+     */
502
+    protected static function get_default_options($multirequest = false) {
503
+        $defaults = array(
504
+            'timeout' => 10,
505
+            'connect_timeout' => 10,
506
+            'useragent' => 'php-requests/' . self::VERSION,
507
+            'protocol_version' => 1.1,
508
+            'redirected' => 0,
509
+            'redirects' => 10,
510
+            'follow_redirects' => true,
511
+            'blocking' => true,
512
+            'type' => self::GET,
513
+            'filename' => false,
514
+            'auth' => false,
515
+            'proxy' => false,
516
+            'cookies' => false,
517
+            'max_bytes' => false,
518
+            'idn' => true,
519
+            'hooks' => null,
520
+            'transport' => null,
521
+            'verify' => Requests::get_certificate_path(),
522
+            'verifyname' => true,
523
+        );
524
+        if ($multirequest !== false) {
525
+            $defaults['complete'] = null;
526
+        }
527
+        return $defaults;
528
+    }
529
+
530
+    /**
531
+     * Get default certificate path.
532
+     *
533
+     * @return string Default certificate path.
534
+     */
535
+    public static function get_certificate_path() {
536
+        if ( ! empty( Requests::$certificate_path ) ) {
537
+            return Requests::$certificate_path;
538
+        }
539
+
540
+        return dirname(__FILE__) . '/Requests/Transport/cacert.pem';
541
+    }
542
+
543
+    /**
544
+     * Set default certificate path.
545
+     *
546
+     * @param string $path Certificate path, pointing to a PEM file.
547
+     */
548
+    public static function set_certificate_path( $path ) {
549
+        Requests::$certificate_path = $path;
550
+    }
551
+
552
+    /**
553
+     * Set the default values
554
+     *
555
+     * @param string $url URL to request
556
+     * @param array $headers Extra headers to send with the request
557
+     * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
558
+     * @param string $type HTTP request type
559
+     * @param array $options Options for the request
560
+     * @return array $options
561
+     */
562
+    protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) {
563
+        if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) {
564
+            throw new Requests_Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url);
565
+        }
566
+
567
+        if (empty($options['hooks'])) {
568
+            $options['hooks'] = new Requests_Hooks();
569
+        }
570
+
571
+        if (is_array($options['auth'])) {
572
+            $options['auth'] = new Requests_Auth_Basic($options['auth']);
573
+        }
574
+        if ($options['auth'] !== false) {
575
+            $options['auth']->register($options['hooks']);
576
+        }
577
+
578
+        if (is_string($options['proxy']) || is_array($options['proxy'])) {
579
+            $options['proxy'] = new Requests_Proxy_HTTP($options['proxy']);
580
+        }
581
+        if ($options['proxy'] !== false) {
582
+            $options['proxy']->register($options['hooks']);
583
+        }
584
+
585
+        if (is_array($options['cookies'])) {
586
+            $options['cookies'] = new Requests_Cookie_Jar($options['cookies']);
587
+        }
588
+        elseif (empty($options['cookies'])) {
589
+            $options['cookies'] = new Requests_Cookie_Jar();
590
+        }
591
+        if ($options['cookies'] !== false) {
592
+            $options['cookies']->register($options['hooks']);
593
+        }
594
+
595
+        if ($options['idn'] !== false) {
596
+            $iri = new Requests_IRI($url);
597
+            $iri->host = Requests_IDNAEncoder::encode($iri->ihost);
598
+            $url = $iri->uri;
599
+        }
600
+
601
+        // Massage the type to ensure we support it.
602
+        $type = strtoupper($type);
603
+
604
+        if (!isset($options['data_format'])) {
605
+            if (in_array($type, array(self::HEAD, self::GET, self::DELETE))) {
606
+                $options['data_format'] = 'query';
607
+            }
608
+            else {
609
+                $options['data_format'] = 'body';
610
+            }
611
+        }
612
+    }
613
+
614
+    /**
615
+     * HTTP response parser
616
+     *
617
+     * @throws Requests_Exception On missing head/body separator (`requests.no_crlf_separator`)
618
+     * @throws Requests_Exception On missing head/body separator (`noversion`)
619
+     * @throws Requests_Exception On missing head/body separator (`toomanyredirects`)
620
+     *
621
+     * @param string $headers Full response text including headers and body
622
+     * @param string $url Original request URL
623
+     * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects
624
+     * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects
625
+     * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects
626
+     * @return Requests_Response
627
+     */
628
+    protected static function parse_response($headers, $url, $req_headers, $req_data, $options) {
629
+        $return = new Requests_Response();
630
+        if (!$options['blocking']) {
631
+            return $return;
632
+        }
633
+
634
+        $return->raw = $headers;
635
+        $return->url = $url;
636
+
637
+        if (!$options['filename']) {
638
+            if (($pos = strpos($headers, "\r\n\r\n")) === false) {
639
+                // Crap!
640
+                throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator');
641
+            }
642
+
643
+            $headers = substr($return->raw, 0, $pos);
644
+            $return->body = substr($return->raw, $pos + strlen("\n\r\n\r"));
645
+        }
646
+        else {
647
+            $return->body = '';
648
+        }
649
+        // Pretend CRLF = LF for compatibility (RFC 2616, section 19.3)
650
+        $headers = str_replace("\r\n", "\n", $headers);
651
+        // Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2)
652
+        $headers = preg_replace('/\n[ \t]/', ' ', $headers);
653
+        $headers = explode("\n", $headers);
654
+        preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches);
655
+        if (empty($matches)) {
656
+            throw new Requests_Exception('Response could not be parsed', 'noversion', $headers);
657
+        }
658
+        $return->protocol_version = (float) $matches[1];
659
+        $return->status_code = (int) $matches[2];
660
+        if ($return->status_code >= 200 && $return->status_code < 300) {
661
+            $return->success = true;
662
+        }
663
+
664
+        foreach ($headers as $header) {
665
+            list($key, $value) = explode(':', $header, 2);
666
+            $value = trim($value);
667
+            preg_replace('#(\s+)#i', ' ', $value);
668
+            $return->headers[$key] = $value;
669
+        }
670
+        if (isset($return->headers['transfer-encoding'])) {
671
+            $return->body = self::decode_chunked($return->body);
672
+            unset($return->headers['transfer-encoding']);
673
+        }
674
+        if (isset($return->headers['content-encoding'])) {
675
+            $return->body = self::decompress($return->body);
676
+        }
677
+
678
+        //fsockopen and cURL compatibility
679
+        if (isset($return->headers['connection'])) {
680
+            unset($return->headers['connection']);
681
+        }
682
+
683
+        $options['hooks']->dispatch('requests.before_redirect_check', array(&$return, $req_headers, $req_data, $options));
684
+
685
+        if ($return->is_redirect() && $options['follow_redirects'] === true) {
686
+            if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) {
687
+                if ($return->status_code === 303) {
688
+                    $options['type'] = self::GET;
689
+                }
690
+                $options['redirected']++;
691
+                $location = $return->headers['location'];
692
+                if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) {
693
+                    // relative redirect, for compatibility make it absolute
694
+                    $location = Requests_IRI::absolutize($url, $location);
695
+                    $location = $location->uri;
696
+                }
697
+
698
+                $hook_args = array(
699
+                    &$location,
700
+                    &$req_headers,
701
+                    &$req_data,
702
+                    &$options,
703
+                    $return
704
+                );
705
+                $options['hooks']->dispatch('requests.before_redirect', $hook_args);
706
+                $redirected = self::request($location, $req_headers, $req_data, $options['type'], $options);
707
+                $redirected->history[] = $return;
708
+                return $redirected;
709
+            }
710
+            elseif ($options['redirected'] >= $options['redirects']) {
711
+                throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return);
712
+            }
713
+        }
714
+
715
+        $return->redirects = $options['redirected'];
716
+
717
+        $options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options));
718
+        return $return;
719
+    }
720
+
721
+    /**
722
+     * Callback for `transport.internal.parse_response`
723
+     *
724
+     * Internal use only. Converts a raw HTTP response to a Requests_Response
725
+     * while still executing a multiple request.
726
+     *
727
+     * @param string $response Full response text including headers and body (will be overwritten with Response instance)
728
+     * @param array $request Request data as passed into {@see Requests::request_multiple()}
729
+     * @return null `$response` is either set to a Requests_Response instance, or a Requests_Exception object
730
+     */
731
+    public static function parse_multiple(&$response, $request) {
732
+        try {
733
+            $url = $request['url'];
734
+            $headers = $request['headers'];
735
+            $data = $request['data'];
736
+            $options = $request['options'];
737
+            $response = self::parse_response($response, $url, $headers, $data, $options);
738
+        }
739
+        catch (Requests_Exception $e) {
740
+            $response = $e;
741
+        }
742
+    }
743
+
744
+    /**
745
+     * Decoded a chunked body as per RFC 2616
746
+     *
747
+     * @see https://tools.ietf.org/html/rfc2616#section-3.6.1
748
+     * @param string $data Chunked body
749
+     * @return string Decoded body
750
+     */
751
+    protected static function decode_chunked($data) {
752
+        if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) {
753
+            return $data;
754
+        }
755
+
756
+
757
+
758
+        $decoded = '';
759
+        $encoded = $data;
760
+
761
+        while (true) {
762
+            $is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches);
763
+            if (!$is_chunked) {
764
+                // Looks like it's not chunked after all
765
+                return $data;
766
+            }
767
+
768
+            $length = hexdec(trim($matches[1]));
769
+            if ($length === 0) {
770
+                // Ignore trailer headers
771
+                return $decoded;
772
+            }
773
+
774
+            $chunk_length = strlen($matches[0]);
775
+            $decoded .= substr($encoded, $chunk_length, $length);
776
+            $encoded = substr($encoded, $chunk_length + $length + 2);
777
+
778
+            if (trim($encoded) === '0' || empty($encoded)) {
779
+                return $decoded;
780
+            }
781
+        }
782
+
783
+        // We'll never actually get down here
784
+        // @codeCoverageIgnoreStart
785
+    }
786
+    // @codeCoverageIgnoreEnd
787
+
788
+    /**
789
+     * Convert a key => value array to a 'key: value' array for headers
790
+     *
791
+     * @param array $array Dictionary of header values
792
+     * @return array List of headers
793
+     */
794
+    public static function flatten($array) {
795
+        $return = array();
796
+        foreach ($array as $key => $value) {
797
+            $return[] = sprintf('%s: %s', $key, $value);
798
+        }
799
+        return $return;
800
+    }
801
+
802
+    /**
803
+     * Convert a key => value array to a 'key: value' array for headers
804
+     *
805
+     * @codeCoverageIgnore
806
+     * @deprecated Misspelling of {@see Requests::flatten}
807
+     * @param array $array Dictionary of header values
808
+     * @return array List of headers
809
+     */
810
+    public static function flattern($array) {
811
+        return self::flatten($array);
812
+    }
813
+
814
+    /**
815
+     * Decompress an encoded body
816
+     *
817
+     * Implements gzip, compress and deflate. Guesses which it is by attempting
818
+     * to decode.
819
+     *
820
+     * @param string $data Compressed data in one of the above formats
821
+     * @return string Decompressed string
822
+     */
823
+    public static function decompress($data) {
824
+        if (substr($data, 0, 2) !== "\x1f\x8b" && substr($data, 0, 2) !== "\x78\x9c") {
825
+            // Not actually compressed. Probably cURL ruining this for us.
826
+            return $data;
827
+        }
828
+
829
+        if (function_exists('gzdecode') && ($decoded = @gzdecode($data)) !== false) {
830
+            return $decoded;
831
+        }
832
+        elseif (function_exists('gzinflate') && ($decoded = @gzinflate($data)) !== false) {
833
+            return $decoded;
834
+        }
835
+        elseif (($decoded = self::compatible_gzinflate($data)) !== false) {
836
+            return $decoded;
837
+        }
838
+        elseif (function_exists('gzuncompress') && ($decoded = @gzuncompress($data)) !== false) {
839
+            return $decoded;
840
+        }
841
+
842
+        return $data;
843
+    }
844
+
845
+    /**
846
+     * Decompression of deflated string while staying compatible with the majority of servers.
847
+     *
848
+     * Certain Servers will return deflated data with headers which PHP's gzinflate()
849
+     * function cannot handle out of the box. The following function has been created from
850
+     * various snippets on the gzinflate() PHP documentation.
851
+     *
852
+     * Warning: Magic numbers within. Due to the potential different formats that the compressed
853
+     * data may be returned in, some "magic offsets" are needed to ensure proper decompression
854
+     * takes place. For a simple progmatic way to determine the magic offset in use, see:
855
+     * https://core.trac.wordpress.org/ticket/18273
856
+     *
857
+     * @since 2.8.1
858
+     * @link https://core.trac.wordpress.org/ticket/18273
859
+     * @link https://secure.php.net/manual/en/function.gzinflate.php#70875
860
+     * @link https://secure.php.net/manual/en/function.gzinflate.php#77336
861
+     *
862
+     * @param string $gzData String to decompress.
863
+     * @return string|bool False on failure.
864
+     */
865
+    public static function compatible_gzinflate($gzData) {
866
+        // Compressed data might contain a full zlib header, if so strip it for
867
+        // gzinflate()
868
+        if (substr($gzData, 0, 3) == "\x1f\x8b\x08") {
869
+            $i = 10;
870
+            $flg = ord(substr($gzData, 3, 1));
871
+            if ($flg > 0) {
872
+                if ($flg & 4) {
873
+                    list($xlen) = unpack('v', substr($gzData, $i, 2));
874
+                    $i = $i + 2 + $xlen;
875
+                }
876
+                if ($flg & 8) {
877
+                    $i = strpos($gzData, "\0", $i) + 1;
878
+                }
879
+                if ($flg & 16) {
880
+                    $i = strpos($gzData, "\0", $i) + 1;
881
+                }
882
+                if ($flg & 2) {
883
+                    $i = $i + 2;
884
+                }
885
+            }
886
+            $decompressed = self::compatible_gzinflate(substr($gzData, $i));
887
+            if (false !== $decompressed) {
888
+                return $decompressed;
889
+            }
890
+        }
891
+
892
+        // If the data is Huffman Encoded, we must first strip the leading 2
893
+        // byte Huffman marker for gzinflate()
894
+        // The response is Huffman coded by many compressors such as
895
+        // java.util.zip.Deflater, Ruby’s Zlib::Deflate, and .NET's
896
+        // System.IO.Compression.DeflateStream.
897
+        //
898
+        // See https://decompres.blogspot.com/ for a quick explanation of this
899
+        // data type
900
+        $huffman_encoded = false;
901
+
902
+        // low nibble of first byte should be 0x08
903
+        list(, $first_nibble)    = unpack('h', $gzData);
904
+
905
+        // First 2 bytes should be divisible by 0x1F
906
+        list(, $first_two_bytes) = unpack('n', $gzData);
907
+
908
+        if (0x08 == $first_nibble && 0 == ($first_two_bytes % 0x1F)) {
909
+            $huffman_encoded = true;
910
+        }
911
+
912
+        if ($huffman_encoded) {
913
+            if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) {
914
+                return $decompressed;
915
+            }
916
+        }
917
+
918
+        if ("\x50\x4b\x03\x04" == substr($gzData, 0, 4)) {
919
+            // ZIP file format header
920
+            // Offset 6: 2 bytes, General-purpose field
921
+            // Offset 26: 2 bytes, filename length
922
+            // Offset 28: 2 bytes, optional field length
923
+            // Offset 30: Filename field, followed by optional field, followed
924
+            // immediately by data
925
+            list(, $general_purpose_flag) = unpack('v', substr($gzData, 6, 2));
926
+
927
+            // If the file has been compressed on the fly, 0x08 bit is set of
928
+            // the general purpose field. We can use this to differentiate
929
+            // between a compressed document, and a ZIP file
930
+            $zip_compressed_on_the_fly = (0x08 == (0x08 & $general_purpose_flag));
931
+
932
+            if (!$zip_compressed_on_the_fly) {
933
+                // Don't attempt to decode a compressed zip file
934
+                return $gzData;
935
+            }
936
+
937
+            // Determine the first byte of data, based on the above ZIP header
938
+            // offsets:
939
+            $first_file_start = array_sum(unpack('v2', substr($gzData, 26, 4)));
940
+            if (false !== ($decompressed = @gzinflate(substr($gzData, 30 + $first_file_start)))) {
941
+                return $decompressed;
942
+            }
943
+            return false;
944
+        }
945
+
946
+        // Finally fall back to straight gzinflate
947
+        if (false !== ($decompressed = @gzinflate($gzData))) {
948
+            return $decompressed;
949
+        }
950
+
951
+        // Fallback for all above failing, not expected, but included for
952
+        // debugging and preventing regressions and to track stats
953
+        if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) {
954
+            return $decompressed;
955
+        }
956
+
957
+        return false;
958
+    }
959
+
960
+    public static function match_domain($host, $reference) {
961
+        // Check for a direct match
962
+        if ($host === $reference) {
963
+            return true;
964
+        }
965
+
966
+        // Calculate the valid wildcard match if the host is not an IP address
967
+        // Also validates that the host has 3 parts or more, as per Firefox's
968
+        // ruleset.
969
+        $parts = explode('.', $host);
970
+        if (ip2long($host) === false && count($parts) >= 3) {
971
+            $parts[0] = '*';
972
+            $wildcard = implode('.', $parts);
973
+            if ($wildcard === $reference) {
974
+                return true;
975
+            }
976
+        }
977
+
978
+        return false;
979
+    }
980 980
 }
Please login to merge, or discard this patch.
plugin/buycourses/src/Culqi/Planes.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -27,9 +27,9 @@
 block discarded – undo
27 27
     public function delete($id)
28 28
     {
29 29
 
30
-       return $this->request("DELETE", Planes::URL_PLANES . $id . "/", $api_key = $this->culqi->api_key);
30
+        return $this->request("DELETE", Planes::URL_PLANES . $id . "/", $api_key = $this->culqi->api_key);
31 31
 
32
-   }
32
+    }
33 33
 
34 34
 
35 35
 
Please login to merge, or discard this patch.
plugin/buycourses/src/Culqi/AuthBearer.php 1 patch
Indentation   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -4,17 +4,17 @@
 block discarded – undo
4 4
 
5 5
 class AuthBearer implements \Requests_Auth
6 6
 {
7
-	protected $password;
7
+    protected $password;
8 8
 
9
-	public function __construct($password) {
10
-		$this->password = $password;
11
-	}
9
+    public function __construct($password) {
10
+        $this->password = $password;
11
+    }
12 12
 
13
-	public function register(\Requests_Hooks &$hooks) {
14
-		$hooks->register('requests.before_request', array(&$this, 'before_request'));
15
-	}
13
+    public function register(\Requests_Hooks &$hooks) {
14
+        $hooks->register('requests.before_request', array(&$this, 'before_request'));
15
+    }
16 16
 
17
-	public function before_request(&$url, &$headers, &$data, &$type, &$options) {
18
-		$headers['Authorization: Bearer'] = $this->password;
19
-	}
17
+    public function before_request(&$url, &$headers, &$data, &$type, &$options) {
18
+        $headers['Authorization: Bearer'] = $this->password;
19
+    }
20 20
 }
Please login to merge, or discard this patch.