Completed
Push — master ( 67d50f...8a7d08 )
by Nazar
04:56
created

Builder::get_htaccess()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 26
ccs 2
cts 2
cp 1
crap 1
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package    CleverStyle Framework
4
 * @subpackage Builder
5
 * @author     Nazar Mokrynskyi <[email protected]>
6
 * @copyright  Copyright (c) 2011-2016, Nazar Mokrynskyi
7
 * @license    MIT License, see license.txt
8
 */
9
namespace cs;
10
use
11
	Phar;
12
13
class Builder {
14
	/**
15
	 * @var string
16
	 */
17
	protected $root;
18
	/**
19
	 * @var string
20
	 */
21
	protected $target;
22
	/**
23
	 * @param string $root
24
	 * @param string $target
25
	 */
26 4
	function __construct ($root, $target) {
27 4
		$this->root   = $root;
28 4
		$this->target = $target;
29 4
		@mkdir($target);
30 4
	}
31
	/**
32
	 * @param string[]    $modules
33
	 * @param string[]    $themes
34
	 * @param null|string $suffix
35
	 *
36
	 * @return string
37
	 */
38 4
	function core ($modules = [], $themes = [], $suffix = null) {
39 4
		$suffix      = $suffix ? "_$suffix" : '';
40 4
		$version     = file_get_json("$this->root/components/modules/System/meta.json")['version'];
41 4
		$target_file = "$this->target/CleverStyle_Framework_$version$suffix.phar.php";
42 4
		if (file_exists($target_file)) {
43
			unlink($target_file);
44
		}
45 4
		$phar = new Phar($target_file);
46 4
		unset($target_file);
47 4
		$phar->startBuffering();
48 4
		$length = strlen("$this->root/");
49 4
		foreach (get_files_list("$this->root/install", false, 'f', '', true) as $file) {
50 4
			$phar->addFile("$this->root/install/$file", $file);
51
		}
52 4
		unset($file);
53 4
		$phar->addFile("$this->root/includes/img/logo.svg", 'logo.svg');
54
		/**
55
		 * Core files to be included into installation package
56
		 */
57 4
		$core_files = $this->get_core_files();
58
		/**
59
		 * Add modules that should be built-in into package
60
		 */
61 4
		$components_files = [];
62 4
		$modules          = $this->filter_and_add_components("$this->root/components/modules", $modules, $components_files);
63 4
		$phar->addFromString('modules.json', _json_encode($modules));
64
		/**
65
		 * Add themes that should be built-in into package
66
		 */
67 4
		$themes = $this->filter_and_add_components("$this->root/themes", $themes, $components_files);
68 4
		$phar->addFromString('themes.json', _json_encode($themes));
69
		/**
70
		 * Joining system and components files
71
		 */
72 4
		$core_files = array_merge($core_files, $components_files);
73
		/**
74
		 * Addition of files into package
75
		 */
76 4
		foreach ($core_files as $index => &$file) {
77 4
			$phar->addFile($file, "fs/$index");
78 4
			$file = substr($file, $length);
79
		}
80 4
		unset($index, $file);
81
		/**
82
		 * Addition of separate files into package
83
		 */
84 4
		$phar->addFromString(
85 4
			'languages.json',
86
			_json_encode(
87
				array_merge(
88 4
					_substr(get_files_list("$this->root/core/languages", '/^.*?\.php$/i', 'f'), 0, -4) ?: [],
89 4
					_substr(get_files_list("$this->root/core/languages", '/^.*?\.json$/i', 'f'), 0, -5) ?: []
90
				)
91
			)
92
		);
93 4
		$phar->addFromString(
94 4
			'db_engines.json',
95
			_json_encode(
96 4
				_substr(get_files_list("$this->root/core/engines/DB", '/^[^_].*?\.php$/i', 'f'), 0, -4)
97
			)
98
		);
99
		/**
100
		 * Fixation of system files list (without components files), it is needed for future system updating
101
		 */
102 4
		$phar->addFromString(
103 4
			'fs.json',
104
			_json_encode(
105
				array_flip(
106
					array_diff(
107
						$core_files,
108
						_substr($components_files, $length)
109
					)
110
				)
111
			)
112
		);
113 4
		unset($components_files, $length);
114
		/**
115
		 * Addition of files, that are needed only for installation
116
		 */
117 4
		$phar->addFromString('fs/'.count($core_files), $this->get_htaccess());
118 4
		$core_files[] = '.htaccess';
119 4
		$phar->addFile("$this->root/config/main.php", 'fs/'.count($core_files));
120 4
		$core_files[] = 'config/main.php';
121 4
		$phar->addFile("$this->root/favicon.ico", 'fs/'.count($core_files));
122 4
		$core_files[] = 'favicon.ico';
123 4
		$phar->addFile("$this->root/.gitignore", 'fs/'.count($core_files));
124 4
		$core_files[] = '.gitignore';
125
		/**
126
		 * Flip array to have direct access to files by name during extracting and installation, and fixing of files list for installation
127
		 */
128 4
		$phar->addFromString(
129 4
			'fs_installer.json',
130
			_json_encode(
131
				array_flip($core_files)
132
			)
133
		);
134 4
		unset($core_files);
135
		/**
136
		 * Addition of supplementary files, that are needed directly for installation process: installer with GUI interface, readme, license, some additional
137
		 * information about available languages, themes, current version of system
138
		 */
139 4
		$phar->addFile("$this->root/license.txt", 'license.txt');
140 4
		$phar->addFile("$this->root/components/modules/System/meta.json", 'meta.json');
141 4
		$phar->setStub(
142
		/** @lang PHP */
143
			<<<STUB
144
<?php
145
if (version_compare(PHP_VERSION, '5.6', '<')) {
146
	echo 'CleverStyle Framework require PHP 5.6 or higher';
147
	return;
148
}
149
150
if (PHP_SAPI == 'cli') {
151
	Phar::mapPhar('cleverstyle_framework.phar');
152
	include 'phar://cleverstyle_framework.phar/cli.php';
153
} else {
154
	Phar::webPhar(null, 'web.php');
155
}
156 4
__HALT_COMPILER();
157
STUB
158
		);
159 4
		$phar->stopBuffering();
160 4
		return "Done! CleverStyle Framework $version";
161
	}
162
	/**
163
	 * Get array of files
164
	 *
165
	 * @return string[]
166
	 */
167 4
	protected function get_core_files () {
168
		$files_to_include = [
169 4
			"$this->root/components/modules/System",
170 4
			"$this->root/components/blocks/.gitkept",
171 4
			"$this->root/core",
172 4
			"$this->root/custom",
173 4
			"$this->root/includes",
174 4
			"$this->root/templates",
175 4
			"$this->root/themes/CleverStyle",
176 4
			"$this->root/bower.json",
177 4
			"$this->root/cli",
178 4
			"$this->root/composer.json",
179 4
			"$this->root/composer.lock",
180 4
			"$this->root/index.php",
181 4
			"$this->root/license.txt",
182 4
			"$this->root/package.json",
183 4
			"$this->root/Storage.php"
184
		];
185 4
		$files            = [];
186 4
		foreach ($files_to_include as $s) {
187 4
			if (is_file($s)) {
188 4
				$files[] = $s;
189 4
			} elseif (is_dir($s)) {
190
				/** @noinspection SlowArrayOperationsInLoopInspection */
191 4
				$files = array_merge(
192
					$files,
193 4
					get_files_list($s, false, 'f', true, true, false, false, true)
194
				);
195
			}
196
		}
197 4
		return $files;
198
	}
199
	/**
200
	 * @param string   $dir
201
	 * @param string[] $components
202
	 * @param string[] $components_files
203
	 *
204
	 * @return string[]
205
	 */
206 4
	protected function filter_and_add_components ($dir, $components, &$components_files) {
207 4
		$components = array_filter(
208
			$components,
209 4
			function ($component) use ($dir, &$components_files) {
210
				return $this->get_component_files("$dir/$component", $components_files);
211 4
			}
212
		);
213 4
		sort($components);
214 4
		return $components;
215
	}
216
	/**
217
	 * @param string   $component_root
218
	 * @param string[] $files Array, where new files will be appended
219
	 *
220
	 * @return bool
221
	 */
222
	protected function get_component_files ($component_root, &$files) {
223
		/**
224
		 * Do not allow building System module and CleverStyle theme
225
		 */
226
		if (in_array(basename($component_root), ['System', 'CleverStyle'])) {
227
			return false;
228
		}
229
		/**
230
		 * Components without meta.json also not allowed
231
		 */
232
		if (!file_exists("$component_root/meta.json")) {
233
			return false;
234
		}
235
		@unlink("$component_root/fs.json");
236
		$local_files = get_files_list($component_root, false, 'f', true, true, false, false, true);
237
		$files       = array_merge($files, $local_files);
238
		file_put_json(
239
			"$component_root/fs.json",
240
			array_values(
241
				_substr(
242
					$local_files,
243
					strlen("$component_root/")
244
				)
245
			)
246
		);
247
		$files[] = "$component_root/fs.json";
248
		return true;
249
	}
250
	/**
251
	 * @return string
252
	 */
253 4
	protected function get_htaccess () {
254
		/** @lang ApacheConfig */
255
		return <<<HTACCESS
256
AddDefaultCharset utf-8
257
Options -Indexes -Multiviews +FollowSymLinks
258
IndexIgnore *.php *.pl *.cgi *.htaccess *.htpasswd
259
260
RewriteEngine On
261
RewriteBase /
262
263
<FilesMatch ".*/.*">
264
	Options -FollowSymLinks
265
</FilesMatch>
266
<FilesMatch "\.(css|js|gif|jpg|jpeg|png|ico|svg|svgz|ttc|ttf|otf|woff|woff2|eot)$">
267
	RewriteEngine Off
268
</FilesMatch>
269
<Files license.txt>
270
	RewriteEngine Off
271
</Files>
272
#<Files Storage.php>
273
#	RewriteEngine Off
274
#</Files>
275
276 4
RewriteRule .* index.php
277
HTACCESS;
278
	}
279
	/**
280
	 * @param string      $module
281
	 * @param null|string $suffix
282
	 *
283
	 * @return string
284
	 */
285
	function module ($module, $suffix = null) {
286
		if ($module == 'System') {
287
			return "Can't build module, System module is a part of core, it is not necessary to build it as separate module";
288
		}
289
		return $this->generic_package_creation("$this->root/components/modules/$module", $suffix);
290
	}
291
	/**
292
	 * @param string      $theme
293
	 * @param null|string $suffix
294
	 *
295
	 * @return string
296
	 */
297
	function theme ($theme, $suffix = null) {
298
		if ($theme == 'CleverStyle') {
299
			return "Can't build theme, CleverStyle theme is a part of core, it is not necessary to build it as separate theme";
300
		}
301
		return $this->generic_package_creation("$this->root/themes/$theme", $suffix);
302
	}
303
	protected function generic_package_creation ($source_dir, $suffix = null) {
304
		if (!file_exists("$source_dir/meta.json")) {
305
			$component = basename($source_dir);
306
			return "Can't build $component, meta information (meta.json) not found";
307
		}
308
		$meta = file_get_json("$source_dir/meta.json");
309
		$type = '';
310
		$Type = '';
311
		switch ($meta['category']) {
312
			case 'modules':
313
				$type = 'module_';
314
				$Type = 'Module';
315
				break;
316
			case 'themes':
317
				$type = 'theme_';
318
				$Type = 'Theme';
319
				break;
320
		}
321
		$suffix      = $suffix ? "_$suffix" : '';
322
		$target_file = "$this->target/$type$meta[package]_$meta[version]$suffix.phar.php";
323
		if (file_exists($target_file)) {
324
			unlink($target_file);
325
		}
326
		$phar = new Phar($target_file);
327
		unset($target_file);
328
		$phar->startBuffering();
329
		@unlink("$source_dir/fs.json");
330
		$files  = get_files_list($source_dir, false, 'f', true, true, false, false, true);
331
		$length = strlen("$source_dir/");
332
		foreach ($files as $index => &$file) {
333
			$phar->addFile($file, "fs/$index");
334
			$file = substr($file, $length);
335
		}
336
		unset($index, $file, $length);
337
		/**
338
		 * Flip array to have direct access to files by name during extraction
339
		 */
340
		$phar->addFromString(
341
			'fs.json',
342
			_json_encode(
343
				array_flip($files)
344
			)
345
		);
346
		unset($files);
347
		$phar->addFile("$source_dir/meta.json", 'meta.json');
348
		$readme = false;
349
		if (file_exists("$source_dir/readme.html")) {
350
			$phar->addFile("$source_dir/readme.html", 'readme.html');
351
			$readme = 'readme.html';
352
		} elseif (file_exists("$source_dir/readme.txt")) {
353
			$phar->addFile("$source_dir/readme.txt", 'readme.txt');
354
			$readme = 'readme.txt';
355
		}
356
		if ($readme) {
357
			$phar->setStub("<?php Phar::webPhar(null, '$readme'); __HALT_COMPILER();");
358
		} else {
359
			$phar->addFromString('index.html', isset($meta['description']) ? $meta['description'] : $meta['package']);
360
			$phar->setStub("<?php Phar::webPhar(null, 'index.html'); __HALT_COMPILER();");
361
		}
362
		$phar->stopBuffering();
363
		return "Done! $Type $meta[package] $meta[version]";
364
	}
365
}
366