Issues (1358)

build/Builder.php (4 issues)

Labels
Severity
1
<?php
2
/**
3
 * @package    CleverStyle Framework
4
 * @subpackage Builder
5
 * @author     Nazar Mokrynskyi <[email protected]>
6
 * @license    0BSD
7
 */
8
namespace cs;
9
use
10
	Phar;
11
12
class Builder {
13
	/**
14
	 * @var string
15
	 */
16
	protected $root;
17
	/**
18
	 * @var string
19
	 */
20
	protected $target;
21
	/**
22
	 * @param string $root
23
	 * @param string $target
24
	 */
25 15
	public function __construct ($root, $target) {
26 15
		$this->root   = $root;
27 15
		$this->target = $target;
28
		/** @noinspection MkdirRaceConditionInspection */
29 15
		@mkdir($target);
30 15
	}
31
	/**
32
	 * @param string[]    $modules
33
	 * @param string[]    $themes
34
	 * @param null|string $suffix
35
	 *
36
	 * @return string
37
	 *
38
	 * @throws \UnexpectedValueException
39
	 * @throws \BadMethodCallException
40
	 */
41 8
	public function core ($modules = [], $themes = [], $suffix = null) {
42 8
		$suffix      = $suffix ? "_$suffix" : '';
43 8
		$version     = file_get_json("$this->root/modules/System/meta.json")['version'];
44 8
		$target_file = "$this->target/CleverStyle_Framework_$version$suffix.phar.php";
45 8
		if (file_exists($target_file)) {
46
			unlink($target_file);
47
		}
48 8
		$phar = new Phar($target_file);
49 8
		unset($target_file);
50 8
		$phar->startBuffering();
51 8
		$length = strlen("$this->root/");
52
		/** @noinspection ForeachSourceInspection */
53 8
		foreach (get_files_list("$this->root/install", false, 'f', '', true) as $file) {
54 8
			$phar->addFile("$this->root/install/$file", $file);
55
		}
56 8
		unset($file);
57 8
		$phar->addFile("$this->root/assets/img/logo.svg", 'logo.svg');
58
		/**
59
		 * Core files to be included into installation package
60
		 */
61 8
		$core_files = $this->get_core_files();
62
		/**
63
		 * Add modules that should be built-in into package
64
		 */
65 8
		$components_files = [];
66 8
		$modules          = $this->filter_and_add_components("$this->root/modules", $modules, $components_files);
67 8
		$phar->addFromString('modules.json', _json_encode($modules));
68
		/**
69
		 * Add themes that should be built-in into package
70
		 */
71 8
		$themes = $this->filter_and_add_components("$this->root/themes", $themes, $components_files);
72 8
		$phar->addFromString('themes.json', _json_encode($themes));
73
		/**
74
		 * Joining system and components files
75
		 */
76 8
		$core_files = array_merge($core_files, $components_files);
77
		/**
78
		 * Addition of files into package
79
		 */
80 8
		foreach ($core_files as $index => &$file) {
81 8
			$phar->addFile($file, "fs/$index");
82 8
			$file = substr($file, $length);
83
		}
84 8
		unset($index, $file);
85
		/**
86
		 * Addition of separate files into package
87
		 */
88 8
		$phar->addFromString(
89 8
			'languages.json',
90 8
			_json_encode(
91 8
				array_merge(
92 8
					_substr(get_files_list("$this->root/core/languages", '/^.*?\.php$/i', 'f'), 0, -4) ?: [],
0 ignored issues
show
It seems like _substr(get_files_list($...'f'), 0, -4) ?: array() can also be of type string; however, parameter $array1 of array_merge() does only seem to accept array, 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

92
					/** @scrutinizer ignore-type */ _substr(get_files_list("$this->root/core/languages", '/^.*?\.php$/i', 'f'), 0, -4) ?: [],
Loading history...
93 8
					_substr(get_files_list("$this->root/core/languages", '/^.*?\.json$/i', 'f'), 0, -5) ?: []
0 ignored issues
show
It seems like _substr(get_files_list($...'f'), 0, -5) ?: array() can also be of type string; however, parameter $array2 of array_merge() does only seem to accept null|array, 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

93
					/** @scrutinizer ignore-type */ _substr(get_files_list("$this->root/core/languages", '/^.*?\.json$/i', 'f'), 0, -5) ?: []
Loading history...
94
				)
95
			)
96
		);
97 8
		$phar->addFromString(
98 8
			'db_drivers.json',
99 8
			_json_encode(
100 8
				_substr(get_files_list("$this->root/core/drivers/DB", '/^[^_].*?\.php$/i', 'f'), 0, -4)
101
			)
102
		);
103
		/**
104
		 * Fixation of system files list (without components files), it is needed for future system updating
105
		 */
106 8
		$phar->addFromString(
107 8
			'fs.json',
108 8
			_json_encode(
109 8
				array_flip(
110 8
					array_diff(
111 8
						$core_files,
112 8
						_substr($components_files, $length)
0 ignored issues
show
It seems like _substr($components_files, $length) can also be of type string; however, parameter $array2 of array_diff() does only seem to accept array, 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

112
						/** @scrutinizer ignore-type */ _substr($components_files, $length)
Loading history...
113
					)
114
				)
115
			)
116
		);
117 8
		unset($components_files, $length);
118
		/**
119
		 * Addition of files, that are needed only for installation
120
		 */
121 8
		$phar->addFromString('fs/'.count($core_files), $this->get_htaccess());
122 8
		$core_files[] = '.htaccess';
123 8
		$phar->addFile("$this->root/config/main.php", 'fs/'.count($core_files));
124 8
		$core_files[] = 'config/main.php';
125 8
		$phar->addFile("$this->root/favicon.ico", 'fs/'.count($core_files));
126 8
		$core_files[] = 'favicon.ico';
127 8
		$phar->addFile("$this->root/.gitignore", 'fs/'.count($core_files));
128 8
		$core_files[] = '.gitignore';
129
		/**
130
		 * Flip array to have direct access to files by name during extracting and installation, and fixing of files list for installation
131
		 */
132 8
		$phar->addFromString(
133 8
			'fs_installer.json',
134 8
			_json_encode(
135 8
				array_flip($core_files)
136
			)
137
		);
138 8
		unset($core_files);
139
		/**
140
		 * Addition of supplementary files, that are needed directly for installation process: installer with GUI interface, readme, license, some additional
141
		 * information about available languages, themes, current version of system
142
		 */
143 8
		$phar->addFile("$this->root/modules/System/meta.json", 'meta.json');
144 8
		$phar->setStub(
145
		/** @lang PHP */
146
			<<<STUB
147 8
<?php
148
if (version_compare(PHP_VERSION, '7.0', '<')) {
149
	echo 'CleverStyle Framework requires PHP 7.0 or higher';
150
	return;
151
}
152
153
if (php_sapi_name() == 'cli') {
154
	Phar::mapPhar('cleverstyle_framework.phar');
155
	include 'phar://cleverstyle_framework.phar/cli.php';
156
} else {
157
	Phar::webPhar(null, 'web.php');
158
}
159
__HALT_COMPILER();
160
STUB
161
		);
162 8
		$phar->stopBuffering();
163 8
		return "Done! CleverStyle Framework $version";
164
	}
165
	/**
166
	 * Get array of files
167
	 *
168
	 * @return string[]
169
	 */
170 8
	protected function get_core_files () {
171
		$files_to_include = [
172 8
			"$this->root/assets",
173 8
			"$this->root/blocks/.gitkept",
174 8
			"$this->root/core",
175 8
			"$this->root/custom",
176 8
			"$this->root/modules/System",
177 8
			"$this->root/storage/.htaccess",
178 8
			"$this->root/storage/public_cache/.htaccess",
179 8
			"$this->root/storage/public/.htaccess",
180 8
			"$this->root/storage/temp/.htaccess",
181 8
			"$this->root/themes/CleverStyle",
182 8
			"$this->root/bower.json",
183 8
			"$this->root/cli",
184 8
			"$this->root/composer.json",
185 8
			"$this->root/composer.lock",
186 8
			"$this->root/index.php",
187 8
			"$this->root/package.json"
188
		];
189 8
		$files            = [];
190 8
		foreach ($files_to_include as $s) {
191 8
			if (is_file($s)) {
192 8
				$files[] = $s;
193 8
			} elseif (is_dir($s)) {
194
				/** @noinspection SlowArrayOperationsInLoopInspection */
195 8
				$files = array_merge(
196 8
					$files,
197 8
					get_files_list($s, false, 'f', true, true, false, false, true)
198
				);
199
			}
200
		}
201 8
		return $files;
202
	}
203
	/**
204
	 * @param string   $dir
205
	 * @param string[] $components
206
	 * @param string[] $components_files
207
	 *
208
	 * @return string[]
209
	 */
210 8
	protected function filter_and_add_components ($dir, $components, &$components_files) {
211 8
		$components = array_filter(
212 8
			$components,
213 8
			function ($component) use ($dir, &$components_files) {
214 1
				return $this->get_component_files("$dir/$component", $components_files);
215 8
			}
216
		);
217 8
		sort($components);
218 8
		return $components;
219
	}
220
	/**
221
	 * @param string   $component_root
222
	 * @param string[] $files Array, where new files will be appended
223
	 *
224
	 * @return bool
225
	 */
226 1
	protected function get_component_files ($component_root, &$files) {
227
		/**
228
		 * Do not allow building System module and CleverStyle theme
229
		 */
230 1
		if (in_array(basename($component_root), ['System', 'CleverStyle'])) {
231 1
			return false;
232
		}
233
		/**
234
		 * Components without meta.json also not allowed
235
		 */
236 1
		if (!file_exists("$component_root/meta.json")) {
237 1
			return false;
238
		}
239 1
		@unlink("$component_root/fs.json");
240 1
		$local_files = get_files_list($component_root, false, 'f', true, true, false, false, true);
241 1
		$files       = array_merge($files, $local_files);
242 1
		file_put_json(
243 1
			"$component_root/fs.json",
244 1
			array_values(
245 1
				_substr(
0 ignored issues
show
It seems like _substr($local_files, st...n($component_root.'/')) can also be of type string; however, parameter $input of array_values() does only seem to accept array, 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

245
				/** @scrutinizer ignore-type */ _substr(
Loading history...
246 1
					$local_files,
247 1
					strlen("$component_root/")
248
				)
249
			)
250
		);
251 1
		$files[] = "$component_root/fs.json";
252 1
		return true;
253
	}
254
	/**
255
	 * @return string
256
	 */
257 8
	protected function get_htaccess () {
258
		/** @lang ApacheConfig */
259
		return <<<HTACCESS
260 8
AddDefaultCharset utf-8
261
Options -Indexes -Multiviews +FollowSymLinks
262
IndexIgnore *.php *.pl *.cgi *.htaccess *.htpasswd
263
FileETag None
264
265
RewriteEngine On
266
RewriteBase /
267
268
<FilesMatch ".*/.*">
269
	Options -FollowSymLinks
270
</FilesMatch>
271
<FilesMatch "\.(css|js|gif|jpg|jpeg|png|ico|svg|svgz|ttc|ttf|otf|woff|woff2|eot)$">
272
	RewriteEngine Off
273
</FilesMatch>
274
<FilesMatch "\.(css|js|gif|jpg|jpeg|png|ico|svg|svgz|ttc|ttf|otf|woff|woff2|eot|html)$">
275
	<ifModule mod_expires.c>
276
		ExpiresActive On
277
		ExpiresDefault "access plus 1 month"
278
	</ifModule>
279
	<ifModule mod_headers.c>
280
		Header set Cache-Control "max-age=2592000, immutable"
281
	</ifModule>
282
</FilesMatch>
283
284
RewriteRule .* index.php
285
HTACCESS;
286
	}
287
	/**
288
	 * @param string      $module
289
	 * @param null|string $suffix
290
	 *
291
	 * @return string
292
	 */
293 4
	public function module ($module, $suffix = null) {
294 4
		if ($module == 'System') {
295 1
			return "Can't build module, System module is a part of core, it is not necessary to build it as separate module";
296
		}
297 3
		return $this->generic_package_creation("$this->root/modules/$module", $suffix);
298
	}
299
	/**
300
	 * @param string      $theme
301
	 * @param null|string $suffix
302
	 *
303
	 * @return string
304
	 */
305 3
	public function theme ($theme, $suffix = null) {
306 3
		if ($theme == 'CleverStyle') {
307 1
			return "Can't build theme, CleverStyle theme is a part of core, it is not necessary to build it as separate theme";
308
		}
309 2
		return $this->generic_package_creation("$this->root/themes/$theme", $suffix);
310
	}
311
	/**
312
	 * @param string      $source_dir
313
	 * @param null|string $suffix
314
	 *
315
	 * @return string
316
	 */
317 5
	protected function generic_package_creation ($source_dir, $suffix = null) {
318 5
		if (!file_exists("$source_dir/meta.json")) {
319 1
			$component = basename($source_dir);
320 1
			return "Can't build $component, meta information (meta.json) not found";
321
		}
322 4
		$meta = file_get_json("$source_dir/meta.json");
323 4
		$type = '';
324 4
		$Type = '';
325 4
		switch ($meta['category']) {
326 4
			case 'modules':
327 2
				$type = 'module_';
328 2
				$Type = 'Module';
329 2
				break;
330 2
			case 'themes':
331 2
				$type = 'theme_';
332 2
				$Type = 'Theme';
333 2
				break;
334
		}
335 4
		$suffix      = $suffix ? "_$suffix" : '';
336 4
		$target_file = "$this->target/$type$meta[package]_$meta[version]$suffix.phar.php";
337 4
		if (file_exists($target_file)) {
338
			unlink($target_file);
339
		}
340 4
		$phar = new Phar($target_file);
341 4
		unset($target_file);
342 4
		$phar->startBuffering();
343 4
		@unlink("$source_dir/fs.json");
344 4
		$files  = get_files_list($source_dir, false, 'f', true, true, false, false, true);
345 4
		$length = strlen("$source_dir/");
346
		/** @noinspection ForeachSourceInspection */
347 4
		foreach ($files as $index => &$file) {
348 4
			$phar->addFile($file, "fs/$index");
349 4
			$file = substr($file, $length);
350
		}
351 4
		unset($index, $file, $length);
352
		/**
353
		 * Flip array to have direct access to files by name during extraction
354
		 */
355 4
		$phar->addFromString(
356 4
			'fs.json',
357 4
			_json_encode(
358 4
				array_flip($files)
359
			)
360
		);
361 4
		unset($files);
362 4
		$phar->addFile("$source_dir/meta.json", 'meta.json');
363 4
		$readme = false;
364 4
		if (file_exists("$source_dir/readme.html")) {
365
			$phar->addFile("$source_dir/readme.html", 'readme.html');
366
			$readme = 'readme.html';
367 4
		} elseif (file_exists("$source_dir/readme.txt")) {
368
			$phar->addFile("$source_dir/readme.txt", 'readme.txt');
369
			$readme = 'readme.txt';
370
		}
371 4
		if ($readme) {
372
			$phar->setStub("<?php Phar::webPhar(null, '$readme'); __HALT_COMPILER();");
373
		} else {
374 4
			$phar->addFromString('index.html', isset($meta['description']) ? $meta['description'] : $meta['package']);
375 4
			$phar->setStub("<?php Phar::webPhar(null, 'index.html'); __HALT_COMPILER();");
376
		}
377 4
		$phar->stopBuffering();
378 4
		return "Done! $Type $meta[package] $meta[version]";
379
	}
380
}
381