Http::parseBaseUrl()   C
last analyzed

Complexity

Conditions 14
Paths 24

Size

Total Lines 48
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 29
c 1
b 0
f 0
nc 24
nop 0
dl 0
loc 48
rs 6.2666

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php 
2
3
/**
4
 * Lenevor Framework
5
 *
6
 * LICENSE
7
 *
8
 * This source file is subject to the new BSD license that is bundled
9
 * with this package in the file license.md.
10
 * It is also available through the world-wide-web at this URL:
11
 * https://lenevor.com/license
12
 * If you did not receive a copy of the license and are unable to
13
 * obtain it through the world-wide-web, please send an email
14
 * to [email protected] so we can send you a copy immediately.
15
 *
16
 * @package     Lenevor
17
 * @subpackage  Base
18
 * @link        https://lenevor.com
19
 * @copyright   Copyright (c) 2019 - 2021 Alexander Campo <[email protected]>
20
 * @license     https://opensource.org/licenses/BSD-3-Clause New BSD license or see https://lenevor.com/license or see /license.md
21
 */
22
23
namespace Syscodes\Http;
24
25
use Syscodes\Collections\Arr;
26
27
/**
28
 * Returns the HTTP requests is filtered and detected in the routes set by the user.
29
 * 
30
 * @author Alexander Campo <[email protected]>
31
 */
