Passed
Push — master ( fcbd1b...c90017 )
by Spuds
01:07 queued 21s
created

Server::getFQDN()   C

Complexity

Conditions 12
Paths 7

Size

Total Lines 36
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 12
eloc 12
nc 7
nop 1
dl 0
loc 36
ccs 0
cts 0
cp 0
crap 156
rs 6.9666
c 1
b 0
f 1

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
 * This file has the functions "describing" the server.
5
 *
6
 * @name      ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
9
 *
10
 * This file contains code covered by:
11
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
12
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
13
 *
14
 * @version 1.1.7
15
 *
16
 */
17
18
/**
19
 * Class Server
20
 *
21
 * Wrapper around many common server functions and server information
22
 */
23
class Server extends \ArrayObject
24
{
25
	/**
26
	 * Server constructor.
27
	 *
28
	 * @param null|array $server
29
	 */
30
	public function __construct($server = null)
31
	{
32
		if (!is_array($server))
33
		{
34
			$server = isset($_SERVER) ? $_SERVER : array();
35
		}
36
37
		parent::__construct($server, ArrayObject::ARRAY_AS_PROPS);
38
	}
39
40
	/**
41
	 * Helper function to set the system memory to a needed value
42
	 *
43
	 * What it does:
44
	 *
45
	 * - If the needed memory is greater than current, will attempt to get more
46
	 * - If in_use is set to true, will also try to take the current memory usage in to account
47
	 *
48
	 * @param string $needed The amount of memory to request, if needed, like 256M
49
	 * @param bool $in_use Set to true to account for current memory usage of the script
50
	 *
51
	 * @return boolean true if we have at least the needed memory
52
	 */
53 1
	public function setMemoryLimit($needed, $in_use = false)
54
	{
55
		// Everything in bytes
56 1
		$memory_current = memoryReturnBytes(ini_get('memory_limit'));
57 1
		$memory_needed = memoryReturnBytes($needed);
58
59
		// Should we account for how much is currently being used?
60
		if ($in_use)
61 1
			$memory_needed += memory_get_usage();
62
63
		// If more is needed, request it
64 1
		if ($memory_current < $memory_needed)
65 1
		{
66
			@ini_set('memory_limit', ceil($memory_needed / 1048576) . 'M');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ini_set(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

66
			/** @scrutinizer ignore-unhandled */ @ini_set('memory_limit', ceil($memory_needed / 1048576) . 'M');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
67
			$memory_current = memoryReturnBytes(ini_get('memory_limit'));
68
		}
69
70 1
		$memory_current = max($memory_current, memoryReturnBytes(get_cfg_var('memory_limit')));
0 ignored issues
show
Bug introduced by
It seems like get_cfg_var('memory_limit') can also be of type array; however, parameter $val of memoryReturnBytes() 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

70
		$memory_current = max($memory_current, memoryReturnBytes(/** @scrutinizer ignore-type */ get_cfg_var('memory_limit')));
Loading history...
71
72
		// Return success or not
73 1
		return (bool) ($memory_current >= $memory_needed);
74
	}
75
76
	/**
77
	 * Wrapper function for set_time_limit
78
	 *
79
	 * When called, attempts to restart the timeout counter from zero.
80
	 *
81
	 * This sets the maximum time in seconds a script is allowed to run before it is terminated by the parser.
82
	 * You can not change this setting with ini_set() when running in safe mode.
83
	 * Your web server can have other timeout configurations that may also interrupt PHP execution.
84
	 * Apache has a Timeout directive and IIS has a CGI timeout function.
85
	 * Security extension may also disable this function, such as Suhosin
86
	 * Hosts may add this to the disabled_functions list in php.ini
87
	 *
88
	 * If the current time limit is not unlimited it is possible to decrease the
89
	 * total time limit if the sum of the new time limit and the current time spent
90
	 * running the script is inferior to the original time limit. It is inherent to
91
	 * the way set_time_limit() works, it should rather be called with an
92
	 * appropriate value every time you need to allocate a certain amount of time
93
	 * to execute a task than only once at the beginning of the script.
94
	 *
95
	 * Before calling set_time_limit(), we check if this function is available
96
	 *
97
	 * @param int $time_limit The time limit
98
	 * @param bool $server_reset whether to reset the server timer or not
99
	 */
100 6
	public function setTimeLimit($time_limit, $server_reset = true)
101
	{
102
		// Make sure the function exists, it may be in the ini disable_functions list
103 6
		if (function_exists('set_time_limit'))
104 6
		{
105 6
			$current = (int) ini_get('max_execution_time');
106
107
			// Do not set a limit if it is currently unlimited.
108 6
			if ($current !== 0)
109 6
			{
110
				// Set it to the maximum that we can, not more, not less
111
				$time_limit = min($current, max($time_limit, $current));
112
113
				// Still need error suppression as some security addons many prevent this action
114
				@set_time_limit($time_limit);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_time_limit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

114
				/** @scrutinizer ignore-unhandled */ @set_time_limit($time_limit);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
115
			}
116 6
		}
117
118
		// Don't let apache close the connection
119 6
		if ($server_reset && function_exists('apache_reset_timeout'))
120 6
			@apache_reset_timeout();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for apache_reset_timeout(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

120
			/** @scrutinizer ignore-unhandled */ @apache_reset_timeout();

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
121
122 6
		return ini_get('max_execution_time');
123
	}
124
125
	/**
126
	 * Checks the type of software the webserver is functioning under
127
	 *
128
	 * @param $server
129
	 *
130
	 * @return bool
131
	 */
132 7
	public function is($server)
133
	{
134
		switch ($server)
135
		{
136 7
			case 'apache':
137
				return $this->_is_web_server('Apache');
138 7
			case 'cgi':
139
				return isset($this->SERVER_SOFTWARE) && strpos(php_sapi_name(), 'cgi') !== false;
140 7
			case 'iis':
141
				return $this->_is_web_server('Microsoft-IIS');
142 7
			case 'iso_case_folding':
143 7
				return ord(strtolower(chr(138))) === 154;
144 1
			case 'lighttpd':
145
				return $this->_is_web_server('lighttpd');
146 1
			case 'litespeed':
147
				return $this->_is_web_server('LiteSpeed');
148 1
			case 'needs_login_fix':
149
				return $this->is('cgi') && $this->_is_web_server('Microsoft-IIS');
150 1
			case 'nginx':
151
				return $this->_is_web_server('nginx');
152 1
			case 'windows':
153 1
				return strpos(PHP_OS, 'WIN') === 0;
154
			default:
155
				return false;
156
		}
157
	}
158
159
	/**
160
	 * Search $_SERVER['SERVER_SOFTWARE'] for a give $type
161
	 *
162
	 * @param string $type
163
	 *
164
	 * @return bool
165
	 */
166
	private function _is_web_server($type)
167
	{
168
		return isset($this->SERVER_SOFTWARE) && strpos($this->SERVER_SOFTWARE, $type) !== false;
169
	}
170
171
	/**
172
	 * Checks if the webserver supports rewrite
173
	 *
174
	 * @return bool
175
	 */
176
	public function supportRewrite()
177
	{
178
		return (!$this->is('cgi') || ini_get('cgi.fix_pathinfo') == 1 || @get_cfg_var('cgi.fix_pathinfo') == 1)
179
			&& ($this->is('apache') || $this->is('nginx') || $this->is('lighttpd') || $this->is('litespeed'));
180
	}
181
182
	/**
183
	 * Returns if the system supports output compression
184
	 *
185
	 * @return bool
186
	 */
187
	public function outPutCompressionEnabled()
188
	{
189
		return ini_get('zlib.output_compression') >= 1 || ini_get('output_handler') == 'ob_gzhandler';
190
	}
191
192
	/**
193
	 * Returns if the system supports / is using https connections
194
	 *
195
	 * @return bool
196
	 */
197
	public function supportsSSL()
198
	{
199
		return
200
			(isset($this->HTTPS) && ($this->HTTPS === 'on' || $this->HTTPS == 1))
201
			|| (isset($this->REQUEST_SCHEME) && $this->REQUEST_SCHEME === 'https')
202
			|| (isset($this->SERVER_PORT) && $this->SERVER_PORT == 443)
203
			|| (isset($this->HTTP_X_FORWARDED_PROTO) && $this->HTTP_X_FORWARDED_PROTO === 'https');
204
	}
205
206
	/**
207
	 * Try to determine a FQDN for the server
208
	 *
209
	 * Many SMTP servers *require* a fully qualified domain name in the
210
	 * HELO/EHLO command.  This function tries to determine the fully qualified domain name
211
	 * from the OS which often just returns the current host name, like bob, rather than a FQDN.
212
	 *
213
	 * From the rfc:
214
	 * The SMTP client MUST, if possible, ensure that the domain parameter to the EHLO
215
	 * command is a valid principal host name (not a CNAME or MX name) for its host. If
216
	 * this is not possible (e.g., when the client's address is dynamically assigned and
217
	 * the client does not have an obvious name), an address literal SHOULD be substituted
218
	 * for the domain name and supplemental information provided that will assist in
219
	 * identifying the client.
220
	 *
221
	 * @param string $fallback the fallback to use when we fail
222
	 * @return string a FQDN
223
	 */
224
	public function getFQDN($fallback = '[127.0.0.1]')
225
	{
226
		// Try gethostname
227
		if (function_exists('gethostname') && $this->_isValidFQDN(gethostname()))
228
		{
229
			return gethostname();
230
		}
231
232
		// Failing, try php_uname
233
		if (function_exists('php_uname') && $this->_isValidFQDN(php_uname('n')))
234
		{
235
			return php_uname('n');
236
		}
237
238
		// This is likely a sitename vs host
239
		if (!empty($_SERVER['SERVER_NAME']) && $this->_isValidFQDN($_SERVER['SERVER_NAME']))
240
		{
241
			return $_SERVER['SERVER_NAME'];
242
		}
243
244
		// Try a reverse IP lookup on the server addr
245
		if (!empty($_SERVER['SERVER_ADDR']) && $this->_isValidFQDN((host_from_ip($_SERVER['SERVER_ADDR']))))
246
		{
247
			return host_from_ip($_SERVER['SERVER_ADDR']);
248
		}
249
250
		// Literal it is, but some SMTP servers may not accept this
251
		if (!empty($_SERVER['SERVER_ADDR']) && $fallback === '[127.0.0.1]')
252
		{
253
			// Set the address literal prefix
254
			$prefix = strpos($_SERVER['SERVER_ADDR'], ':' !== false) ? 'IPv6:' : '';
0 ignored issues
show
Bug introduced by
':' !== false of type boolean is incompatible with the type string expected by parameter $needle of strpos(). ( Ignorable by Annotation )

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

254
			$prefix = strpos($_SERVER['SERVER_ADDR'], /** @scrutinizer ignore-type */ ':' !== false) ? 'IPv6:' : '';
Loading history...
255
256
			return  '[' . $prefix . $_SERVER['SERVER_ADDR'] . ']';
257
		}
258
259
		return $fallback;
260
	}
261
262
	/**
263
	 * Checks if this is a valid FQDN first by basic syntax and then if it has domain records
264
	 *
265
	 * @param string $hostname
266
	 * @return bool
267
	 */
268
	private function _isValidFQDN($hostname)
269
	{
270
		if (empty($hostname) || strpos($hostname, '.') === false)
271
		{
272
			return false;
273
		}
274
275
		if (preg_match('~^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}$~', $hostname) === 1)
276
		{
277
			// Check for ANY dns records for this name for simplicity although we really want A / AAAA
278
			return checkdnsrr($hostname, 'ANY');
279
		}
280
281
		return false;
282
	}
283
}
284