Passed
Pull Request — developer (#16008)
by Arkadiusz
21:29
created

ConfReport::validateHeaderServer()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
dl 0
loc 20
ccs 0
cts 5
cp 0
rs 8.8333
c 1
b 0
f 0
cc 7
nc 9
nop 3
crap 56
1
<?php
2
3
/**
4
 * Conf report class.
5
 *
6
 * @package App
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
10
 * @author    Mariusz Krzaczkowski <[email protected]>
11
 * @author    Radosław Skrzypczak <[email protected]>
12
 */
13
14
namespace App\Utils;
15
16
/**
17
 * Conf report.
18
 */
19
class ConfReport
20
{
21
	/** @var string System URL. */
22
	private static $crmUrl;
23
24
	/** @var string System URL. */
25
	public static $testCli = false;
26
27
	/** @var array Optional database configuration for offline use. */
28
	public static $dbConfig = [
29
		'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=yetiforce;',
30
		'user' => '',
31
		'password' => '',
32
		'options' => [],
33
	];
34
35
	/** @var array Urls to check in request. */
36
	public static $urlsToCheck = ['root' => 'token.php', 'js' => 'layouts/resources/Tools.js', 'css' => 'layouts/resources/fonts/fonts.css'];
37
38
	/**
39
	 * List all variables.
40
	 *
41
	 * @var string[]
42
	 */
43
	public static $types = ['stability', 'security', 'libraries', 'database', 'performance', 'environment', 'writableFilesAndFolders', 'functionalVerification', 'headers', 'publicDirectoryAccess', 'pathVerification'];
44
45
	/**
46
	 * List all container.
47
	 *
48
	 * @var string[]
49
	 */
50
	public static $container = ['php', 'env', 'ext', 'request', 'db', 'writableFilesAndFolders'];
51
52
	/**
53
	 * Stability variables map.
54
	 *
55
	 * @var array
56
	 */
57
	public static $stability = [
58
		'phpVersion' => ['recommended' => '7.4.x, 7.4.x, 8.0.x, 8.1.x (dev)', 'type' => 'Version', 'container' => 'env', 'testCli' => true, 'label' => 'PHP'],
59
		'protocolVersion' => ['recommended' => '2.0, 1.x', 'type' => 'Version', 'container' => 'env', 'testCli' => false, 'label' => 'PROTOCOL_VERSION'],
60
		'error_reporting' => ['recommended' => 'E_ALL & ~E_NOTICE', 'type' => 'ErrorReporting', 'container' => 'php', 'testCli' => true],
61
		'output_buffering' => ['recommended' => 'On', 'type' => 'OnOffInt', 'container' => 'php', 'testCli' => true],
62
		'max_execution_time' => ['recommended' => 600, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
63
		'max_input_time' => ['recommended' => 600, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
64
		'default_socket_timeout' => ['recommended' => 600, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
65
		'memory_limit' => ['recommended' => '1 GB', 'type' => 'GreaterMb', 'container' => 'php', 'testCli' => true],
66
		'log_errors' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
67
		'file_uploads' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
68
		'short_open_tag' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
69
		'post_max_size' => ['recommended' => '50 MB', 'type' => 'GreaterMb', 'container' => 'php', 'testCli' => true],
70
		'upload_max_filesize' => ['recommended' => '100 MB', 'type' => 'GreaterMb', 'container' => 'php', 'testCli' => true],
71
		'max_input_vars' => ['recommended' => 10000, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
72
		'zlib.output_compression' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
73
		'session.auto_start' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
74
		'session.gc_maxlifetime' => ['recommended' => 1440, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
75
		'session.gc_divisor' => ['recommended' => 500, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
76
		'session.gc_probability' => ['recommended' => 1, 'type' => 'Equal', 'container' => 'php', 'testCli' => true],
77
		'mbstring.func_overload' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true], //Roundcube
78
		'date.timezone' => ['type' => 'TimeZone', 'container' => 'php', 'testCli' => true], //Roundcube
79
		'allow_url_fopen' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true], //Roundcube
80
		'auto_detect_line_endings' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true], //CSVReader
81
		'httpMethods' => ['recommended' => 'GET, POST, PUT, OPTIONS, PATCH, PROPFIND, REPORT, LOCK, DELETE, COPY, MOVE', 'type' => 'HttpMethods', 'container' => 'request', 'testCli' => true, 'label' => 'HTTP_METHODS'],
82
		'request_order' => ['recommended' => 'GP', 'type' => 'Equal', 'container' => 'php', 'testCli' => true],
83
		'variables_order' => ['recommended' => 'GPCS', 'type' => 'Equal', 'container' => 'php', 'testCli' => true],
84
		'opcache.jit' => ['container' => 'php', 'testCli' => true],
85
		'opcache.jit_buffer_size' => ['container' => 'php', 'testCli' => true],
86
		'mysqli.allow_persistent' => ['container' => 'php', 'testCli' => true],
87
		'mysqli.max_persistent' => ['container' => 'php', 'testCli' => true],
88
	];
89
	/**
90
	 * Security variables map.
91
	 *
92
	 * @var array
93
	 */
94
	public static $security = [
95
		'HTTPS' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'env', 'testCli' => false],
96
		'public_html' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'env', 'testCli' => false],
97
		'display_errors' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'demoMode' => true, 'testCli' => true],
98
		'session.use_strict_mode' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
99
		'session.use_trans_sid' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
100
		'session.cookie_httponly' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => false],
101
		'session.use_only_cookies' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => false],
102
		'session.cookie_secure' => ['recommended' => '', 'type' => 'CookieSecure', 'container' => 'php', 'testCli' => false],
103
		'session.cookie_samesite' => ['recommended' => '', 'type' => 'CookieSamesite', 'container' => 'php', 'testCli' => false],
104
		'session.name' => ['recommended' => 'YTSID', 'container' => 'php', 'type' => 'Equal', 'testCli' => false],
105
		'expose_php' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
106
		'session_regenerate_id' => ['recommended' => 'On', 'type' => 'SessionRegenerate', 'testCli' => true],
107
		'disable_functions' => ['recommended' => 'shell_exec, exec, system, passthru, popen', 'type' => 'In', 'container' => 'php', 'testCli' => false],
108
		'allow_url_include' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
109
	];
110
111
	/**
112
	 * Headers variables map.
113
	 *
114
	 * @var array
115
	 */
116
	public static $headers = [
117
		'Header: server' => ['recommended' => '', 'type' => 'HeaderServer', 'container' => 'request', 'testCli' => false],
118
		'Header: x-powered-by' => ['recommended' => '', 'type' => 'Header', 'contaiuse_only_cookiesner' => 'request', 'testCli' => false],
119
		'Header: access-control-allow-methods' => ['recommended' => 'GET, POST', 'type' => 'Header', 'container' => 'request', 'testCli' => false, 'onlyPhp' => true],
120
		'Header: access-control-allow-origin' => ['recommended' => '*', 'type' => 'Header', 'container' => 'request', 'testCli' => false, 'onlyPhp' => true],
121
		'Header: referrer-policy' => ['recommended' => 'no-referrer', 'type' => 'Header', 'container' => 'request', 'testCli' => false],
122
		'Header: expect-ct' => ['recommended' => 'enforce; max-age=3600', 'type' => 'Header', 'container' => 'request', 'testCli' => false],
123
		'Header: x-frame-options' => ['recommended' => 'sameorigin', 'type' => 'Header', 'container' => 'request', 'testCli' => false],
124
		'Header: x-xss-protection' => ['recommended' => '1; mode=block', 'type' => 'Header', 'container' => 'request', 'testCli' => false],
125
		'Header: x-content-type-options' => ['recommended' => 'nosniff', 'type' => 'Header', 'container' => 'request', 'testCli' => false],
126
		'Header: x-robots-tag' => ['recommended' => 'none', 'type' => 'Header', 'container' => 'request', 'testCli' => false],
127
		'Header: x-permitted-cross-domain-policies' => ['recommended' => 'none', 'type' => 'Header', 'container' => 'request', 'testCli' => false],
128
		'Header: strict-transport-security' => ['recommended' => 'max-age=31536000; includeSubDomains; preload', 'type' => 'Header', 'container' => 'request', 'testCli' => false, 'httpsRequired' => true],
129
		'Header: content-security-policy' => ['recommended' => '', 'type' => 'HeaderCsp', 'container' => 'request', 'testCli' => false],
130
	];
131
132
	/**
133
	 * Libraries map.
134
	 *
135
	 * @var array
136
	 */
137
	public static $libraries = [
138
		'imap' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'imap', 'container' => 'ext', 'testCli' => true],
139
		'PDO' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'PDO', 'container' => 'ext', 'testCli' => true],
140
		'pdo_mysql' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'pdo_mysql', 'container' => 'ext', 'testCli' => true],
141
		'mysqlnd' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'mysqlnd', 'container' => 'ext', 'testCli' => true],
142
		'openssl' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'openssl', 'container' => 'ext', 'testCli' => true],
143
		'curl' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'curl', 'container' => 'ext', 'testCli' => true],
144
		'gd' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'gd', 'container' => 'ext', 'testCli' => true],
145
		'pcre' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'pcre', 'container' => 'ext', 'testCli' => true],
146
		'xml' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'xml', 'container' => 'ext', 'testCli' => true],
147
		'json' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'json', 'container' => 'ext', 'testCli' => true],
148
		'session' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'session', 'container' => 'ext', 'testCli' => true],
149
		'dom' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'dom', 'container' => 'ext', 'testCli' => true],
150
		'zip' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'zip', 'container' => 'ext', 'testCli' => true],
151
		'mbstring' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'mbstring', 'container' => 'ext', 'testCli' => true],
152
		'soap' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'soap', 'container' => 'ext', 'testCli' => true],
153
		'fileinfo' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'fileinfo', 'container' => 'ext', 'testCli' => true],
154
		'iconv' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'iconv', 'container' => 'ext', 'testCli' => true],
155
		'intl' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'intl', 'container' => 'ext', 'testCli' => true],
156
		'SPL' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'SPL', 'container' => 'ext', 'testCli' => true],
157
		'Reflection' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'Reflection', 'container' => 'ext', 'testCli' => true],
158
		'SimpleXML' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'SimpleXML', 'container' => 'ext', 'testCli' => true],
159
		'bcmath' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'bcmath', 'container' => 'ext', 'testCli' => true],
160
		'filter' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'filter', 'container' => 'ext', 'testCli' => true],
161
		'ctype' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'ctype', 'container' => 'ext', 'testCli' => true],
162
		'hash' => ['mandatory' => true, 'type' => 'ExtExist', 'extName' => 'hash', 'container' => 'ext', 'testCli' => true],
163
		'exif' => ['mandatory' => false, 'type' => 'ExtExist', 'extName' => 'exif', 'container' => 'ext', 'testCli' => true, 'mode' => 'showWarnings'],
164
		'ldap' => ['mandatory' => false, 'type' => 'ExtExist', 'extName' => 'ldap', 'container' => 'ext', 'testCli' => true, 'mode' => 'showWarnings'],
165
		'OPcache' => ['mandatory' => false, 'type' => 'ExtExist', 'extName' => 'Zend OPcache', 'container' => 'ext', 'testCli' => true, 'mode' => 'showWarnings'],
