testSystemCompatibility()   B
last analyzed

Complexity

Conditions 6
Paths 12

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 20
c 1
b 0
f 0
nc 12
nop 0
dl 0
loc 33
rs 8.9777
1
<?php
2
3
namespace Epesi\Core\System;
4
5
use atk4\ui\View;
6
use Illuminate\Support\Facades\DB;
7
use Illuminate\Support\Facades\Schema;
8
use Illuminate\Database\Schema\Blueprint;
9
use atk4\ui\Columns;
10
use atk4\ui\Header;
11
12
class SystemEnvironmentOverview extends View
13
{
14
	protected $systemRequirements = [
15
			'memory_limit' => '32M',
16
			'upload_max_filesize' => '8M',
17
			'post_max_size' => '16M'
18
	];
19
			
20
	protected $extensionRequirements = [
21
			'extension_loaded' => [
22
					'curl' => [
23
							'name' => 'cURL library',
24
							'severity' => 1
25
					]
26
			],
27
			'class_exists' => [
28
					'ZipArchive' => [
29
							'name' => 'ZIPArchive library',
30
							'severity' => 2
31
					]
32
			],
33
			'function_exists' => [
34
					'imagecreatefromjpeg' => [
35
							'name' => 'PHP GD extension - image processing',
36
							'severity' => 2
37
					]
38
			],
39
			'ini_get' => [
40
					'allow_url_fopen' => [
41
							'name' => 'Remote file_get_contents()',
42
							'severity' => 2
43
					]
44
			]
45
	];
46
47
	protected static function severityMap()
48
	{
49
		return [
50
				[
51
						'color' => 'green', 
52
						'result' => __('Good')
53
				], 
54
				[
55
						'color' => 'yellow', 
56
						'result' => __('Recommended')
57
				], 
58
				[
59
						'color' => 'red', 
60
						'result' => __('Critical')
61
				]
62
		];
63
	}
64
		
65
	public function renderView(): void
66
	{
67
		$this->addClass('ui grid');
68
		
69
		$columns = Columns::addTo($this);
70
71
		$this->addLegend($columns->addRow());
72
		
73
		$column = $columns->addColumn()->setStyle('min-width', '350px');
74
		
75
		$grid = View::addTo($column, ['class' => ['ui grid']]);
76
		
77
		$this->addGroupResults(__('System'), $this->testSystemCompatibility(), $grid);
78
		
79
		$this->addGroupResults(__('Extensions'), $this->testRequiredExtensions(), $grid);
80
		
81
		$column = $columns->addColumn()->setStyle('min-width', '350px');
82
		
83
		$grid = View::addTo($column, ['class' => ['ui grid']]);
84
		
85
		$this->addGroupResults(__('Database'), $this->testDatabasePermissions(), $grid);
86
87
		parent::renderView();
88
	}
89
	
90
	public function addLegend($container = null)
91
	{
92
		$container = $container?: $this;
93
		
94
		$legend = \atk4\ui\Header::addTo($container, [__('Scan of Environment Parameters')])->setStyle('margin-left', '2em');
0 ignored issues
show
Unused Code introduced by
The assignment to $legend is dead and can be removed.
Loading history...
95
		$legend = View::addTo($container)->setStyle('margin-left', 'auto');
96
		
97
		foreach (self::severityMap() as $severity) {
98
			\atk4\ui\Label::addTo($legend, [$severity['result'], 'class' => ["$severity[color] horizontal"]]);
99
		}
100
	}
101
	
102
	public function addGroupResults($group, $testResults = [], $container = null)
103
	{
104
		if (! $testResults) return;
105
		
106
		$container = $container?: $this;
107
		
108
		$container->add([Header::class, $group]);
0 ignored issues
show
Bug introduced by
array(atk4\ui\Header::class, $group) of type array<integer,mixed|string> is incompatible with the type atk4\ui\View expected by parameter $object of atk4\ui\View::add(). ( Ignorable by Annotation )

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

108
		$container->add(/** @scrutinizer ignore-type */ [Header::class, $group]);
Loading history...
109
		
110
		$severityMap = self::severityMap();
111
		
112
		foreach ($testResults as $test) {
113
			$color = $severityMap[$test['severity']]['color'];
114
			$result = $test['result']?? $severityMap[$test['severity']]['result'];
115
116
			$row = View::addTo($container, ['class' => ['row']]);
117
			View::addTo($row, [$test['name'], 'class' => ['nine wide column']]);
118
			View::addTo($row, ['class' => ['six wide right aligned column']])->add([\atk4\ui\Label::class, $result, 'class' => ["$color horizontal"]]);
119
		}
120
	}
121
	
122
	protected function testDatabasePermissions()
123
	{
124
		ob_start();
125
		
126
		@Schema::dropIfExists('test');
127
128
		@Schema::create('test', function (Blueprint $table) {
129
			$table->increments('id');
130
		});
131
			
132
		$create = Schema::hasTable('test');
133
				
134
		@Schema::table('test', function (Blueprint $table) {
135
			$table->addColumn('TEXT', 'field_name');
136
		});
137
		
138
		$alter = Schema::hasColumn('test', 'field_name');
139
		
140
		$insert = @DB::insert('INSERT INTO test (field_name) VALUES (\'test\')');
141
		$update = @DB::update('UPDATE test SET field_name=1 WHERE id=1');
142
		$delete = @DB::delete('DELETE FROM test');
143
		@Schema::dropIfExists('test');
144
		
145
		$drop = ! Schema::hasTable('test');
146
		
147
		ob_end_clean();
148
		
149
		$result = compact('create', 'alter', 'insert', 'update', 'delete', 'drop');
150
		
151
		array_walk($result, function(& $testResult, $testName) {
152
			$testResult = [
153
					'name' => __(':permission permission', ['permission' => strtoupper($testName)]),
154
					'result' => $testResult? __('OK'): __('Failed'),
155
					'severity' => $testResult? 0: 2
156
			];
157
		});		
158
		
159
		return $result;
160
	}
161
	
162
	protected function unitToInt($string)
163
	{
164
		return (int) preg_replace_callback('/(\-?\d+)(.?)/', function ($m) {
165
			return $m[1] * pow(1024, strpos('BKMG', $m[2]));
166
		}, strtoupper($string));
167
	}
168
	
169
	protected function testSystemCompatibility()
170
	{
171
		$ret = [];
172
		
173
		if ($requiredPhpVersion = $this->getApp()->packageInfo()['require']['php']?? null) {
174
			$ret[] = [
175
					'name' => __('PHP version required :version', ['version' => $requiredPhpVersion]),
176
					'result' => PHP_VERSION,
177
					'severity' => version_compare(PHP_VERSION, $requiredPhpVersion, '>=')? 0: 2
178
			];
179
		}
180
		
181
		foreach ($this->systemRequirements as $iniKey => $requiredSize) {
182
			$actualSize = ini_get($iniKey);
183
			$actualSizeBytes = $this->unitToInt($actualSize);
184
			$requiredSizeBytes = $this->unitToInt($requiredSize);
185
			
186
			$severity = 0;
187
			if ($actualSizeBytes < $requiredSizeBytes) {
188
				$severity = 2;
189
			}
190
			elseif ($actualSizeBytes == $requiredSizeBytes) {
191
				$severity = 1;
192
			}
193
			
194
			$ret[] = [
195
					'name' => ucwords(str_ireplace('_', ' ', $iniKey)) . ' > ' . $requiredSize,
0 ignored issues
show
Bug introduced by
It seems like str_ireplace('_', ' ', $iniKey) can also be of type array; however, parameter $string of ucwords() 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

195
					'name' => ucwords(/** @scrutinizer ignore-type */ str_ireplace('_', ' ', $iniKey)) . ' > ' . $requiredSize,
Loading history...
196
					'result' => $actualSize,
197
					'severity' => $severity
198
			];
199
		}
200
		
201
		return $ret;
202
	}
203
	
204
	protected function testRequiredExtensions()
205
	{
206
		$ret = [];
207
		
208
		foreach ($this->extensionRequirements as $callback => $extensions) {
209
			foreach ($extensions as $extension => $test) {
210
				$result = $callback($extension);
211
				
212
				$ret[] = array_merge($test, [
213
						'result' => $result? __('OK'): __('Missing'),
214
						'severity' => $result? 0: $test['severity']
215
				]);
216
			}
217
		}
218
		
219
		return $ret;
220
	}
221
	
222
}
223