32
class Http
33
{
34
	/**
35
	 * Return's the protocol that the request was made with.
36
	 *
37
	 * @return string
38
	 */
39
	public function protocol()
40
	{
41
		if ($this->server('HTTPS') == 'on' ||
42
			$this->server('HTTPS') == 1 ||
43
			$this->server('SERVER_PORT') == 443 ||
44
			(config('security.allow-x-headers', false) && $this->server('HTTP_X_FORWARDED_PROTO') == 'https') ||
45
			(config('security.allow-x-headers', false) && $this->server('HTTP_X_FORWARDED_PORT') == 443))
46
		{
47
			return 'https';
48
		}
49
50
		return 'http';
51
	}
52
53
	/**
54
	 * Fetch an item from the COOKIE array.
55
	 *
56
	 * @param  string  $index  The index key
57
	 * @param  mixed  $default  The default value
58
	 *
59
	 * @return string|array
60
	 */
61
	public function cookie($index = null, $default = null)
62
	{
63
		return (func_num_args() === 0) ? $_COOKIE : Arr::get($_COOKIE, strtoupper($index), $default);
0 ignored issues
show
Bug introduced by
It seems like $index can also be of type null; however, parameter $string of strtoupper() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
		return (func_num_args() === 0) ? $_COOKIE : Arr::get($_COOKIE, strtoupper(/** @scrutinizer ignore-type */ $index), $default);
Loading history...
64
	}
65
66
	/**
67
	 * Fetch an item from the FILE array.
68
	 *
69
	 * @param  string  $index  The index key
70
	 * @param  mixed  $default  The default value
71
	 *
72
	 * @return string|array
73
	 */
74
	public function file($index = null, $default = null)
75
	{
76
		return (func_num_args() === 0) ? $_FILES : Arr::get($_FILES, strtoupper($index), $default);
0 ignored issues
show
Bug introduced by
It seems like $index can also be of type null; however, parameter $string of strtoupper() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

76
		return (func_num_args() === 0) ? $_FILES : Arr::get($_FILES, strtoupper(/** @scrutinizer ignore-type */ $index), $default);
Loading history...
77
	}
78
79
	/**
80
	 * Fetch an item from the SERVER array.
81
	 *
82
	 * @param  string  $index  The index key
83
	 * @param  mixed  $default  The default value
84
	 *
85
	 * @return string|array
86
	 */
87
	public function server($index = null, $default = null)
88
	{
89
		return (func_num_args() === 0) ? $_SERVER : Arr::get($_SERVER, strtoupper($index), $default);
0 ignored issues
show
Bug introduced by
It seems like $index can also be of type null; however, parameter $string of strtoupper() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
		return (func_num_args() === 0) ? $_SERVER : Arr::get($_SERVER, strtoupper(/** @scrutinizer ignore-type */ $index), $default);
Loading history...
90
	}
91
	
92
	/**
93
	 * Gets the URI Protocol based setting, will attempt to detect the path 
94
	 * portion of the current URI.
95
	 * 
96
	 * @param  string  $protocol
97
	 * 
98
	 * @return string
99
	 */
100
	public function detectPath(string $protocol = '') 
101
	{
102
		if (empty($protocol)) {
103
			$protocol = 'REQUEST_URI';
104
		}
105
106
		switch($protocol) {
107
			case 'REQUEST_URI':
108
				$path = $this->parseRequestUri();
109
				break;
110
			case 'QUERY_STRING':
111
				$path = $this->parseQueryString();
112
				break;
113
			case 'PATH_INFO':
114
			default:
115
				$path = $this->server($protocol) ?? $this->parseRequestUri();
116
				break;
117
		}
118
119
		return $path;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $path also could return the type array which is incompatible with the documented return type string.
Loading history...
120
	}
121
122
	/**
123
	 * Filters a value from the start of a string in this case the passed URI string.
124
	 *
125
	 * @return string
126
	 */
127
	protected function parseRequestUri()
128
	{
129
		if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME'])) {
130
			return '';
131
		}
132
133
		$requestURI = $this->server('REQUEST_URI') ?? '/';
134
		$components = parse_url($requestURI);
0 ignored issues
show
Bug introduced by
It seems like $requestURI can also be of type array; however, parameter $url of parse_url() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
		$components = parse_url(/** @scrutinizer ignore-type */ $requestURI);
Loading history...
135
		$query      = $components['query'] ?? '';
136
		$uri        = $components['path'] ?? '';
137
138
		// If the search value is at the start
139
		if (isset($this->server('SCRIPT_NAME')[0])) {
140
			if (0 === strpos($uri, $this->server('SCRIPT_NAME'))) {
0 ignored issues
show
Bug introduced by
It seems like $this->server('SCRIPT_NAME') can also be of type array; however, parameter $needle of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
			if (0 === strpos($uri, /** @scrutinizer ignore-type */ $this->server('SCRIPT_NAME'))) {
Loading history...
141
				$uri = (string) substr($uri, strlen($this->server('SCRIPT_NAME')));
0 ignored issues
show
Bug introduced by
It seems like $this->server('SCRIPT_NAME') can also be of type array; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
				$uri = (string) substr($uri, strlen(/** @scrutinizer ignore-type */ $this->server('SCRIPT_NAME')));
Loading history...
142
			} elseif (0 < strpos($uri, $this->server('SCRIPT_NAME'))) {
143
				$uri = (string) substr($uri, strpos($uri, $this->server('SCRIPT_NAME')) + strlen($this->server('SCRIPT_NAME')));
144
			} elseif (0 === strpos($uri, dirname($this->server('SCRIPT_NAME')))) {
0 ignored issues
show
Bug introduced by
It seems like $this->server('SCRIPT_NAME') can also be of type array; however, parameter $path of dirname() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

144
			} elseif (0 === strpos($uri, dirname(/** @scrutinizer ignore-type */ $this->server('SCRIPT_NAME')))) {
Loading history...
145
				$uri = (string) substr($uri, strlen(dirname($this->server('SCRIPT_NAME'))));
146
			}
147
		}
148
149
		// This section ensures that even on servers that require the URI to contain 
150
		// the query string (Nginx) is the correctly
151
		if ('' === trim($uri, '/') && 0 === strncmp($query, '/', 1)) {
152
			$query					 = explode('?', $query, 2);
153
			$uri  					 = $query[0];
154
			$_SERVER['QUERY_STRING'] = $query[1] ?? '';
155
		} else {
156
			$_SERVER['QUERY_STRING'] = $query;
157
		}
158
159
		// Parses the string into variables
160
		parse_str($_SERVER['QUERY_STRING'], $_GET);
161
162
		if ('/' === $uri || '' === $uri) {
163
			return '';
164
		}
165
166
		return $this->filterDecode($uri);
167
	}
168
169
	/**
170
	 * Will parse QUERY_STRING and automatically detect the URI from it.
171
	 * 
172
	 * @return string
173
	 */
174
	protected function parseQueryString()
175
	{
176
		$uri = $_SERVER['QUERY_STRING'] ?? @getenv('QUERY_STRING');
177
178
		if (trim($uri, '/') === '') {
179
			return '';
180
		} elseif (0 === strncmp($uri, '/', 1)) {
181
			$uri    				 = explode('?', $uri, 2);
182
			$_SERVER['QUERY_STRING'] = $uri[1] ?? '';
183
			$uri    				 = $uri[0] ?? '';
184
		}
185
186
		parse_str($_SERVER['QUERY_STRING'], $_GET);
187
188
		return $this->filterDecode($uri);
189
	}
190
191
	/**
192
	 * Filters the uri string remove any malicious characters and inappropriate slashes.
193
	 *
194
	 * @param  string  $uri
195
	 *
196
	 * @return string
197
	 */
198
	protected function filterDecode($uri)
199
	{
200
		// Remove all characters except letters,
201
		// digits and $-_.+!*'(),{}|\\^~[]`<>#%";/?:@&=.
202
		$uri = filter_var(rawurldecode($uri), FILTER_SANITIZE_URL);
203
		
204
		// Return argument if not empty or return a single slash
205
		return trim($uri, '/') ?: '/';
206
	}
207
	
208
	/**
209
	 * Parse the base URL.
210
	 * 
211
	 * @return string
212
	 */
213
	public function parseBaseUrl() 
214
	{
215
		$filename = basename($this->server('SCRIPT_FILENAME'));
0 ignored issues
show
Bug introduced by
It seems like $this->server('SCRIPT_FILENAME') can also be of type array; however, parameter $path of basename() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

215
		$filename = basename(/** @scrutinizer ignore-type */ $this->server('SCRIPT_FILENAME'));
Loading history...
216
		
217
		if ($filename === basename($this->server('SCRIPT_NAME'))) {
218
			$baseUrl = $this->server('SCRIPT_NAME');
219
		} elseif ($filename === basename($this->server('PHP_SELF'))) {
220
			$baseUrl = $this->server('PHP_SELF');
221
		} elseif ($filename === basename($this->server('ORIG_SCRIPT_NAME'))) {
222
			$baseUrl = $this->server('ORIG_SCRIPT_NAME');
223
		} else {
224
			$path    = $this->server('PHP_SELF', '');
225
			$file    = $this->server('SCRIPT_FILENAME', '');
226
			$segs    = explode('/', trim($file, '/'));
0 ignored issues
show
Bug introduced by
It seems like $file can also be of type array; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

226
			$segs    = explode('/', trim(/** @scrutinizer ignore-type */ $file, '/'));
Loading history...
227
			$segs    = array_reverse($segs);
228
			$index   = 0;
229
			$last    = count($segs);
230
			$baseUrl = '';
231
			
232
			do 	{
233
				$seg     = $segs[$index];
234
				$baseUrl = '/'.$seg.$baseUrl;
235
				++$index;
236
			} while ($last > $index && (false !== $pos = strpos($path, $baseUrl)) && 0 != $pos);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type array; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

236
			} while ($last > $index && (false !== $pos = strpos(/** @scrutinizer ignore-type */ $path, $baseUrl)) && 0 != $pos);
Loading history...
237
		}
238
239
		// Does the baseUrl have anything in common with the request_uri?
240
		$requestUri = $this->parseRequestUri();
241
242
		if ('' !== $requestUri && '/' !== $requestUri[0]) {
243
			$requestUri = '/'.$requestUri;
244
		}
245
246
		$baseUrl = dirname($baseUrl);
0 ignored issues
show
Bug introduced by
It seems like $baseUrl can also be of type array; however, parameter $path of dirname() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

246
		$baseUrl = dirname(/** @scrutinizer ignore-type */ $baseUrl);
Loading history...
247
248
		if (empty($baseUrl) || false !== strpos(rawurldecode($requestUri), $baseUrl)) {
249
			// no match whatsoever; set it blank
250
			return '';
251
		}
252
		
253
		// If using mod_rewrite or ISAPI_Rewrite strip the script filename
254
		// out of baseUrl. $pos !== 0 makes sure it is not matching a value
255
		// from PATH_INFO or QUERY_STRING
256
		if (strlen($requestUri) >= strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && 0 !== $pos) {
257
			$baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
258
		}
259
		
260
		return rtrim($baseUrl, '/'.DIRECTORY_SEPARATOR);
261
	}
262
263
	/**
264
	 * Parse the path info.
265
	 * 
266
	 * @return string
267
	 */
268
	public function parsePathInfo()
269
	{
270
		if (null === ($requestUri = $this->parseRequestUri())) {
0 ignored issues
show
introduced by
The condition null === $requestUri = $this->parseRequestUri() is always false.
Loading history...
271
			return '/';
272
		}
273
274
		// Remove the query string from REQUEST_URI
275
		if (false !== $pos = strpos($requestUri, '?')) {
276
			$requestUri = substr($requestUri, 0, $pos);
277
		}
278
279
		if ('' !== $requestUri && '/' !== $requestUri[0]) {
280
			$requestUri = '/'.$requestUri;
281
		}
282
283
		if (null === ($baseUrl = $this->parseBaseUrl())) {
0 ignored issues
show
introduced by
The condition null === $baseUrl = $this->parseBaseUrl() is always false.
Loading history...
284
			return $requestUri;
285
		}
286
287
		$pathInfo = substr($requestUri, strlen($baseUrl));
288
289
		if (false === $pathInfo && '' === $pathInfo) {
290
			return '/';
291
		}
292
		
293
		return (string) $pathInfo;
294
	}
295
}