166
		'apcu' => ['mandatory' => false, 'type' => 'ExtExist', 'extName' => 'apcu', 'container' => 'ext', 'testCli' => true, 'mode' => 'showWarnings'],
167
		'imagick' => ['mandatory' => false, 'type' => 'ExtExist', 'extName' => 'imagick', 'container' => 'ext', 'testCli' => true, 'mode' => 'showWarnings'],
168
		'allExt' => ['container' => 'ext', 'type' => 'AllExt', 'testCli' => true, 'label' => 'EXTENSIONS'],
169
	];
170
171
	/**
172
	 * Database map.
173
	 *
174
	 * @var array
175
	 */
176
	public static $database = [
177
		'driver' => ['recommended' => 'mysql', 'type' => 'Equal', 'container' => 'db', 'testCli' => true, 'label' => 'DB_DRIVER'],
178
		'typeDb' => ['container' => 'db', 'testCli' => true, 'label' => 'DB_VERSION_TYPE'],
179
		'serverVersion' => ['recommended' => ['MariaDb' => '10.x', 'MySQL' => '5.6.x'], 'type' => 'VersionDb', 'container' => 'db', 'testCli' => true, 'label' => 'DB_SERVER_VERSION'],
180
		'clientVersion' => ['container' => 'db', 'testCli' => true, 'label' => 'DB_CLIENT_VERSION'],
181
		'version_comment' => ['container' => 'db', 'testCli' => true, 'label' => 'DB_VERSION_COMMENT'],
182
		'connectionStatus' => ['container' => 'db', 'testCli' => true, 'label' => 'DB_CONNECTION_STATUS'],
183
		'serverInfo' => ['container' => 'db', 'testCli' => true, 'label' => 'DB_SERVER_INFO'],
184
		'maximumMemorySize' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true, 'label' => 'DB_MAXIMUM_MEMORY_SIZE', 'showHelp' => true],
185
		'key_buffer_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
186
		'have_query_cache' => ['container' => 'db', 'testCli' => true],
187
		'query_cache_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
188
		'query_cache_type' => ['container' => 'db', 'testCli' => true],
189
		'table_cache' => ['container' => 'db', 'testCli' => true],
190
		'table_open_cache_instances' => ['container' => 'db', 'testCli' => true],
191
		'table_open_cache' => ['recommended' => 1000, 'type' => 'Greater', 'container' => 'db', 'testCli' => true, 'mode' => 'showWarnings'],
192
		'table_definition_cache' => ['type' => 'DbTableDefinitionCache', 'container' => 'db', 'testCli' => true, 'mode' => 'showWarnings'],
193
		'open_files_limit' => ['container' => 'db', 'testCli' => true],
194
		'tmp_table_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
195
		'innodb_buffer_pool_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
196
		'innodb_additional_mem_pool_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
197
		'innodb_log_buffer_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
198
		'max_connections' => ['container' => 'db', 'testCli' => true],
199
		'sort_buffer_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
200
		'myisam_sort_buffer_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
201
		'read_buffer_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
202
		'read_rnd_buffer_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
203
		'join_buffer_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
204
		'thread_stack' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
205
		'binlog_cache_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
206
		'bulk_insert_buffer_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
207
		'max_heap_table_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
208
		'innodb_log_file_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
209
		'innodb_lock_wait_timeout' => ['recommended' => 600, 'type' => 'Greater', 'container' => 'db', 'testCli' => true],
210
		'wait_timeout' => ['recommended' => 600, 'type' => 'Greater', 'container' => 'db', 'testCli' => true],
211
		'interactive_timeout' => ['recommended' => 600, 'type' => 'Greater', 'container' => 'db', 'testCli' => true],
212
		'sql_mode' => ['recommended' => '', 'type' => 'NotIn', 'container' => 'db', 'testCli' => true, 'exclusions' => ['STRICT_ALL_TABLES', 'STRICT_TRANS_TABLE']],
213
		'max_allowed_packet' => ['recommended' => '10 MB', 'type' => 'GreaterMb', 'container' => 'db', 'testCli' => true],
214
		'thread_cache_size' => ['container' => 'db', 'testCli' => true],
215
		'tx_isolation' => ['container' => 'db', 'testCli' => true],
216
		'transaction_isolation' => ['container' => 'db', 'testCli' => true],
217
		'ft_min_word_len' => ['container' => 'db', 'testCli' => true],
218
		'innodb_ft_min_token_size' => ['container' => 'db', 'testCli' => true],
219
		'innodb_default_row_format' => ['recommended' => 'dynamic', 'type' => 'Equal', 'container' => 'db', 'testCli' => true],
220
		'innodb_strict_mode' => ['container' => 'db', 'testCli' => true],
221
		'innodb_large_prefix' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'db', 'testCli' => true],
222
		'innodb_file_per_table' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'db', 'testCli' => true],
223
		'innodb_stats_on_metadata' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'db', 'testCli' => true],
224
		'innodb_buffer_pool_instances' => ['container' => 'db', 'testCli' => true],
225
		'innodb_buffer_pool_load_at_startup' => ['container' => 'db', 'testCli' => true],
226
		'innodb_io_capacity' => ['container' => 'db', 'testCli' => true],
227
		'innodb_io_capacity_max' => ['container' => 'db', 'testCli' => true],
228
		'innodb_file_format' => ['container' => 'db', 'testCli' => true],
229
		'innodb_file_format_check' => ['container' => 'db', 'testCli' => true],
230
		'innodb_file_format_max' => ['container' => 'db', 'testCli' => true],
231
		'character_set_server' => ['recommended' => 'utf8', 'values' => ['utf8', 'utf8mb3', 'utf8mb4'], 'type' => 'OneOf', 'container' => 'db', 'testCli' => true],
232
		'character_set_database' => ['recommended' => 'utf8', 'values' => ['utf8', 'utf8mb3', 'utf8mb4'], 'type' => 'OneOf', 'container' => 'db', 'testCli' => true],
233
		'character_set_client' => ['recommended' => 'utf8', 'values' => ['utf8', 'utf8mb3', 'utf8mb4'], 'type' => 'OneOf', 'container' => 'db', 'testCli' => true],
234
		'character_set_connection' => ['recommended' => 'utf8', 'values' => ['utf8', 'utf8mb3', 'utf8mb4'], 'type' => 'OneOf', 'container' => 'db', 'testCli' => true],
235
		'character_set_results' => ['recommended' => 'utf8', 'values' => ['utf8', 'utf8mb3', 'utf8mb4'], 'type' => 'OneOf', 'container' => 'db', 'testCli' => true],
236
		'character_set_system' => ['container' => 'db', 'testCli' => true],
237
		'character_set_filesystem' => ['container' => 'db', 'testCli' => true],
238
		'datadir' => ['container' => 'db', 'testCli' => true],
239
		'connect_timeout' => ['container' => 'db', 'testCli' => true],
240
		'lock_wait_timeout' => ['container' => 'db', 'testCli' => true],
241
		'net_read_timeout' => ['container' => 'db', 'testCli' => true],
242
		'net_write_timeout' => ['container' => 'db', 'testCli' => true],
243
		'aria_recover_options' => ['container' => 'db', 'testCli' => true],
244
		'aria_recover' => ['container' => 'db', 'testCli' => true],
245
		'hostname' => ['container' => 'db', 'testCli' => true],
246
		'innodb_checksum_algorithm' => ['container' => 'db', 'testCli' => true],
247
		'innodb_flush_method' => ['container' => 'db', 'testCli' => true],
248
		'innodb_thread_sleep_delay' => ['container' => 'db', 'testCli' => true],
249
		'innodb_thread_concurrency' => ['container' => 'db', 'testCli' => true],
250
		'innodb_adaptive_max_sleep_delay' => ['container' => 'db', 'testCli' => true],
251
		'innodb_read_ahead_threshold' => ['container' => 'db', 'testCli' => true],
252
		'innodb_max_dirty_pages_pct_lwm' => ['container' => 'db', 'testCli' => true],
253
		'innodb_open_files' => ['container' => 'db', 'testCli' => true],
254
		'thread_pool_max_threads' => ['container' => 'db', 'testCli' => true],
255
		'innodb_read_io_threads' => ['container' => 'db', 'testCli' => true],
256
		'innodb_write_io_threads' => ['container' => 'db', 'testCli' => true],
257
		'lower_case_file_system' => ['container' => 'db', 'testCli' => true],
258
		'lower_case_table_names' => ['container' => 'db', 'testCli' => true],
259
		'system_time_zone' => ['container' => 'db', 'testCli' => true],
260
		'use_stat_tables' => ['container' => 'db', 'testCli' => true],
261
		'thread_handling' => ['container' => 'db', 'testCli' => true],
262
		'host_cache_size' => ['container' => 'db', 'testCli' => true],
263
		'optimizer_search_depth' => ['container' => 'db', 'testCli' => true],
264
		'version_compile_machine' => ['container' => 'db', 'testCli' => true],
265
		'version_compile_os' => ['container' => 'db', 'testCli' => true],
266
		'socket' => ['container' => 'db', 'testCli' => true],
267
		'back_log' => ['container' => 'db', 'testCli' => true],
268
		'log_bin' => ['container' => 'db', 'testCli' => true],
269
		'log_bin_basename' => ['container' => 'db', 'testCli' => true],
270
		'log_slave_updates' => ['container' => 'db', 'testCli' => true],
271
		'binlog_format' => ['container' => 'db', 'testCli' => true],
272
		'max_binlog_size' => ['container' => 'db', 'type' => 'ShowBytes', 'testCli' => true],
273
		'slow_query_log' => ['container' => 'db', 'testCli' => true],
274
		'slow_query_log_file' => ['container' => 'db', 'testCli' => true],
275
		'log_slow_admin_statements' => ['container' => 'db', 'testCli' => true],
276
		'general_log' => ['container' => 'db', 'testCli' => true],
277
		'general_log_file' => ['container' => 'db', 'testCli' => true],
278
		'log_error' => ['container' => 'db', 'testCli' => true],
279
		'log_warnings' => ['container' => 'db', 'testCli' => true],
280
		'log_output' => ['container' => 'db', 'testCli' => true],
281
	];
282
283
	/**
284
	 * Performance map.
285
	 *
286
	 * @var array
287
	 */
288
	public static $performance = [
289
		'xdebug' => ['recommended' => 'Off', 'type' => 'ExtNotExist', 'extName' => 'xdebug', 'container' => 'ext', 'testCli' => true],
290
		'opcache.enable' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
291
		'opcache.enable_cli' => ['recommended' => 'On', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
292
		'opcache.max_accelerated_files' => ['recommended' => 40000, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
293
		'opcache.interned_strings_buffer' => ['recommended' => 100, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
294
		'opcache.validate_timestamps' => ['recommended' => 1, 'type' => 'Equal', 'container' => 'php', 'testCli' => true],
295
		'opcache.revalidate_freq' => ['recommended' => 0, 'type' => 'Equal', 'container' => 'php', 'testCli' => true],
296
		'opcache.save_comments' => ['recommended' => 0, 'type' => 'Equal', 'container' => 'php', 'testCli' => true],
297
		'opcache.file_update_protection' => ['recommended' => 0, 'type' => 'Equal', 'container' => 'php', 'testCli' => true],
298
		'opcache.memory_consumption' => ['container' => 'php', 'testCli' => true],
299
		'realpath_cache_size' => ['recommended' => '256k', 'type' => 'GreaterMb', 'container' => 'php', 'testCli' => true],
300
		'realpath_cache_ttl' => ['recommended' => 600, 'type' => 'Greater', 'container' => 'php', 'testCli' => true],
301
		'mysqlnd.collect_statistics' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
302
		'mysqlnd.collect_memory_statistics' => ['recommended' => 'Off', 'type' => 'OnOff', 'container' => 'php', 'testCli' => true],
303
		'apc.enabled' => ['container' => 'php', 'testCli' => true],
304
		'apc.enable_cli' => ['container' => 'php', 'testCli' => true],
305
		'apc.preload_path' => ['container' => 'php', 'testCli' => true],
306
		'apc.ttl' => ['container' => 'php', 'testCli' => true],
307
		'apc.user_ttl' => ['container' => 'php', 'testCli' => true],
308
		'apc.num_files_hint' => ['container' => 'php', 'testCli' => true],
309
		'apc.stat' => ['container' => 'php', 'testCli' => true],
310
		'apc.optimization' => ['container' => 'php', 'testCli' => true],
311
		'apc.cache_by_default' => ['container' => 'php', 'testCli' => true],
312
		'apc.mmap_file_mask' => ['container' => 'php', 'testCli' => true],
313
		'apc.shm_segments' => ['container' => 'php', 'testCli' => true],
314
	];
315
316
	/**
317
	 * Environment map.
318
	 *
319
	 * @var array
320
	 */
321
	public static $environment = [
322
		'crmVersion' => ['container' => 'env', 'testCli' => false, 'label' => 'CRM_VERSION'],
323
		'crmDate' => ['container' => 'env', 'testCli' => false, 'label' => 'CRM_DATE'],
324
		'companySize' => ['container' => 'env', 'testCli' => false, 'label' => 'COMPANY_SIZE'],
325
		'operatingSystem' => ['container' => 'env', 'testCli' => true, 'label' => 'OPERATING_SYSTEM'],
326
		'serverSoftware' => ['container' => 'env', 'testCli' => false, 'label' => 'SERVER_SOFTWARE'],
327
		'currentUser' => ['container' => 'env', 'type' => 'CronEqual', 'testCli' => true, 'label' => 'SCRIPT_USER'],
328
		'tempDir' => ['container' => 'env', 'testCli' => true, 'label' => 'TMP_DIR'],
329
		'crmDir' => ['container' => 'env', 'testCli' => false, 'label' => 'CRM_DIR'],
330
		'sapi' => ['container' => 'env', 'testCli' => true, 'label' => 'PHP_SAPI'],
331
		'zendVersion' => ['container' => 'env', 'testCli' => true, 'label' => 'ZEND_VERSION'],
332
		'locale' => ['container' => 'env', 'testCli' => true, 'label' => 'LOCALE'],
333
		'error_log' => ['type' => 'ErrorLog', 'container' => 'php', 'testCli' => true, 'label' => 'LOG_FILE'],
334
		'phpIni' => ['container' => 'env', 'testCli' => true, 'label' => 'PHPINI'],
335
		'phpIniAll' => ['container' => 'env', 'testCli' => true, 'label' => 'PHPINIS'],
336
		'spaceRoot' => ['container' => 'env', 'type' => 'Space', 'testCli' => false, 'label' => 'SPACE_ROOT'],
337
		'spaceStorage' => ['container' => 'env', 'type' => 'Space', 'testCli' => false, 'label' => 'SPACE_STORAGE'],
338
		'spaceTemp' => ['container' => 'env', 'type' => 'Space', 'testCli' => false, 'label' => 'SPACE_TEMP'],
339
		'spaceBackup' => ['container' => 'env', 'type' => 'Space', 'testCli' => false, 'label' => 'SPACE_BACKUP'],
340
		'lastCronStart' => ['container' => 'env', 'testCli' => false, 'label' => 'LAST_CRON_START', 'isHtml' => true],
341
		'crmProvider' => ['container' => 'env', 'testCli' => true, 'label' => 'CRM_PROVIDER'],
342
		'appId' => ['container' => 'env', 'testCli' => true, 'label' => 'APP_ID'],
343
		'open_basedir' => ['container' => 'php',  'type' => 'OpenBasedir', 'testCli' => true, 'mode' => 'showWarnings'],
344
		'caCertBundle' => ['recommended' => 'On', 'container' => 'env', 'type' => 'OnOff', 'testCli' => true, 'label' => 'CACERTBUNDLE'],
345
		'caCertBundlePath' => ['recommended' => 'On', 'container' => 'env', 'testCli' => true, 'label' => 'CACERTBUNDLE_PATH'],
346
		'SSL_CERT_FILE' => ['container' => 'env', 'testCli' => true, 'label' => 'SSL_CERT_FILE'],
347
		'SSL_CERT_DIR' => ['container' => 'env', 'testCli' => true, 'label' => 'SSL_CERT_DIR'],
348
		'openssl.cafile' => ['container' => 'php',  'type' => 'NotEmpty', 'testCli' => true, 'mode' => 'showWarnings'],
349
		'openssl.capath' => ['container' => 'php',  'type' => 'NotEmpty', 'testCli' => true, 'mode' => 'showWarnings'],
350
	];
351
352
	/**
353
	 * Directory permissions map.
354
	 *
355
	 * @var array
356
	 */
357
	public static $publicDirectoryAccess = [
358
		'config' => ['type' => 'NotExistsUrl', 'container' => 'request', 'testCli' => false],
359
		'cache' => ['type' => 'NotExistsUrl', 'container' => 'request', 'testCli' => false],
360
		'app_data' => ['type' => 'NotExistsUrl', 'container' => 'request', 'testCli' => false],
361
		'storage' => ['type' => 'NotExistsUrl', 'container' => 'request', 'testCli' => false],
362
		'user_privileges' => ['type' => 'NotExistsUrl', 'container' => 'request', 'testCli' => false],
363
	];
364
	/**
365
	 * Path verification.
366
	 *
367
	 * @var array
368
	 */
369
	public static $pathVerification = [
370
		'webservice/WebserviceStandard/' => ['type' => 'Webservice', 'container' => 'request', 'testCli' => false],
371
		'.well-known/carddav' => ['type' => 'ExistsUrl', 'container' => 'request', 'testCli' => false],
372
		'.well-known/caldav' => ['type' => 'ExistsUrl', 'container' => 'request', 'testCli' => false],
373
		'robots.txt' => ['type' => 'ExistsUrl', 'container' => 'request', 'testCli' => false],
374
		'install/index.php' => ['type' => 'NotExistsUrl', 'container' => 'request', 'testCli' => false],
375
	];
376
377
	/**
378 1
	 * Writable files and folders permissions map.
379
	 *
380 1
	 * @var array
381
	 */
382
	public static $writableFilesAndFolders = [
383
		'app_data/cron.php' => ['type' => 'IsWritable', 'testCli' => true],
384
		'app_data/registration.php' => ['type' => 'IsWritable', 'testCli' => true],
385
		'app_data/moduleHierarchy.php' => ['type' => 'IsWritable', 'testCli' => true],
386
		'app_data/shop.php' => ['type' => 'IsWritable', 'testCli' => true],
387
		'app_data/icons.php' => ['type' => 'IsWritable', 'testCli' => true],
388
		'app_data/LanguagesUpdater.json' => ['type' => 'IsWritable', 'testCli' => true],
389
		'app_data/SystemUpdater.json' => ['type' => 'IsWritable', 'testCli' => true],
390
		'app_data/libraries.json' => ['type' => 'IsWritable', 'testCli' => true],
391 1
		'user_privileges/tabdata.php' => ['type' => 'IsWritable', 'testCli' => true],
392
		'user_privileges/menu_0.php' => ['type' => 'IsWritable', 'testCli' => true],
393 1
		'user_privileges/user_privileges_1.php' => ['type' => 'IsWritable', 'testCli' => true],
394 1
		'cache/logs/system.log' => ['type' => 'IsWritable', 'testCli' => true],
395
		'app_data/' => ['type' => 'IsWritable', 'testCli' => true],
396 1
		'app_data/shop/' => ['type' => 'IsWritable', 'testCli' => true],
397 1
		'cache/' => ['type' => 'IsWritable', 'testCli' => true],
398 1
		'cache/addressBook/' => ['type' => 'IsWritable', 'testCli' => true],
399
		'cache/images/' => ['type' => 'IsWritable', 'testCli' => true],
400
		'cache/import/' => ['type' => 'IsWritable', 'testCli' => true],
401 1
		'cache/mail/' => ['type' => 'IsWritable', 'testCli' => true],
402
		'cache/pdf/' => ['type' => 'IsWritable', 'testCli' => true],
403
		'cache/logs/' => ['type' => 'IsWritable', 'testCli' => true],
404 1
		'cache/logs/cron/' => ['type' => 'IsWritable', 'testCli' => true],
405
		'cache/session/' => ['type' => 'IsWritable', 'testCli' => true],
406 1
		'cache/templates_c/' => ['type' => 'IsWritable', 'testCli' => true],
407
		'cache/upload/' => ['type' => 'IsWritable', 'testCli' => true],
408
		'cache/vtlib/' => ['type' => 'IsWritable', 'testCli' => true],
409
		'cache/vtlib/HTML' => ['type' => 'IsWritable', 'testCli' => true],
410
		'config/' => ['type' => 'IsWritable', 'testCli' => true],
411
		'config/Components' => ['type' => 'IsWritable', 'testCli' => true],
412
		'config/Modules' => ['type' => 'IsWritable', 'testCli' => true],
413
		'user_privileges/' => ['type' => 'IsWritable', 'testCli' => true],
414 1
		'cron/modules/' => ['type' => 'IsWritable', 'testCli' => true],
415
		'languages/' => ['type' => 'IsWritable', 'testCli' => true],
416 1
		'install/' => ['type' => 'IsWritable', 'testCli' => true],
417 1
		'modules/' => ['type' => 'IsWritable', 'testCli' => true],
418 1
		'storage/' => ['type' => 'IsWritable', 'testCli' => true],
419
		'storage/Products/' => ['type' => 'IsWritable', 'testCli' => true],
420 1
		'storage/Users/' => ['type' => 'IsWritable', 'testCli' => true],
421 1
		'storage/Contacts/' => ['type' => 'IsWritable', 'testCli' => true],
422 1
		'storage/OSSMailView/' => ['type' => 'IsWritable', 'testCli' => true],
423 1
		'public_html/modules/OSSMail/' => ['type' => 'IsWritable', 'testCli' => true],
424 1
		'public_html/libraries/' => ['type' => 'IsWritable', 'testCli' => true],
425 1
		'public_html/layouts/resources/Logo/' => ['type' => 'IsWritable', 'testCli' => true],
426 1
	];
427 1
	/**
428 1
	 * Functionality test map.
429 1
	 *
430 1
	 * @var array
431 1
	 */
432 1
	public static $functionalVerification = [
433 1
		'branding' => ['type' => 'Branding',  'testCli' => false, 'label' => 'FOOTER', 'mode' => 'onlyText'],
434 1
		'shop' => ['type' => 'ShopProducts',  'testCli' => false, 'label' => 'PREMIUM_MODULES', 'mode' => 'onlyText'],
435 1
		'watchdog' => ['type' => 'Watchdog',  'testCli' => true, 'label' => 'WATCHDOG', 'mode' => 'onlyText'],
436 1
		'register' => ['type' => 'Register',  'testCli' => true, 'label' => 'REGISTER', 'mode' => 'onlyText'],
437 1
		'shopCache' => ['type' => 'ShopCache',  'testCli' => true, 'label' => 'SHOP_CACHE', 'mode' => 'onlyText'],
438
	];
439
	/**
440
	 * Php variables.
441
	 *
442 1
	 * @var mixed[]
443
	 */
444
	private static $php = [];
445
446
	/**
447
	 * Environment variables.
448
	 *
449 2
	 * @var mixed[]
450
	 */
451 2
	private static $env = [];
452 2
453 2
	/**
454
	 * Database variables.
455 2
	 *
456 2
	 * @var mixed[]
457 2
	 */
458
	private static $db = [];
459 2
460 2
	/**
461 2
	 * Extensions.
462 2
	 *
463 2
	 * @var mixed[]
464 2
	 */
465
	private static $ext = [];
466
467 2
	/**
468
	 * Request request.
469 2
	 *
470
	 * @var mixed[]
471 2
	 */
472 2
	private static $request = [];
473 2
474 2
	/**
475 2
	 * Sapi name.
476 2
	 *
477 2
	 * @var string
478 2
	 */
479 2
	public static $sapi = 'www';
480 2
	/**
481 2
	 * Errors.
482 2
	 *
483 2
	 * @var string[]
484 2
	 */
485 2
	public static $errors = [];
486 2
487 2
	/**
488 2
	 * Get all configuration values.
489 2
	 *
490 2
	 * @return array
491
	 */
492
	public static function getAll(): array
493
	{
494
		return static::getByType(static::$types, true);
495
	}
496
497
	/**
498
	 * Get configuration values by type.
499
	 *
500
	 * @param array $types
501
	 * @param bool  $initAll
502 2
	 *
503
	 * @return array
504 2
	 */
505 2
	public static function getByType(array $types, bool $initAll = false): array
506 2
	{
507
		if ($initAll) {
508 1
			static::init('all');
509
		}
510
		$returnVal = [];
511
		foreach ($types as $type) {
512
			if (!\in_array($type, static::$types)) {
513
				throw new \App\Exceptions\IllegalValue('ERR_NOT_ALLOWED_VALUE', 406);
514
			}
515
			if (!$initAll) {
516 1
				static::init($type);
517
			}
518 1
			$returnVal[$type] = static::validate($type);
519 1
		}
520 1
		return $returnVal;
521
	}
522 1
523
	/**
524 1
	 * Initializing variables.
525 1
	 *
526 1
	 * @param string $type
527 1
	 */
528
	private static function init(string $type)
529
	{
530
		if (\App\Config::main('site_URL')) {
531
			static::$crmUrl = \App\Config::main('site_URL');
0 ignored issues
show
Bug introduced by
Since $crmUrl is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $crmUrl to at least protected.
Loading history...
532 1
		} elseif (isset(\App\Process::$requestMode) && 'Install' === \App\Process::$requestMode) {
533
			static::$crmUrl = str_replace('/install/', '/', \App\RequestUtil::getBrowserInfo()->siteUrl);
534
		}
535
		$types = static::$container;
536
		if (isset(static::${$type})) {
537
			$types = \array_unique(\array_column(static::${$type}, 'container'));
538
		}
539
		$conf = static::getConfig();
540
		foreach ($types as $item) {
541
			switch ($item) {
542 1
				case 'php':
543
					static::$php = $conf['php'];
0 ignored issues
show
Bug introduced by
Since $php is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $php to at least protected.
Loading history...
544 1
					break;
545 1
				case 'env':
546 1
					static::$env = $conf['env'];
0 ignored issues
show
Bug introduced by
Since $env is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $env to at least protected.
Loading history...
547 1
					break;
548 1
				case 'ext':
549 1
					static::$ext = get_loaded_extensions();
0 ignored issues
show
Bug introduced by
Since $ext is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $ext to at least protected.
Loading history...
550 1
					break;
551
				case 'request':
552 1
					static::$request = static::getRequest();
0 ignored issues
show
Bug introduced by
Since $request is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $request to at least protected.
Loading history...
553
					break;
554
				case 'db':
555
					$db = \App\Db::getInstance();
556
					if ($db->getMasterPdo()) {
557 1
						static::$db = $db->getInfo();
0 ignored issues
show
Bug introduced by
Since $db is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $db to at least protected.
Loading history...
558 1
					}
559 1
					break;
560 1
				case 'writableFilesAndFolders':
561
					if ($tmp = sys_get_temp_dir()) {
562
						self::$writableFilesAndFolders[$tmp] = ['type' => 'IsWritable', 'testCli' => true, 'absolutePaths' => true];
563 1
					}
564
					if ($tmp = ini_get('upload_tmp_dir')) {
565
						self::$writableFilesAndFolders[$tmp] = ['type' => 'IsWritable', 'testCli' => true, 'absolutePaths' => true];
566
					}
567 1
					break;
568
				default:
569
					break;
570
			}
571
		}
572
	}
573 1
574
	/**
575
	 * Get environment variables.
576
	 *
577
	 * @return array
578
	 */
579
	public static function getConfig()
580
	{
581
		$php = [];
582
		foreach (ini_get_all() as $key => $value) {
583 1
			$php[$key] = $value['local_value'];
584
		}
585 1
		$locale = '';
586 1
		if (\function_exists('locale_get_default')) {
587 1
			$locale = print_r(locale_get_default(), true);
588 1
		}
589
		$cron = static::getCronVariables('last_start');
590 1
		$lastCronStart = '-';
591 1
		$lastCronStartText = '-';
592 1
		if ($cron) {
593 1
			$lastCronStart = date('Y-m-d H:i:s', $cron);
594 1
			$lastCronStartText = \App\Fields\DateTime::formatToViewDate($lastCronStart);
595 1
		}
596
		$caCertBundlePath = realpath(\Composer\CaBundle\CaBundle::getSystemCaRootBundlePath());
597
		if (0 === strpos($caCertBundlePath, ROOT_DIRECTORY)) {
598
			$caCertBundlePath = str_replace(ROOT_DIRECTORY, '__CRM_PATH__', $caCertBundlePath);
599 1
		}
600
		return [
601
			'php' => $php,
602
			'env' => [
603
				'phpVersion' => PHP_VERSION,
604
				'sapi' => \PHP_SAPI,
605
				'zendVersion' => zend_version(),
606
				'phpIni' => php_ini_loaded_file() ?: '-',
607
				'phpIniAll' => php_ini_scanned_files() ?: '-',
608
				'locale' => $locale,
609
				'https' => \App\RequestUtil::isHttps(),
610 1
				'caCertBundle' => \is_file(\Composer\CaBundle\CaBundle::getSystemCaRootBundlePath()) ? 'On' : 'Off',
611
				'caCertBundlePath' => $caCertBundlePath,
612 1
				'public_html' => IS_PUBLIC_DIR ? 'On' : 'Off',
613 1
				'crmVersion' => \App\Version::get(),
614 1
				'crmDate' => \App\Version::get('patchVersion'),
615 1
				'companySize' => \App\Config::main('application_unique_key') ? \App\Company::getSize() : '-',
616 1
				'crmDir' => ROOT_DIRECTORY,
617
				'operatingSystem' => 'demo' === \App\Config::main('systemMode') ? php_uname('s') : php_uname(),
618
				'serverSoftware' => $_SERVER['SERVER_SOFTWARE'] ?? '-',
619
				'currentUser' => (\function_exists('get_current_user') ? get_current_user() : '') . ((\function_exists('getmyuid') && getmyuid()) ? ' (uid:' . getmyuid() . ')' : ''),
620 1
				'tempDir' => \App\Fields\File::getTmpPath(),
621
				'spaceRoot' => '',
622 1
				'spaceStorage' => '',
623
				'spaceTemp' => '',
624
				'spaceBackup' => '',
625
				'crmProvider' => \App\YetiForce\Register::getProvider(),
626
				'appId' => substr(\App\YetiForce\Register::getInstanceKey(), -15),
627
				'lastCronStart' => $lastCronStartText,
628
				'lastCronStartDateTime' => $lastCronStart,
629
				'protocolVersion' => isset($_SERVER['SERVER_PROTOCOL']) ? substr($_SERVER['SERVER_PROTOCOL'], strpos($_SERVER['SERVER_PROTOCOL'], '/') + 1) : '-',
630
				'SSL_CERT_FILE' => getenv('SSL_CERT_FILE') ?? '',
631
				'SSL_CERT_DIR' => getenv('SSL_CERT_DIR') ?? '',
632
			],
633
		];
634
	}
635
636
	/**
637
	 * Get variable for cron.
638
	 *
639
	 * @param string $type
640
	 *
641
	 * @return mixed
642
	 */
643
	public static function getCronVariables(string $type)
644
	{
645
		$data = [];
646
		$filePath = ROOT_DIRECTORY . '/app_data/cron.php';
647
		if (file_exists($filePath)) {
648
			try {
649
				$cron = include $filePath;
650
				$data = $cron[$type] ?? null;
651
			} catch (\Throwable $e) {
652
				unlink($filePath);
653
				throw $e;
654
			}
655
		}
656
		return $data;
657
	}
658
659
	/**
660
	 * Get request request.
661
	 *
662
	 * @return array
663
	 */
664
	private static function getRequest()
665
	{
666
		$requestUrl = static::$crmUrl;
0 ignored issues
show
Bug introduced by
Since $crmUrl is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $crmUrl to at least protected.
Loading history...
667
		if (\PHP_SAPI !== 'cli' && !IS_PUBLIC_DIR) {
668
			$requestUrl .= 'public_html/';
669
		}
670
		$request = [];
671
		try {
672
			foreach (static::$urlsToCheck as $type => $url) {
673
				$urlAddress = $requestUrl . $url;
674
				\App\Log::beginProfile("GET|ConfReport::getRequest|{$urlAddress}", __NAMESPACE__);
675
				$res = (new \GuzzleHttp\Client(\App\RequestHttp::getOptions()))->request('HEAD', $urlAddress, ['timeout' => 1, 'verify' => false]);
676
				\App\Log::endProfile("GET|ConfReport::getRequest|{$urlAddress}", __NAMESPACE__);
677
				foreach ($res->getHeaders() as $key => $value) {
678
					$request[strtolower($key)][$type] = \is_array($value) ? implode(',', $value) : $value;
679
				}
680
			}
681
		} catch (\Throwable $e) {
682
			self::$errors[__FUNCTION__] = $e->getMessage();
683
		}
684
		return $request;
685
	}
686
687
	/**
688
	 * Validating configuration values.
689
	 *
690
	 * @param string $type
691
	 *
692
	 * @return mixed
693
	 */
694
	private static function validate(string $type)
695
	{
696
		$main = static::parse($type);
697
		$cron = static::getCronVariables($type);
698
		foreach (static::${$type} as $key => &$item) {
699
			if (!isset($item['status'])) {
700
				$item['status'] = true;
701
				if (isset($main[$key])) {
702
					$item[static::$sapi] = $main[$key];
703
				}
704
				if (isset($cron[$key]['cron']) && (self::$testCli || ($item['testCli'] && 'www' === static::$sapi))) {
705
					$item['cron'] = $cron[$key]['cron'];
706
				}
707
				if (isset($item['type'])) {
708
					$methodName = 'validate' . $item['type'];
709
					if (\method_exists(__CLASS__, $methodName)) {
710
						if ('www' === static::$sapi) {
711
							$item = static::$methodName($key, $item, 'www');
712
						}
713
						if (self::$testCli || ($item['testCli'] && !empty($cron))) {
714
							$item = static::$methodName($key, $item, 'cron');
715
						}
716
					}
717
					if (isset($item['mode']) && (('whenError' === $item['mode'] && !$item['status']) || 'skipParam' === $item['mode'])) {
718
						unset(static::${$type}[$key]);
719
					}
720
				}
721
			}
722
		}
723
		return static::${$type};
724
	}
725
726
	/**
727
	 * Parser of configuration values.
728
	 *
729
	 * @param string $type
730
	 *
731
	 * @return array
732
	 */
733
	private static function parse(string $type)
734
	{
735
		$values = [];
736
		foreach (static::${$type} as $key => $item) {
737
			if ('cron' === static::$sapi && !$item['testCli']) {
738
				continue;
739
			}
740
			if (isset($item['type']) && ($methodName = 'parser' . $item['type']) && \method_exists(__CLASS__, $methodName)) {
741
				$values[$key] = \call_user_func_array([__CLASS__, $methodName], [$key, $item]);
742
			} elseif (isset($item['container'])) {
743
				$container = $item['container'];
744
				if (isset(static::${$container}[\strtolower($key)]) || isset(static::${$container}[$key])) {
745
					$values[$key] = static::${$container}[\strtolower($key)] ?? static::${$container}[$key];
746
				}
747
			}
748
		}
749
		return $values;
750
	}
751
752
	/**
753
	 * Get configuration values by type of map.
754
	 *
755
	 * @param string $type
756
	 * @param bool   $onlyError
757
	 *
758
	 * @return mixed
759
	 */
760
	public static function get(string $type, bool $onlyError = false)
761
	{
762
		static::init($type);
763
		if ($onlyError) {
764
			$values = [];
765
			foreach (static::validate($type) as $key => $item) {
766
				if (!$item['status']) {
767
					$values[$key] = $item;
768
				}
769
			}
770
			return $values;
771
		}
772
		return static::validate($type);
773
	}
774
775
	/**
776
	 * Validate php version.
777
	 *
778
	 * @param string $name
779
	 * @param array  $row
780
	 * @param string $sapi
781
	 *
782
	 * @return mixed
783
	 */
784
	private static function validateVersion(string $name, array $row, string $sapi)
785
	{
786
		unset($name);
787
		$phpVersions = explode(',', $row['recommended']);
788
		$row['status'] = false;
789
		foreach ($phpVersions as $phpVersion) {
790
			if (!empty($row[$sapi]) && \App\Version::compare($row[$sapi], trim($phpVersion))) {
791
				$row['status'] = true;
792
				break;
793
			}
794
		}
795
		if ((isset(\App\Process::$requestMode) && 'Install' === \App\Process::$requestMode) && isset($row['Install']) && !$row['Install']) {
796
			$row['mode'] = 'skipParam';
797
		}
798
		return $row;
799
	}
800
801
	/**
802
	 * Validate database version.
803
	 *
804
	 * @param string $name
805
	 * @param array  $row
806
	 * @param string $sapi
807
	 *
808
	 * @return bool
809
	 */
810
	private static function validateVersionDb(string $name, array $row, string $sapi)
811
	{
812
		unset($name);
813
		$recommended = \is_string($row['recommended']) ? $row['recommended'] : $row['recommended'][static::$db['typeDb']];
0 ignored issues
show
Bug introduced by
Since $db is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $db to at least protected.
Loading history...
814
		$row['status'] = false;
815
		if (!empty($row[$sapi]) && \App\Version::compare($row[$sapi], $recommended, '>=')) {
816
			$row['status'] = true;
817
		}
818
		$row['recommended'] = $recommended;
819
		return $row;
820
	}
821
822
	/**
823
	 * Validate error reporting.
824
	 *
825
	 * @param string $name
826
	 * @param array  $row
827
	 * @param string $sapi
828
	 *
829
	 * @return array
830
	 */
831
	private static function validateErrorReporting(string $name, array $row, string $sapi)
832
	{
833
		unset($name);
834
		$current = $row[$sapi];
835
		$errorReporting = false === stripos($current, '_') ? \App\ErrorHandler::error2string($current) : $current;
836
		if ('E_ALL & ~E_NOTICE' === $row['recommended'] && ((E_ALL & ~E_NOTICE) === (int) $current || 'E_ALL & ~E_NOTICE' === $errorReporting)) {
837
			$row[$sapi] = $row['recommended'];
838
		} else {
839
			$row['status'] = false;
840
			if (\is_array($errorReporting)) {
841
				$row[$sapi] = implode(' | ', $errorReporting) . " ({$current})";
842
			}
843
		}
844
		return $row;
845
	}
846
847
	/**
848
	 * Validate on, off and int values.
849
	 *
850
	 * @param string $name
851
	 * @param array  $row
852
	 * @param string $sapi
853
	 *
854
	 * @return array
855
	 */
856
	private static function validateOnOffInt(string $name, array $row, string $sapi)
857
	{
858
		unset($name);
859
		if ('cron' !== $sapi && 'on' !== strtolower($row[$sapi])) {
860
			$row['status'] = false;
861
		}
862
		return $row;
863
	}
864
865
	/**
866
	 * Validate number greater than recommended.
867
	 *
868
	 * @param string $name
869
	 * @param array  $row
870
	 * @param string $sapi
871
	 *
872
	 * @return array
873
	 */
874
	private static function validateGreater(string $name, array $row, string $sapi)
875
	{
876
		unset($name);
877
		if (isset($row[$sapi])) {
878
			if ((int) $row[$sapi] > 0 && (int) $row[$sapi] < (int) $row['recommended']) {
879
				$row['status'] = false;
880
			}
881
		} else {
882
			$row['noParameter'] = true;
883
		}
884
		return $row;
885
	}
886
887
	/**
888
	 * Validate number greater than another parameter.
889
	 *
890
	 * @param string $name
891
	 * @param array  $row
892
	 * @param string $sapi
893
	 *
894
	 * @return array
895
	 */
896
	private static function validateDbTableDefinitionCache(string $name, array $row, string $sapi)
897
	{
898
		unset($name);
899
		$tableOpenCache = (self::$db['table_open_cache'] > self::$database['table_open_cache']['recommended']) ? self::$db['table_open_cache'] : self::$database['table_open_cache']['recommended'];
900
		$row['recommended'] = $tableOpenCache + 400;
901
		if (isset($row[$sapi]) && (int) $row[$sapi] < $row['recommended']) {
902
			$row['status'] = false;
903
		}
904
		if (!isset($row[$sapi])) {
905
			$row['noParameter'] = true;
906
		}
907
		return $row;
908
	}
909
910
	/**
911
	 * Validate number in bytes greater than recommended.
912
	 *
913
	 * @param string $name
914
	 * @param array  $row
915
	 * @param string $sapi
916
	 *
917
	 * @return array
918
	 */
919
	private static function validateGreaterMb(string $name, array $row, string $sapi)
920
	{
921
		unset($name);
922
		if (isset($row[$sapi])) {
923
			if ('-1' !== $row[$sapi] && \vtlib\Functions::parseBytes($row[$sapi]) < \vtlib\Functions::parseBytes($row['recommended'])) {
924
				$row['status'] = false;
925
			}
926
			$row[$sapi] = \vtlib\Functions::showBytes($row[$sapi]);
927
		} else {
928
			$row['noParameter'] = true;
929
		}
930
		return $row;
931
	}
932
933
	/**
934 1
	 * Display number in bytes.
935
	 *
936 1
	 * @param string $name
937 1
	 * @param array  $row
938 1
	 * @param string $sapi
939 1
	 *
940
	 * @return array
941
	 */
942
	private static function validateShowBytes(string $name, array $row, string $sapi)
943
	{
944
		unset($name);
945
		if (isset($row[$sapi])) {
946
			$row[$sapi] = \vtlib\Functions::showBytes($row[$sapi]);
947
		} else {
948
			$row['noParameter'] = true;
949
		}
950
		return $row;
951
	}
952
953
	/**
954
	 * Validate equal value "recommended == current".
955
	 *
956
	 * @param string $name
957
	 * @param array  $row
958
	 * @param string $sapi
959
	 *
960
	 * @return array
961
	 */
962
	private static function validateEqual(string $name, array $row, string $sapi)
963
	{
964
		unset($name);
965
		if (isset($row[$sapi])) {
966
			if (strtolower((string) $row[$sapi]) !== strtolower((string) $row['recommended'])) {
967
				$row['status'] = false;
968
			}
969
		} else {
970
			$row['noParameter'] = true;
971
		}
972
		return $row;
973
	}
974
975
	/**
976
	 * Validate equal value "cron == www".
977
	 *
978
	 * @param string $name
979
	 * @param array  $row
980
	 * @param string $sapi
981
	 *
982
	 * @return array
983
	 */
984
	private static function validateCronEqual(string $name, array $row, string $sapi)
985
	{
986
		unset($name);
987
		if ('www' === $sapi && isset($row['cron']) && strtolower($row['www'] ?? '') !== strtolower($row['cron'] ?? '')) {
988
			$row['status'] = false;
989
		}
990
		return $row;
991
	}
992
993
	/**
994
	 * Validate date timezone.
995
	 *
996
	 * @param string $name
997
	 * @param array  $row
998
	 * @param string $sapi
999
	 *
1000
	 * @return array
1001
	 */
1002
	private static function validateTimeZone(string $name, array $row, string $sapi)
1003
	{
1004
		unset($name);
1005
		$row[$sapi] = \App\Fields\DateTime::getTimeZone();
1006
		try {
1007
			$test = new \DateTimeZone($row[$sapi]);
1008
			if ($test->getName() === $row[$sapi]) {
1009
				return $row;
1010
			}
1011
			$row['status'] = false;
1012
			return $row;
1013
		} catch (\Throwable $e) {
1014
			$row[$sapi] = \App\Language::translate('LBL_INVALID_TIME_ZONE', 'Settings::ConfReport') . $row[$sapi];
1015
			$row['status'] = false;
1016
		}
1017
		return $row;
1018
	}
1019
1020
	/**
1021
	 * Validate on or off value.
1022
	 *
1023
	 * @param string $name
1024
	 * @param array  $row
1025
	 * @param string $sapi
1026
	 *
1027
	 * @return array
1028
	 */
1029
	private static function validateOnOff(string $name, array $row, string $sapi)
1030
	{
1031
		unset($name);
1032
		if (isset($row[$sapi])) {
1033
			if ($row[$sapi] !== $row['recommended'] && !(isset($row['demoMode']) && 'prod' !== \App\Config::main('systemMode'))) {
1034
				$row['status'] = false;
1035
			}
1036
		} else {
1037
			$row['noParameter'] = true;
1038
		}
1039
1040
		return $row;
1041
	}
1042
1043
	/**
1044
	 * Validate function exist.
1045
	 *
1046
	 * @param string $name
1047
	 * @param array  $row
1048
	 * @param string $sapi
1049
	 *
1050
	 * @return array
1051
	 */
1052
	private static function validateFnExist(string $name, array $row, string $sapi)
1053
	{
1054
		unset($name);
1055
		$row['status'] = \function_exists($row['fnName']);
1056
		$row[$sapi] = $row['status'] ? 'LBL_YES' : 'LBL_NO';
1057
		return $row;
1058
	}
1059
1060
	/**
1061
	 * Validate extension loaded.
1062
	 *
1063
	 * @param string $name
1064
	 * @param array  $row
1065
	 * @param string $sapi
1066
	 *
1067 1
	 * @return array
1068
	 */
1069 1
	private static function validateExtExist(string $name, array $row, string $sapi)
1070 1
	{
1071
		unset($name);
1072
		$row['status'] = \in_array($row['extName'], static::$ext);
0 ignored issues
show
Bug introduced by
Since $ext is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $ext to at least protected.
Loading history...
1073
		$row[$sapi] = $row['status'] ? 'LBL_YES' : 'LBL_NO';
1074
		if ($row['status'] && 'www' === $sapi) {
1075
			$ext = new \ReflectionExtension($row['extName']);
1076
			ob_start();
1077
			$ext->info();
1078
			if ($i = ob_get_contents()) {
1079
				$info = $i;
1080
			}
1081
			ob_end_clean();
1082
			$row[$sapi . '_info'] = $info;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $info does not seem to be defined for all execution paths leading up to this point.
Loading history...
1083
		}
1084
		return $row;
1085
	}
1086
1087
	/**
1088
	 * Validate extension loaded.
1089
	 *
1090
	 * @param string $name
1091
	 * @param array  $row
1092
	 * @param string $sapi
1093
	 *
1094
	 * @return array
1095
	 */
1096
	private static function validateExtNotExist(string $name, array $row, string $sapi)
1097
	{
1098
		unset($name);
1099
		if (\in_array($row['extName'], static::$ext)) {
0 ignored issues
show
Bug introduced by
Since $ext is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $ext to at least protected.
Loading history...
1100
			$row['status'] = false;
1101
		}
1102
		$row[$sapi] = $row['status'] ? 'Off' : 'On';
1103
		return $row;
1104
	}
1105
1106
	/**
1107
	 * Validate session.cookie_secure.
1108
	 *
1109
	 * @param string $name
1110
	 * @param array  $row
1111
	 * @param string $sapi
1112
	 *
1113
	 * @return array
1114
	 */
1115
	private static function validateCookieSecure(string $name, array $row, string $sapi)
1116
	{
1117
		$row[$sapi] = static::parserOnOff($name, $row);
1118
		$row['recommended'] = static::$env['https'] ? 'On' : 'Off';
0 ignored issues
show
Bug introduced by
Since $env is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $env to at least protected.
Loading history...
1119
		$row['status'] = $row[$sapi] === $row['recommended'];
1120
		return $row;
1121
	}
1122
1123
	/**
1124
	 * Validate session.cookie_samesite.
1125
	 *
1126
	 * @param string $name
1127
	 * @param array  $row
1128
	 * @param string $sapi
1129
	 *
1130
	 * @return array
1131
	 */
1132
	private static function validateCookieSamesite(string $name, array $row, string $sapi)
1133
	{
1134
		$row['recommended'] = \Config\Security::$cookieSameSite;
1135
		$row['status'] = ($row[$sapi] ?? '') === $row['recommended'];
1136
		return $row;
1137
	}
1138
1139
	/**
1140
	 * Parser on or off value.
1141
	 *
1142
	 * @param string $name
1143
	 * @param array  $row
1144
	 *
1145
	 * @return array
1146
	 */
1147
	private static function parserOnOff(string $name, array $row)
1148
	{
1149
		$container = $row['container'];
1150
		$current = static::${$container}[\strtolower($name)] ?? static::${$container}[$name] ?? '';
1151
		static $map = ['on' => 'On', 'true' => 'On', 'off' => 'Off', 'false' => 'Off'];
1152
		return isset($map[strtolower($current)]) ? $map[strtolower($current)] : ($current ? 'On' : 'Off');
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $map[...$current ? 'On' : 'Off' also could return the type string which is incompatible with the documented return type array.
Loading history...
1153
	}
1154
1155
	/**
1156
	 * Validate session_regenerate_id.
1157
	 *
1158
	 * @param string $name
1159
	 * @param array  $row
1160
	 * @param string $sapi
1161
	 *
1162
	 * @return array
1163
	 */
1164
	private static function validateSessionRegenerate(string $name, array $row, string $sapi)
1165
	{
1166
		unset($name);
1167
		if ('Install' !== \App\Process::$requestMode) {
1168
			$row[$sapi] = \Config\Security::$loginSessionRegenerate ? 'On' : 'Off';
1169
			$row['status'] = \Config\Security::$loginSessionRegenerate;
1170
		} else {
1171
			$row['mode'] = 'skipParam';
1172
		}
1173
		return $row;
1174
	}
1175
1176
	/**
1177
	 * Validate header.
1178
	 *
1179
	 * @param string $name
1180
	 * @param array  $row
1181
	 * @param string $sapi
1182
	 *
1183
	 * @return array
1184
	 */
1185
	private static function validateHeader(string $name, array $row, string $sapi)
1186
	{
1187
		unset($sapi);
1188
		$header = strtolower(\str_replace('Header: ', '', $name));
1189
		if (!empty($row['httpsRequired']) && !\App\RequestUtil::isHttps()) {
1190
			$row['recommended'] = '';
1191
		}
1192
		$onlyPhp = empty($row['onlyPhp']);
1193
		if (isset(static::$request[$header])) {
0 ignored issues
show
Bug introduced by
Since $request is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $request to at least protected.
Loading history...
1194
			$row['www'] = static::$request[$header]['root'] ?? '-';
1195
			$row['js'] = static::$request[$header]['js'] ?? '-';
1196
			$row['css'] = static::$request[$header]['css'] ?? '-';
1197
			$row['status'] = strtolower($row['www']) === strtolower($row['recommended']);
1198
			if ($onlyPhp) {
1199
				$row['status'] = $row['status'] && strtolower($row['js']) === strtolower($row['recommended']) && strtolower($row['css']) === strtolower($row['recommended']);
1200
			}
1201
		} elseif ('' === $row['recommended']) {
1202
			$row['status'] = true;
1203
		} else {
1204
			$row['status'] = false;
1205
		}
1206
		return $row;
1207
	}
1208
1209
	/**
1210
	 * Validate header CSP.
1211
	 *
1212
	 * @param string $name
1213
	 * @param array  $row
1214
	 * @param string $sapi
1215
	 *
1216
	 * @return array
1217
	 */
1218
	private static function validateHeaderServer(string $name, array $row, string $sapi)
1219
	{
1220
		unset($sapi);
1221
		$header = strtolower(\str_replace('Header: ', '', $name));
1222
		$onlyPhp = empty($row['onlyPhp']);
1223
		if (isset(static::$request[$header])) {
0 ignored issues
show
Bug introduced by
Since $request is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $request to at least protected.
Loading history...
1224
			$row['www'] = static::$request[$header]['root'] ?? '-';
1225
			$row['js'] = static::$request[$header]['js'] ?? '-';
1226
			$row['css'] = static::$request[$header]['css'] ?? '-';
1227
			$row['status'] = empty($row['www']);
1228
			if ($onlyPhp) {
1229
				$row['status'] = $row['status'] && empty($row['js']) && empty($row['css']);
1230
			}
1231
			if (!$row['status'] && \App\Validator::standard($row['www'])) {
1232
				$row['mode'] = 'showWarnings';
1233
			}
1234
		}
1235
		$row['status'] = false;
1236
1237
		return $row;
1238
	}
1239
1240
	/**
1241
	 * Validate header CSP.
1242
	 *
1243
	 * @param string $name
1244
	 * @param array  $row
1245
	 * @param string $sapi
1246
	 *
1247
	 * @return array
1248
	 */
1249
	private static function validateHeaderCsp(string $name, array $row, string $sapi)
1250
	{
1251
		unset($sapi);
1252
		$header = strtolower(\str_replace('Header: ', '', $name));
1253
		$row['recommended'] = trim(\App\Controller\Headers::getInstance()->getCspHeader());
1254
		if (isset(static::$request[$header])) {
0 ignored issues
show
Bug introduced by
Since $request is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $request to at least protected.
Loading history...
1255
			$row['www'] = static::$request[$header]['root'] ?? '-';
1256
			$row['status'] = strtolower($row['www']) === strtolower($row['recommended']);
1257
			if (!$row['status']) {
1258
				$www = [];
1259
				foreach (explode(';', $row['www']) as $value) {
1260
					if ($value) {
1261
						$name = explode(' ', trim($value))[0];
1262
						$www[$name] = $value;
1263
					}
1264
				}
1265
				foreach (explode(';', $row['recommended']) as $value) {
1266
					if ($value) {
1267
						$name = explode(' ', trim($value))[0];
1268
						if ($www[$name] !== $value) {
1269
							$row['recommended'] = str_replace($value, "<b class=\"text-danger\">$value</b>", $row['recommended']);
1270
							$row['isHtml'] = true;
1271 1
						}
1272
					}
1273 1
				}
1274 1
			}
1275
		} else {
1276
			$row['status'] = false;
1277
		}
1278
		return $row;
1279
	}
1280
1281
	/**
1282
	 * Validate not in array.
1283
	 *
1284
	 * @param string $name
1285
	 * @param array  $row
1286
	 * @param string $sapi
1287
	 *
1288
	 * @return array
1289
	 */
1290
	private static function validateNotIn(string $name, array $row, string $sapi)
1291
	{
1292
		unset($name);
1293
		if (isset($row[$sapi])) {
1294
			$value = $row[$sapi];
1295
			if (!\is_array($row[$sapi])) {
1296
				$value = \explode(',', $row[$sapi]);
1297
			}
1298
			$recommended = (array) $row['exclusions'];
1299
			foreach ($recommended as $item) {
1300 1
				if (\in_array($item, $value)) {
1301
					$row['status'] = false;
1302
					break;
1303
				}
1304
			}
1305
		} else {
1306
			$row['noParameter'] = true;
1307
		}
1308
		return $row;
1309
	}
1310
1311
	/**
1312
	 * Validate in array.
1313
	 *
1314
	 * @param string $name
1315
	 * @param array  $row
1316
	 * @param string $sapi
1317
	 *
1318
	 * @return array
1319
	 */
1320
	private static function validateIn(string $name, array $row, string $sapi)
1321
	{
1322
		unset($name);
1323
		$value = $row[$sapi] ?? '';
1324
		if (!isset($row[$sapi])) {
1325
			$row['noParameter'] = true;
1326
		}
1327
		if (!\is_array($value)) {
1328
			$value = \explode(',', $value);
1329
		}
1330
		$value = \array_map('trim', $value);
1331
		$recommended = \array_map('trim', \explode(',', $row['recommended']));
1332
		foreach ($recommended as &$item) {
1333 1
			if (!\in_array($item, $value)) {
1334
				$row['status'] = false;
1335 1
				$item = "<b class=\"text-danger\">$item</b>";
1336 1
				$row['isHtml'] = true;
1337 1
			}
1338
		}
1339 1
		$row['recommended'] = \implode(', ', $recommended);
1340 1
		return $row;
1341 1
	}
1342 1
1343 1
	/**
1344
	 * Validate one of array.
1345 1
	 *
1346 1
	 * @param string $name
1347 1
	 * @param array  $row
1348 1
	 * @param string $sapi
1349 1
	 *
1350
	 * @return array
1351
	 */
1352 1
	private static function validateOneOf(string $name, array $row, string $sapi)
1353 1
	{
1354 1
		unset($name);
1355 1
		if (isset($row['values'])) {
1356 1
			$recommended = $row['values'];
1357 1
		} else {
1358
			$recommended = \array_map('trim', \explode(',', strtolower($row['recommended'])));
1359 1
		}
1360 1
		if (isset($row[$sapi])) {
1361 1
			if (!\in_array((string) $row[$sapi], $recommended)) {
1362 1
				$row['status'] = false;
1363 1
			}
1364 1
		} else {
1365
			$row['noParameter'] = true;
1366 1
		}
1367 1
		return $row;
1368 1
	}
1369 1
1370
	/**
1371 1
	 * Validate exists url.
1372 1
	 *
1373 1
	 * @param string $name
1374 1
	 * @param array  $row
1375 1
	 * @param string $sapi
1376
	 *
1377
	 * @return array
1378
	 */
1379
	private static function validateExistsUrl(string $name, array $row, string $sapi)
1380
	{
1381
		unset($sapi);
1382
		$row['status'] = \App\Fields\File::isExistsUrl(static::$crmUrl . $name);
0 ignored issues
show
Bug introduced by
Since $crmUrl is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $crmUrl to at least protected.
Loading history...
1383
		return $row;
1384
	}
1385
1386
	/**
1387
	 * Validate not exists url.
1388
	 *
1389
	 * @param string $name
1390
	 * @param array  $row
1391
	 * @param string $sapi
1392
	 *
1393
	 * @return array
1394
	 */
1395
	private static function validateNotExistsUrl(string $name, array $row, string $sapi)
1396
	{
1397
		unset($sapi);
1398
		$row['status'] = !\App\Fields\File::isExistsUrl(static::$crmUrl . $name);
0 ignored issues
show
Bug introduced by
Since $crmUrl is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $crmUrl to at least protected.
Loading history...
1399
		return $row;
1400
	}
1401
1402
	/**
1403
	 * Parser all extensions value.
1404
	 *
1405
	 * @param string $name
1406
	 * @param array  $row
1407
	 *
1408
	 * @return array
1409
	 */
1410
	private static function parserAllExt(string $name, array $row)
1411
	{
1412
		unset($name, $row);
1413
		sort(static::$ext, SORT_NATURAL | SORT_FLAG_CASE);
0 ignored issues
show
Bug introduced by
Since $ext is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $ext to at least protected.
Loading history...
1414
		return \implode(', ', static::$ext);
0 ignored issues
show
Bug Best Practice introduced by
The expression return implode(', ', static::ext) returns the type string which is incompatible with the documented return type array.
Loading history...
1415
	}
1416
1417
	/**
1418
	 * Validate exists url.
1419
	 *
1420
	 * @param string $name
1421
	 * @param array  $row
1422
	 * @param string $sapi
1423
	 *
1424
	 * @return array
1425
	 */
1426
	private static function validateAllExt(string $name, array $row, string $sapi)
1427
	{
1428
		unset($name);
1429
		$forbidden = ['uopz'];
1430
		if (isset($row[$sapi])) {
1431
			foreach (array_intersect($forbidden, \explode(', ', $row[$sapi])) as $type) {
1432
				$row[$sapi] = \str_replace($type, "<b class=\"text-danger\">$type</b>", $row[$sapi]);
1433
				$row['isHtml'] = true;
1434
				$row['status'] = false;
1435
			}
1436
		}
1437
		return $row;
1438
	}
1439
1440
	/**
1441
	 * Validate disc space value.
1442
	 *
1443
	 * @param string $name
1444
	 * @param array  $row
1445
	 * @param string $sapi
1446
	 *
1447
	 * @return array
1448
	 */
1449
	private static function validateSpace(string $name, array $row, string $sapi)
1450
	{
1451
		$dir = ROOT_DIRECTORY . \DIRECTORY_SEPARATOR;
1452
		switch ($name) {
1453
			case 'spaceStorage':
1454
				$dir .= 'storage';
1455
				break;
1456
			case 'spaceTemp':
1457
				$dir = static::$env['tempDir'];
0 ignored issues
show
Bug introduced by
Since $env is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $env to at least protected.
Loading history...
1458
				break;
1459
			case 'spaceBackup':
1460
				$dir = \App\Utils\Backup::getBackupCatalogPath();
1461
				break;
1462
			default:
1463
				break;
1464
		}
1465
		if (empty($dir) || !is_dir($dir)) {
1466
			return $row;
1467
		}
1468
		$free = disk_free_space($dir);
1469
		$total = disk_total_space($dir);
1470
		$row['spaceTotal'] = $total;
1471
		$row['spaceFree'] = $free;
1472
		$row[$sapi] = round((($total - $free) / $total) * 100) . '% | ';
1473
		$row[$sapi] .= \App\Language::translate('LBL_SPACE_FREE', 'Settings::ConfReport') . ': ';
1474
		$row[$sapi] .= \vtlib\Functions::showBytes($free) . ' | ';
1475
		$row[$sapi] .= \App\Language::translate('LBL_SPACE_USED', 'Settings::ConfReport') . ': ';
1476
		$row[$sapi] .= \vtlib\Functions::showBytes($total - $free);
1477
		if ($free < 1024 * 1024 * 1024) {
1478
			$row['status'] = false;
1479
		}
1480
		return $row;
1481
	}
1482
1483
	/**
1484
	 * Parser http methods value.
1485
	 *
1486
	 * @param string $name
1487
	 * @param array  $row
1488
	 *
1489
	 * @return array
1490
	 */
1491
	private static function parserHttpMethods(string $name, array $row)
1492
	{
1493
		unset($name);
1494
		$supported = [];
1495
		$requestUrl = static::$crmUrl . 'token.php';
0 ignored issues
show
Bug introduced by
Since $crmUrl is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $crmUrl to at least protected.
Loading history...
1496
		foreach (\explode(', ', $row['recommended']) as $type) {
1497
			try {
1498
				$response = (new \GuzzleHttp\Client(\App\RequestHttp::getOptions()))->request($type, $requestUrl, ['timeout' => 1, 'verify' => false]);
1499
				if (200 === $response->getStatusCode()) {
1500
					$supported[] = $type;
1501
				}
1502
			} catch (\Throwable $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1503
			}
1504
		}
1505
		return \implode(', ', $supported);
0 ignored issues
show
Bug Best Practice introduced by
The expression return implode(', ', $supported) returns the type string which is incompatible with the documented return type array.
Loading history...
1506
	}
1507
1508
	/**
1509
	 * Validate http methods.
1510
	 *
1511
	 * @param string $name
1512
	 * @param array  $row
1513
	 * @param string $sapi
1514
	 *
1515
	 * @return array
1516
	 */
1517
	private static function validateHttpMethods(string $name, array $row, string $sapi)
1518
	{
1519
		unset($name);
1520
		foreach (array_diff(\explode(',', $row['recommended']), \explode(',', $row[static::$sapi])) as $type) {
1521
			$row['recommended'] = \str_replace($type, "<b class=\"text-danger\">$type</b>", $row['recommended']);
1522
			$row['isHtml'] = true;
1523
		}
1524
		return $row;
1525
	}
1526
1527
	/**
1528
	 * Validate realpath cache size.
1529
	 *
1530
	 * @param string $name
1531
	 * @param array  $row
1532
	 * @param string $sapi
1533
	 *
1534
	 * @return array
1535
	 */
1536
	private static function validateIsWritable(string $name, array $row, string $sapi)
1537
	{
1538
		$absolutePaths = $row['absolutePaths'] ?? false;
1539
		$path = $name;
1540
		if (!$absolutePaths) {
1541
			$path = ROOT_DIRECTORY . \DIRECTORY_SEPARATOR . $path;
1542
		}
1543
		if (!file_exists($path)) {
1544
			$row['mode'] = 'skipParam';
1545
		} else {
1546
			$row['status'] = \App\Fields\File::isWriteable($path, true);
1547
			$row[$sapi] = $row['status'] ? 'LBL_YES' : 'LBL_NO';
1548
			$row['owner'] = fileowner($path);
1549
			$row['perms'] = substr(sprintf('%o', fileperms($path)), -4);
1550
		}
1551
		return $row;
1552
	}
1553
1554
	/**
1555
	 * Validate branding value.
1556
	 *
1557
	 * @param string $name
1558
	 * @param array  $row
1559
	 * @param string $sapi
1560
	 *
1561
	 * @return array
1562
	 */
1563
	private static function validateBranding(string $name, array $row, string $sapi)
1564
	{
1565
		$view = new \Vtiger_Viewer();
1566
		$view->assign('APPTITLE', \App\Language::translate('APPTITLE'));
1567
		$view->assign('YETIFORCE_VERSION', \App\Version::get());
1568
		$view->assign('MODULE_NAME', 'Base');
1569
		$view->assign('USER_MODEL', \Users_Record_Model::getCurrentUserModel());
1570
		$view->assign('ACTIVITY_REMINDER', 0);
1571
		$view->assign('FOOTER_SCRIPTS', []);
1572
		$view->assign('SHOW_FOOTER', true);
1573
		$view->assign('SHOW_FOOTER_BAR', true);
1574
		$html = $view->view('PageFooter.tpl', '', true);
1575
		$row['status'] = true;
1576
		if (!\App\YetiForce\Shop::check('YetiForceDisableBranding')) {
1577
			$row['status'] = false !== \strpos($html, '&copy; YetiForce.com All rights reserved') || !empty(\App\Config::component('Branding', 'footerName'));
1578
		}
1579
		unset($name);
1580
		$row[$sapi] = \App\Language::translate($row['status'] ? 'LBL_YES' : 'LBL_NO');
1581
		return $row;
1582
	}
1583
1584
	/**
1585
	 * Validate shop products.
1586
	 *
1587
	 * @param string $name
1588
	 * @param array  $row
1589
	 * @param string $sapi
1590
	 *
1591
	 * @return array
1592
	 */
1593
	public static function validateShopProducts(string $name, array $row, string $sapi)
1594
	{
1595
		unset($name);
1596
		$row['status'] = true;
1597
		$status = '';
1598
		foreach (\App\YetiForce\Shop::getProducts() as $name => $product) {
1599
			$verify = $product->verify();
1600
			if (!$verify['status']) {
1601
				$status .= $name . '(' . \strlen($verify['message']) . '), ';
1602
				$row['status'] = false;
1603
			}
1604
		}
1605
		$row[$sapi] = $status ? trim($status, ', ') : ('shop' === $sapi ? '' : \App\Language::translate('LBL_YES'));
1606
		return $row;
1607
	}
1608
1609
	/**
1610
	 * Validate open_basedir.
1611
	 *
1612
	 * @param string $name
1613
	 * @param array  $row
1614
	 * @param string $sapi
1615
	 *
1616
	 * @return array
1617
	 */
1618
	private static function validateOpenBasedir(string $name, array $row, string $sapi)
1619
	{
1620
		unset($name);
1621
		$row['status'] = true;
1622
		if ('cron' === $sapi) {
1623
			if (!empty($row[$sapi])) {
1624
				$row['status'] = false;
1625
			}
1626
		} else {
1627
			if (empty($row[$sapi])) {
1628
				$row['status'] = false;
1629
			}
1630
		}
1631
		return $row;
1632
	}
1633
1634
	/**
1635
	 * Validate check if value is empty.
1636
	 *
1637
	 * @param string $name
1638
	 * @param array  $row
1639
	 * @param string $sapi
1640
	 *
1641
	 * @return array
1642
	 */
1643
	private static function validateNotEmpty(string $name, array $row, string $sapi)
1644
	{
1645
		unset($name);
1646
		if (empty($row[$sapi])) {
1647
			$row['status'] = false;
1648
		}
1649
		return $row;
1650
	}
1651
1652
	/**
1653
	 * Validate check error_log.
1654
	 *
1655
	 * @param string $name
1656
	 * @param array  $row
1657
	 * @param string $sapi
1658
	 *
1659
	 * @return array
1660
	 */
1661
	private static function validateErrorLog(string $name, array $row, string $sapi)
1662
	{
1663
		$row = self::validateNotEmpty($name, $row, $sapi);
1664
		if ($row['status']) {
1665
			$dir = \dirname($row[$sapi]);
1666
			if (!is_dir($dir) && !is_readable($dir)) {
1667
				$row['status'] = true;
1668
			}
1669
		}
1670
		return $row;
1671
	}
1672
1673
	/**
1674
	 * Validate watchdog.
1675
	 *
1676
	 * @param string $name
1677
	 * @param array  $row
1678
	 * @param string $sapi
1679
	 *
1680
	 * @return array
1681
	 */
1682
	public static function validateWatchdog(string $name, array $row, string $sapi)
1683
	{
1684
		unset($name);
1685
		$row['status'] = true;
1686
		$row[$sapi] = \App\Language::translate('LBL_YES');
1687
		if (!\App\Cron::$watchdogIsActive) {
1688
			$row['status'] = false;
1689
			$row[$sapi] = \App\Language::translate('LBL_NO');
1690
		}
1691
		return $row;
1692
	}
1693
1694
	/**
1695
	 * Validate register.
1696
	 *
1697
	 * @param string $name
1698
	 * @param array  $row
1699
	 * @param string $sapi
1700
	 *
1701
	 * @return array
1702
	 */
1703
	public static function validateRegister(string $name, array $row, string $sapi)
1704
	{
1705
		unset($name);
1706
		$row['status'] = true;
1707
		$row[$sapi] = \App\Language::translate('LBL_YES');
1708
		if (!\App\Cron::$registerIsActive) {
1709
			$row['status'] = false;
1710
			$row[$sapi] = \App\Language::translate('LBL_NO');
1711
		}
1712
		return $row;
1713
	}
1714
1715
	/**
1716
	 * Validate shop cache.
1717
	 *
1718
	 * @param string $name
1719
	 * @param array  $row
1720
	 * @param string $sapi
1721
	 *
1722
	 * @return array
1723
	 */
1724
	public static function validateShopCache(string $name, array $row, string $sapi)
1725
	{
1726
		unset($name);
1727
		$row['status'] = true;
1728
		$row[$sapi] = \App\Language::translate('LBL_YES');
1729
		if (!\App\Cron::$shopIsActive) {
1730
			$row['status'] = false;
1731
			$row[$sapi] = \App\Language::translate('LBL_NO');
1732
		}
1733
		return $row;
1734
	}
1735
1736
	/**
1737
	 * Validate webservice.
1738
	 *
1739
	 * @param string $name
1740
	 * @param array  $row
1741
	 * @param string $sapi
1742
	 *
1743
	 * @return array
1744
	 */
1745
	private static function validateWebservice(string $name, array $row, string $sapi)
1746
	{
1747
		unset($sapi);
1748
		try {
1749
			$response = (new \GuzzleHttp\Client(\App\RequestHttp::getOptions()))->request('HEAD', static::$crmUrl . $name, ['timeout' => 1, 'connect_timeout' => 1, 'verify' => false, 'http_errors' => false, 'allow_redirects' => false]);
0 ignored issues
show
Bug introduced by
Since $crmUrl is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $crmUrl to at least protected.
Loading history...
1750
			$row['status'] = 401 === $response->getStatusCode();
1751
		} catch (\Throwable $th) {
1752
			$row['status'] = false;
1753
		}
1754
		if (!\in_array('webservice', \Config\Api::$enabledServices)) {
0 ignored issues
show
Bug introduced by
The type Config\Api was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1755
			$row['mode'] = 'showWarnings';
1756
		}
1757
		return $row;
1758
	}
1759
1760
	/**
1761
	 * Get all configuration error values.
1762
	 *
1763
	 * @param bool $cache
1764
	 *
1765
	 * @return array
1766
	 */
1767
	public static function getAllErrors(bool $cache = false)
1768
	{
1769
		$fileCache = ROOT_DIRECTORY . '/app_data/ConfReport_AllErrors.php';
1770
		if ($cache && file_exists($fileCache) && filemtime($fileCache) > strtotime('-15 minute')) {
1771
			return require $fileCache;
1772
		}
1773
		$result = [];
1774
		foreach (static::getAll() as $category => $params) {
1775
			foreach ($params as $param => $data) {
1776
				if (!$data['status']) {
1777
					if (!isset($data['www']) && !isset($data['cron'])) {
1778
						$val = $data['status'];
1779
					} else {
1780
						$val = $data['www'] ?? $data['cron'];
1781
					}
1782
					$result[$category][$param] = $val;
1783
				}
1784
			}
1785
		}
1786
		if ($cache) {
1787
			\App\Utils::saveToFile($fileCache, $result, '', 0, true);
1788
		}
1789
		return $result;
1790
	}
1791
1792
	/**
1793
	 * Get configuration error values.
1794
	 *
1795
	 * @param string $type
1796
	 * @param bool   $returnMore
1797
	 *
1798
	 * @return array
1799
	 */
1800
	public static function getErrors(string $type, bool $returnMore = false): array
1801
	{
1802
		$result = [];
1803
		foreach (static::get($type, true) as $param => $data) {
1804
			if (!$data['status'] && (empty($data['mode']) || 'showErrors' === $data['mode'])) {
1805
				if (!isset($data['www']) && !isset($data['cron'])) {
1806
					$val = $data['status'];
1807
				} else {
1808
					$tmp = [];
1809
					if (isset($data['www'])) {
1810
						$tmp[] = 'www: ' . $data['www'];
1811
					}
1812
					if (isset($data['cron'])) {
1813
						$tmp[] = 'cron: ' . $data['cron'];
1814
					}
1815
					$val = \implode(' | ', $tmp) ?? '';
1816
				}
1817
				if ($returnMore) {
1818
					$data['val'] = $val;
1819
					$result[$param] = $data;
1820
				} else {
1821
					$result[$param] = $val;
1822
				}
1823
			}
1824
		}
1825
		return $result;
1826
	}
1827
1828
	/**
1829
	 * Get actual version of PHP.
1830
	 *
1831
	 * @return string[]
1832
	 */
1833
	public static function getNewestPhpVersion()
1834
	{
1835
		if (!\App\RequestUtil::isNetConnection()) {
1836
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string[].
Loading history...
1837
		}
1838
		$response = (new \GuzzleHttp\Client(\App\RequestHttp::getOptions()))->get('http://php.net/releases/index.php?json&max=7&version=7');
1839
		$data = array_keys((array) \App\Json::decode($response->getBody()));
1840
		natsort($data);
1841
		$ver = [];
1842
		foreach (array_reverse($data) as $row) {
1843
			$t = explode('.', $row);
1844
			array_pop($t);
1845
			$short = implode('.', $t);
1846
			if (!isset($ver[$short]) && version_compare($short, '7.2', '>') && version_compare($short, '8.0', '<')) {
1847
				$ver[$short] = $row;
1848
			}
1849
		}
1850
		return $ver;
1851
	}
1852
1853
	/**
1854
	 * Save environment variables.
1855
	 *
1856
	 * @return void
1857
	 */
1858
	public static function saveEnv(): void
1859
	{
1860
		$data = self::getEnv();
1861
		$key = \PHP_SAPI !== 'cli' ? 'www' : 'cli';
1862
		$data[$key]['sapi'] = \PHP_SAPI;
1863
		$data[$key]['operatingSystem'] = [
1864
			'machineType' => php_uname('m'),
1865
			'hostName' => php_uname('n'),
1866
			'release' => php_uname('r'),
1867
			'operatingSystem' => php_uname('s'),
1868
			'version' => php_uname('v'),
1869
		];
1870
		if (($db = \App\Db::getInstance()) && $db->getMasterPdo() && ($dbInfo = $db->getInfo())) {
1871
			$data[$key]['sql'] = [
1872
				'clientVersion' => $dbInfo['clientVersion'],
1873
				'serverVersion' => $dbInfo['serverVersion'],
1874
				'typeDb' => $dbInfo['typeDb'],
1875
				'version' => $dbInfo['version'] ?? '',
1876
				'versionComment' => $dbInfo['version_comment'] ?? '',
1877
				'versionSslLibrary' => $dbInfo['version_ssl_library'] ?? '',
1878
			];
1879
		}
1880
		if (isset($_SERVER['SERVER_SOFTWARE'])) {
1881
			$data[$key]['serverSoftware'] = $_SERVER['SERVER_SOFTWARE'];
1882
		}
1883
		if (isset($_SERVER['GATEWAY_INTERFACE'])) {
1884
			$data[$key]['gatewayInterface'] = $_SERVER['GATEWAY_INTERFACE'];
1885
		}
1886
		\App\Utils::saveToFile(ROOT_DIRECTORY . '/app_data/ConfReport_Env.php', $data, '', 0, true);
1887
	}
1888
1889
	/**
1890
	 * Get environment variables.
1891
	 *
1892
	 * @return array
1893
	 */
1894
	public static function getEnv(): array
1895
	{
1896
		$path = ROOT_DIRECTORY . '/app_data/ConfReport_Env.php';
1897
		return file_exists($path) ? (require $path) : [];
1898
	}
1899
}
1900