1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @package CleverStyle CMS |
4
|
|
|
* @subpackage System module |
5
|
|
|
* @category modules |
6
|
|
|
* @author Nazar Mokrynskyi <[email protected]> |
7
|
|
|
* @copyright Copyright (c) 2015-2016, Nazar Mokrynskyi |
8
|
|
|
* @license MIT License, see license.txt |
9
|
|
|
*/ |
10
|
|
|
namespace cs\modules\System\api\Controller\admin; |
11
|
|
|
use |
12
|
|
|
cs\Cache as System_cache, |
13
|
|
|
cs\Config, |
14
|
|
|
cs\Event, |
15
|
|
|
cs\ExitException, |
16
|
|
|
cs\Language\Prefix, |
17
|
|
|
cs\Page, |
18
|
|
|
cs\Permission, |
19
|
|
|
cs\Session, |
20
|
|
|
cs\modules\System\Packages_manipulation; |
21
|
|
|
|
22
|
|
|
trait modules { |
23
|
|
|
/** |
24
|
|
|
* @param \cs\Request $Request |
25
|
|
|
* |
26
|
|
|
* @throws ExitException |
27
|
|
|
*/ |
28
|
|
|
static function admin_modules_get ($Request) { |
29
|
|
|
if ($Request->route_path(3)) { |
30
|
|
|
$route_path = $Request->route_path; |
31
|
|
|
switch ($route_path[3]) { |
32
|
|
|
/** |
33
|
|
|
* Get dependent packages for module |
34
|
|
|
*/ |
35
|
|
|
case 'dependent_packages': |
36
|
|
|
static::get_dependent_packages_for_module($route_path[2]); |
37
|
|
|
break; |
38
|
|
|
/** |
39
|
|
|
* Get dependencies for module (packages, databases, storages) |
40
|
|
|
*/ |
41
|
|
|
case 'dependencies': |
42
|
|
|
static::get_dependencies_for_module($route_path[2]); |
43
|
|
|
break; |
44
|
|
|
/** |
45
|
|
|
* Get dependencies for module during update |
46
|
|
|
*/ |
47
|
|
|
case 'update_dependencies': |
48
|
|
|
static::get_update_dependencies_for_module($route_path[2]); |
49
|
|
|
break; |
50
|
|
|
/** |
51
|
|
|
* Get mapping of named module's databases to indexes of system databases |
52
|
|
|
*/ |
53
|
|
|
case 'db': |
54
|
|
|
static::get_module_databases($route_path[2]); |
55
|
|
|
break; |
56
|
|
|
/** |
57
|
|
|
* Get mapping of named module's storages to indexes of system storages |
58
|
|
|
*/ |
59
|
|
|
case 'storage': |
60
|
|
|
static::get_module_storages($route_path[2]); |
61
|
|
|
break; |
62
|
|
|
default: |
63
|
|
|
throw new ExitException(400); |
64
|
|
|
} |
65
|
|
|
} elseif ($Request->route_path(2) == 'default') { |
66
|
|
|
/** |
67
|
|
|
* Get current default module |
68
|
|
|
*/ |
69
|
|
|
static::get_default_module(); |
70
|
|
|
} else { |
71
|
|
|
/** |
72
|
|
|
* Get array of modules in extended form |
73
|
|
|
*/ |
74
|
|
|
static::get_modules_list(); |
75
|
|
|
} |
76
|
|
|
} |
77
|
|
|
/** |
78
|
|
|
* @param string $module |
79
|
|
|
* |
80
|
|
|
* @throws ExitException |
81
|
|
|
*/ |
82
|
|
|
protected static function get_dependent_packages_for_module ($module) { |
83
|
|
|
if (!Config::instance()->module($module)) { |
84
|
|
|
throw new ExitException(404); |
85
|
|
|
} |
86
|
|
|
$meta_file = MODULES."/$module/meta.json"; |
87
|
|
|
Page::instance()->json( |
88
|
|
|
file_exists($meta_file) ? Packages_manipulation::get_dependent_packages(file_get_json($meta_file)) : [] |
89
|
|
|
); |
90
|
|
|
} |
91
|
|
|
/** |
92
|
|
|
* @param string $module |
93
|
|
|
* |
94
|
|
|
* @throws ExitException |
95
|
|
|
*/ |
96
|
|
|
protected static function get_dependencies_for_module ($module) { |
97
|
|
|
if (!Config::instance()->module($module)) { |
98
|
|
|
throw new ExitException(404); |
99
|
|
|
} |
100
|
|
|
$meta_file = MODULES."/$module/meta.json"; |
101
|
|
|
Page::instance()->json( |
102
|
|
|
file_exists($meta_file) ? Packages_manipulation::get_dependencies(file_get_json($meta_file)) : [] |
103
|
|
|
); |
104
|
|
|
} |
105
|
|
|
/** |
106
|
|
|
* @param string $module |
107
|
|
|
* |
108
|
|
|
* @throws ExitException |
109
|
|
|
*/ |
110
|
|
|
protected static function get_update_dependencies_for_module ($module) { |
111
|
|
|
if (!Config::instance()->module($module)) { |
112
|
|
|
throw new ExitException(404); |
113
|
|
|
} |
114
|
|
|
$tmp_location = TEMP.'/System/admin/'.Session::instance()->get_id().'.phar'; |
115
|
|
|
$tmp_dir = "phar://$tmp_location"; |
116
|
|
|
if ( |
117
|
|
|
!file_exists(MODULES."/$module/meta.json") || |
118
|
|
|
!file_exists("$tmp_dir/meta.json") |
119
|
|
|
) { |
120
|
|
|
throw new ExitException(400); |
121
|
|
|
} |
122
|
|
|
$new_meta = file_get_json("$tmp_dir/meta.json"); |
123
|
|
|
if (!static::is_same_module($new_meta, $module)) { |
124
|
|
|
throw new ExitException((new Prefix('system_admin_modules_'))->this_is_not_module_installer_file, 400); |
125
|
|
|
} |
126
|
|
|
Page::instance()->json( |
127
|
|
|
Packages_manipulation::get_dependencies($new_meta) |
128
|
|
|
); |
129
|
|
|
} |
130
|
|
|
/** |
131
|
|
|
* @param array $meta |
132
|
|
|
* @param string $module |
133
|
|
|
* |
134
|
|
|
* @return bool |
135
|
|
|
*/ |
136
|
|
|
protected static function is_same_module ($meta, $module) { |
137
|
|
|
return $meta['category'] == 'modules' && $meta['package'] == $module; |
138
|
|
|
} |
139
|
|
|
/** |
140
|
|
|
* @param string $module |
141
|
|
|
* |
142
|
|
|
* @throws ExitException |
143
|
|
|
*/ |
144
|
|
|
protected static function get_module_databases ($module) { |
145
|
|
|
$Config = Config::instance(); |
146
|
|
|
if (!isset($Config->components['modules'][$module]['db'])) { |
147
|
|
|
throw new ExitException(404); |
148
|
|
|
} |
149
|
|
|
Page::instance()->json( |
150
|
|
|
$Config->components['modules'][$module]['db'] |
151
|
|
|
); |
152
|
|
|
} |
153
|
|
|
/** |
154
|
|
|
* @param string $module |
155
|
|
|
* |
156
|
|
|
* @throws ExitException |
157
|
|
|
*/ |
158
|
|
|
protected static function get_module_storages ($module) { |
159
|
|
|
$Config = Config::instance(); |
160
|
|
|
if (!isset($Config->components['modules'][$module]['storage'])) { |
161
|
|
|
throw new ExitException(404); |
162
|
|
|
} |
163
|
|
|
Page::instance()->json( |
164
|
|
|
$Config->components['modules'][$module]['storage'] |
165
|
|
|
); |
166
|
|
|
} |
167
|
|
|
protected static function get_modules_list () { |
168
|
|
|
$Config = Config::instance(); |
169
|
|
|
$modules_list = []; |
170
|
|
|
foreach ($Config->components['modules'] as $module_name => &$module_data) { |
171
|
|
|
$module = [ |
172
|
|
|
'active' => $module_data['active'], |
173
|
|
|
'name' => $module_name, |
174
|
|
|
'has_user_section' => file_exists_with_extension(MODULES."/$module_name/index", ['php', 'html', 'json']), |
175
|
|
|
'has_admin_section' => file_exists_with_extension(MODULES."/$module_name/admin/index", ['php', 'json']) |
176
|
|
|
]; |
177
|
|
|
/** |
178
|
|
|
* Check if API available |
179
|
|
|
*/ |
180
|
|
|
static::check_module_feature_availability($module, 'readme', 'api'); |
181
|
|
|
/** |
182
|
|
|
* Check if readme available |
183
|
|
|
*/ |
184
|
|
|
static::check_module_feature_availability($module, 'readme'); |
185
|
|
|
/** |
186
|
|
|
* Check if license available |
187
|
|
|
*/ |
188
|
|
|
static::check_module_feature_availability($module, 'license'); |
189
|
|
|
if (file_exists(MODULES."/$module_name/meta.json")) { |
190
|
|
|
$module['meta'] = file_get_json(MODULES."/$module_name/meta.json"); |
191
|
|
|
} |
192
|
|
|
$modules_list[] = $module; |
193
|
|
|
} |
194
|
|
|
unset($module_name, $module_data, $module); |
195
|
|
|
Page::instance()->json($modules_list); |
196
|
|
|
} |
197
|
|
|
/** |
198
|
|
|
* @param array $module |
199
|
|
|
* @param string $feature |
200
|
|
|
* @param string $dir |
201
|
|
|
*/ |
202
|
|
|
protected static function check_module_feature_availability (&$module, $feature, $dir = '') { |
203
|
|
|
/** |
204
|
|
|
* Check if feature available |
205
|
|
|
*/ |
206
|
|
|
$file = file_exists_with_extension(MODULES."/$module[name]/$dir/$feature", ['txt', 'html']); |
207
|
|
|
if ($file) { |
208
|
|
|
$module[$dir ?: $feature] = [ |
209
|
|
|
'type' => substr($file, -3) == 'txt' ? 'txt' : 'html', |
210
|
|
|
'content' => file_get_contents($file) |
211
|
|
|
]; |
212
|
|
|
} elseif ($dir && is_dir(MODULES."/$module[name]/$dir")) { |
213
|
|
|
$module[$dir ?: $feature] = []; |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
protected static function get_default_module () { |
217
|
|
|
Page::instance()->json( |
218
|
|
|
Config::instance()->core['default_module'] |
219
|
|
|
); |
220
|
|
|
} |
221
|
|
|
/** |
222
|
|
|
* @param \cs\Request $Request |
223
|
|
|
* |
224
|
|
|
* @throws ExitException |
225
|
|
|
*/ |
226
|
|
|
static function admin_modules_put ($Request) { |
227
|
|
|
if ($Request->route_path(3)) { |
228
|
|
|
$route_path = $Request->route_path; |
229
|
|
|
switch ($route_path[3]) { |
230
|
|
|
/** |
231
|
|
|
* Set mapping of named module's databases to indexes of system databases |
232
|
|
|
*/ |
233
|
|
|
case 'db': |
234
|
|
|
static::set_module_databases($route_path[2]); |
235
|
|
|
break; |
236
|
|
|
/** |
237
|
|
|
* Set mapping of named module's storages to indexes of system storages |
238
|
|
|
*/ |
239
|
|
|
case 'storage': |
240
|
|
|
static::set_module_storages($route_path[2]); |
241
|
|
|
break; |
242
|
|
|
default: |
243
|
|
|
throw new ExitException(400); |
244
|
|
|
} |
245
|
|
|
} elseif ($Request->route_path(2) == 'default') { |
246
|
|
|
/** |
247
|
|
|
* Set current default module |
248
|
|
|
*/ |
249
|
|
|
static::set_default_module($Request->data('module')); |
250
|
|
|
} else { |
251
|
|
|
throw new ExitException(400); |
252
|
|
|
} |
253
|
|
|
} |
254
|
|
|
/** |
255
|
|
|
* @param string $module |
256
|
|
|
* |
257
|
|
|
* @throws ExitException |
258
|
|
|
*/ |
259
|
|
|
protected static function set_module_databases ($module) { |
260
|
|
|
$Config = Config::instance(); |
261
|
|
|
if (!isset($Config->components['modules'][$module]['db'], $_POST['db'])) { |
262
|
|
|
throw new ExitException(404); |
263
|
|
|
} |
264
|
|
|
$Config->components['modules'][$module]['db'] = _int($_POST['db']); |
265
|
|
|
static::admin_modules_save(); |
266
|
|
|
} |
267
|
|
|
/** |
268
|
|
|
* @param string $module |
269
|
|
|
* |
270
|
|
|
* @throws ExitException |
271
|
|
|
*/ |
272
|
|
|
protected static function set_module_storages ($module) { |
273
|
|
|
$Config = Config::instance(); |
274
|
|
|
if (!isset($Config->components['modules'][$module]['storage'], $_POST['storage'])) { |
275
|
|
|
throw new ExitException(404); |
276
|
|
|
} |
277
|
|
|
$Config->components['modules'][$module]['storage'] = _int($_POST['storage']); |
278
|
|
|
static::admin_modules_save(); |
279
|
|
|
} |
280
|
|
|
/** |
281
|
|
|
* @param string $module |
282
|
|
|
* |
283
|
|
|
* @throws ExitException |
284
|
|
|
*/ |
285
|
|
|
protected static function set_default_module ($module) { |
286
|
|
|
$Config = Config::instance(); |
287
|
|
|
$module_data = $Config->module($module); |
288
|
|
|
if (!$module_data) { |
289
|
|
|
throw new ExitException(404); |
290
|
|
|
} |
291
|
|
|
if ( |
292
|
|
|
$module == $Config->core['default_module'] || |
293
|
|
|
!$module_data->enabled() || |
294
|
|
|
!file_exists_with_extension(MODULES."/$module/index", ['php', 'html', 'json']) |
295
|
|
|
) { |
296
|
|
|
throw new ExitException(400); |
297
|
|
|
} |
298
|
|
|
if (!Event::instance()->fire('admin/System/components/modules/default', ['name' => $module])) { |
299
|
|
|
throw new ExitException(500); |
300
|
|
|
} |
301
|
|
|
$Config->core['default_module'] = $module; |
302
|
|
|
static::admin_modules_save(); |
303
|
|
|
} |
304
|
|
|
/** |
305
|
|
|
* Enable module |
306
|
|
|
* |
307
|
|
|
* Provides next events: |
308
|
|
|
* admin/System/components/modules/enable/before |
309
|
|
|
* ['name' => module_name] |
310
|
|
|
* |
311
|
|
|
* admin/System/components/modules/enable/after |
312
|
|
|
* ['name' => module_name] |
313
|
|
|
* |
314
|
|
|
* @param \cs\Request $Request |
315
|
|
|
* |
316
|
|
|
* @throws ExitException |
317
|
|
|
*/ |
318
|
|
|
static function admin_modules_enable ($Request) { |
319
|
|
|
$Config = Config::instance(); |
320
|
|
|
$module = $Request->route_path(2); |
321
|
|
|
if (!$Config->module($module)->disabled()) { |
|
|
|
|
322
|
|
|
throw new ExitException(400); |
323
|
|
|
} |
324
|
|
|
if (!Event::instance()->fire('admin/System/components/modules/enable/before', ['name' => $module])) { |
325
|
|
|
throw new ExitException(500); |
326
|
|
|
} |
327
|
|
|
$Config->components['modules'][$module]['active'] = Config\Module_Properties::ENABLED; |
328
|
|
|
static::admin_modules_save(); |
329
|
|
|
Event::instance()->fire('admin/System/components/modules/enable/after', ['name' => $module]); |
330
|
|
|
static::admin_modules_cleanup(); |
331
|
|
|
} |
332
|
|
|
protected static function admin_modules_cleanup () { |
333
|
|
|
clean_pcache(); |
334
|
|
|
$Cache = System_cache::instance(); |
335
|
|
|
unset( |
336
|
|
|
$Cache->functionality, |
337
|
|
|
$Cache->languages, |
338
|
|
|
$Cache->events_files_paths |
339
|
|
|
); |
340
|
|
|
clean_classes_cache(); |
341
|
|
|
} |
342
|
|
|
/** |
343
|
|
|
* Disable module |
344
|
|
|
* |
345
|
|
|
* Provides next events: |
346
|
|
|
* admin/System/components/modules/disable/before |
347
|
|
|
* ['name' => module_name] |
348
|
|
|
* |
349
|
|
|
* admin/System/components/modules/disable/after |
350
|
|
|
* ['name' => module_name] |
351
|
|
|
* |
352
|
|
|
* @param \cs\Request $Request |
353
|
|
|
* |
354
|
|
|
* @throws ExitException |
355
|
|
|
*/ |
356
|
|
|
static function admin_modules_disable ($Request) { |
357
|
|
|
$Config = Config::instance(); |
358
|
|
|
$module = $Request->route_path(2); |
359
|
|
|
if ( |
360
|
|
|
$module == Config::SYSTEM_MODULE || |
361
|
|
|
$Config->core['default_module'] == $module || |
362
|
|
|
!$Config->module($module)->enabled() |
|
|
|
|
363
|
|
|
) { |
364
|
|
|
throw new ExitException(400); |
365
|
|
|
} |
366
|
|
|
if (!Event::instance()->fire('admin/System/components/modules/disable/before', ['name' => $module])) { |
367
|
|
|
throw new ExitException(500); |
368
|
|
|
} |
369
|
|
|
$Config->components['modules'][$module]['active'] = Config\Module_Properties::DISABLED; |
370
|
|
|
static::admin_modules_save(); |
371
|
|
|
Event::instance()->fire('admin/System/components/modules/disable/after', ['name' => $module]); |
372
|
|
|
static::admin_modules_cleanup(); |
373
|
|
|
} |
374
|
|
|
/** |
375
|
|
|
* Install module |
376
|
|
|
* |
377
|
|
|
* Provides next events: |
378
|
|
|
* admin/System/components/modules/install/before |
379
|
|
|
* ['name' => module_name] |
380
|
|
|
* |
381
|
|
|
* admin/System/components/modules/install/after |
382
|
|
|
* ['name' => module_name] |
383
|
|
|
* |
384
|
|
|
* @param \cs\Request $Request |
385
|
|
|
* |
386
|
|
|
* @throws ExitException |
387
|
|
|
*/ |
388
|
|
|
static function admin_modules_install ($Request) { |
389
|
|
|
$Config = Config::instance(); |
390
|
|
|
$module = $Request->route_path(2); |
391
|
|
|
if (!$Config->module($module)->uninstalled()) { |
|
|
|
|
392
|
|
|
throw new ExitException(400); |
393
|
|
|
} |
394
|
|
|
if (!Event::instance()->fire('admin/System/components/modules/install/before', ['name' => $module])) { |
395
|
|
|
throw new ExitException(500); |
396
|
|
|
} |
397
|
|
|
$module_data = &$Config->components['modules'][$module]; |
398
|
|
|
if (isset($_POST['db'])) { |
399
|
|
|
$module_data['db'] = $_POST['db']; |
400
|
|
|
Packages_manipulation::execute_sql_from_directory(MODULES."/$module/meta/install_db", $module_data['db']); |
401
|
|
|
} |
402
|
|
|
if (isset($_POST['storage'])) { |
403
|
|
|
$module_data['storage'] = $_POST['storage']; |
404
|
|
|
} |
405
|
|
|
$module_data['active'] = Config\Module_Properties::DISABLED; |
406
|
|
|
static::admin_modules_save(); |
407
|
|
|
Event::instance()->fire('admin/System/components/modules/install/after', ['name' => $module]); |
408
|
|
|
static::admin_modules_cleanup(); |
409
|
|
|
} |
410
|
|
|
/** |
411
|
|
|
* Uninstall module |
412
|
|
|
* |
413
|
|
|
* Provides next events: |
414
|
|
|
* admin/System/components/modules/uninstall/before |
415
|
|
|
* ['name' => module_name] |
416
|
|
|
* |
417
|
|
|
* admin/System/components/modules/uninstall/after |
418
|
|
|
* ['name' => module_name] |
419
|
|
|
* |
420
|
|
|
* @param \cs\Request $Request |
421
|
|
|
* |
422
|
|
|
* @throws ExitException |
423
|
|
|
*/ |
424
|
|
|
static function admin_modules_uninstall ($Request) { |
425
|
|
|
$Config = Config::instance(); |
426
|
|
|
$module = $Request->route_path(2); |
427
|
|
|
$modules = &$Config->components['modules']; |
428
|
|
|
/** |
429
|
|
|
* Do not allow to uninstall enabled module, it should be explicitly disabled first |
430
|
|
|
*/ |
431
|
|
|
if (!$Config->module($module)->disabled()) { |
|
|
|
|
432
|
|
|
throw new ExitException(400); |
433
|
|
|
} |
434
|
|
|
if (!Event::instance()->fire('admin/System/components/modules/uninstall/before', ['name' => $module])) { |
435
|
|
|
throw new ExitException(500); |
436
|
|
|
} |
437
|
|
|
$module_data = &$modules[$module]; |
438
|
|
|
if (isset($module_data['db'])) { |
439
|
|
|
Packages_manipulation::execute_sql_from_directory(MODULES."/$module/meta/uninstall_db", $module_data['db']); |
440
|
|
|
} |
441
|
|
|
static::delete_permissions_for_module($module); |
|
|
|
|
442
|
|
|
$modules[$module] = ['active' => Config\Module_Properties::UNINSTALLED]; |
443
|
|
|
static::admin_modules_save(); |
444
|
|
|
Event::instance()->fire('admin/System/components/modules/uninstall/after', ['name' => $module]); |
445
|
|
|
static::admin_modules_cleanup(); |
446
|
|
|
} |
447
|
|
|
/** |
448
|
|
|
* @param string $module |
449
|
|
|
*/ |
450
|
|
|
protected static function delete_permissions_for_module ($module) { |
451
|
|
|
$Permission = Permission::instance(); |
452
|
|
|
$permissions_ids = array_merge( |
453
|
|
|
$Permission->get(null, $module), |
454
|
|
|
$Permission->get(null, "admin/$module"), |
455
|
|
|
$Permission->get(null, "api/$module") |
456
|
|
|
); |
457
|
|
|
if (!empty($permissions_ids)) { |
458
|
|
|
$Permission->del( |
459
|
|
|
array_column($permissions_ids, 'id') |
460
|
|
|
); |
461
|
|
|
} |
462
|
|
|
} |
463
|
|
|
/** |
464
|
|
|
* Extract uploaded module |
465
|
|
|
* |
466
|
|
|
* @throws ExitException |
467
|
|
|
*/ |
468
|
|
|
static function admin_modules_extract () { |
469
|
|
|
$Config = Config::instance(); |
470
|
|
|
$L = new Prefix('system_admin_modules_'); |
471
|
|
|
$tmp_location = TEMP.'/System/admin/'.Session::instance()->get_id().'.phar'; |
472
|
|
|
$tmp_dir = "phar://$tmp_location"; |
473
|
|
|
if ( |
474
|
|
|
!file_exists($tmp_location) || |
475
|
|
|
!file_exists("$tmp_dir/meta.json") |
476
|
|
|
) { |
477
|
|
|
throw new ExitException(400); |
478
|
|
|
} |
479
|
|
|
$new_meta = file_get_json("$tmp_dir/meta.json"); |
480
|
|
|
if ($new_meta['category'] !== 'modules') { |
481
|
|
|
throw new ExitException($L->this_is_not_module_installer_file, 400); |
482
|
|
|
} |
483
|
|
|
if (!Packages_manipulation::install_extract(MODULES."/$new_meta[package]", $tmp_location)) { |
484
|
|
|
throw new ExitException($L->module_files_unpacking_error, 500); |
485
|
|
|
} |
486
|
|
|
$Config->components['modules'][$new_meta['package']] = ['active' => Config\Module_Properties::UNINSTALLED]; |
487
|
|
|
ksort($Config->components['modules'], SORT_STRING | SORT_FLAG_CASE); |
488
|
|
|
static::admin_modules_save(); |
489
|
|
|
static::admin_modules_cleanup(); |
490
|
|
|
} |
491
|
|
|
/** |
492
|
|
|
* Update module (or system if module name is System) |
493
|
|
|
* |
494
|
|
|
* @param \cs\Request $Request |
495
|
|
|
* |
496
|
|
|
* @throws ExitException |
497
|
|
|
*/ |
498
|
|
|
static function admin_modules_update ($Request) { |
499
|
|
|
$module = $Request->route_path(2); |
500
|
|
|
if (!Config::instance()->module($module)) { |
|
|
|
|
501
|
|
|
throw new ExitException(404); |
502
|
|
|
} |
503
|
|
|
$tmp_location = TEMP.'/System/admin/'.Session::instance()->get_id().'.phar'; |
504
|
|
|
$tmp_dir = "phar://$tmp_location"; |
505
|
|
|
$module_dir = MODULES."/$module"; |
506
|
|
|
if ( |
507
|
|
|
!file_exists($tmp_location) || |
508
|
|
|
!file_exists("$module_dir/meta.json") || |
509
|
|
|
!file_exists("$tmp_dir/meta.json") |
510
|
|
|
) { |
511
|
|
|
throw new ExitException(400); |
512
|
|
|
} |
513
|
|
|
$existing_meta = file_get_json("$module_dir/meta.json"); |
514
|
|
|
$new_meta = file_get_json("$tmp_dir/meta.json"); |
515
|
|
|
if ($module == Config::SYSTEM_MODULE) { |
516
|
|
|
static::update_system($module, $existing_meta, $new_meta, $tmp_location); |
|
|
|
|
517
|
|
|
} else { |
518
|
|
|
static::update_module($module, $existing_meta, $new_meta, $tmp_location, $Request); |
|
|
|
|
519
|
|
|
} |
520
|
|
|
static::admin_modules_cleanup(); |
521
|
|
|
} |
522
|
|
|
/** |
523
|
|
|
* Provides next events: |
524
|
|
|
* admin/System/components/modules/update/before |
525
|
|
|
* ['name' => module_name] |
526
|
|
|
* |
527
|
|
|
* admin/System/components/modules/update/after |
528
|
|
|
* ['name' => module_name] |
529
|
|
|
* |
530
|
|
|
* @param string $module |
531
|
|
|
* @param array $existing_meta |
532
|
|
|
* @param array $new_meta |
533
|
|
|
* @param string $tmp_location |
534
|
|
|
* @param \cs\Request $Request |
535
|
|
|
* |
536
|
|
|
* @throws ExitException |
537
|
|
|
*/ |
538
|
|
|
protected static function update_module ($module, $existing_meta, $new_meta, $tmp_location, $Request) { |
539
|
|
|
$Config = Config::instance(); |
540
|
|
|
$L = new Prefix('system_admin_modules_'); |
541
|
|
|
$module_dir = MODULES."/$module"; |
542
|
|
|
$enabled = $Config->module($module)->enabled(); |
543
|
|
|
// If module is currently enabled - disable it temporary |
544
|
|
|
if ($enabled) { |
545
|
|
|
static::admin_modules_disable($Request); |
546
|
|
|
} |
547
|
|
|
if (!static::is_same_module($new_meta, $module)) { |
548
|
|
|
throw new ExitException($L->this_is_not_module_installer_file, 400); |
549
|
|
|
} |
550
|
|
|
if (!Event::instance()->fire('admin/System/components/modules/update/before', ['name' => $module])) { |
551
|
|
|
throw new ExitException(500); |
552
|
|
|
} |
553
|
|
|
if (!is_writable($module_dir)) { |
554
|
|
|
throw new ExitException($L->cant_unpack_module_no_write_permissions, 500); |
555
|
|
|
} |
556
|
|
|
if (!Packages_manipulation::update_extract($module_dir, $tmp_location)) { |
557
|
|
|
throw new ExitException($L->module_files_unpacking_error, 500); |
558
|
|
|
} |
559
|
|
|
$module_data = $Config->components['modules'][$module]; |
560
|
|
|
// Run PHP update scripts and SQL queries if any |
561
|
|
|
Packages_manipulation::update_php_sql($module_dir, $existing_meta['version'], isset($module_data['db']) ? $module_data['db'] : null); |
562
|
|
|
Event::instance()->fire('admin/System/components/modules/update/after', ['name' => $module]); |
563
|
|
|
// If module was enabled before update - enable it back |
564
|
|
|
if ($enabled) { |
565
|
|
|
static::admin_modules_enable($Request); |
566
|
|
|
} |
567
|
|
|
} |
568
|
|
|
/** |
569
|
|
|
* Provides next events: |
570
|
|
|
* admin/System/components/modules/update_system/before |
571
|
|
|
* |
572
|
|
|
* admin/System/components/modules/update_system/after |
573
|
|
|
* |
574
|
|
|
* @param string $module |
575
|
|
|
* @param array $existing_meta |
576
|
|
|
* @param array $new_meta |
577
|
|
|
* @param string $tmp_location |
578
|
|
|
* |
579
|
|
|
* @throws ExitException |
580
|
|
|
*/ |
581
|
|
|
protected static function update_system ($module, $existing_meta, $new_meta, $tmp_location) { |
582
|
|
|
$Config = Config::instance(); |
583
|
|
|
$L = new Prefix('system_admin_modules_'); |
584
|
|
|
$module_dir = MODULES."/$module"; |
585
|
|
|
/** |
586
|
|
|
* Temporary close site |
587
|
|
|
*/ |
588
|
|
|
$site_mode = $Config->core['site_mode']; |
589
|
|
|
if ($site_mode) { |
590
|
|
|
$Config->core['site_mode'] = 0; |
591
|
|
|
static::admin_modules_save(); |
592
|
|
|
} |
593
|
|
|
if (!static::is_same_module($new_meta, Config::SYSTEM_MODULE)) { |
594
|
|
|
throw new ExitException($L->this_is_not_system_installer_file, 400); |
595
|
|
|
} |
596
|
|
|
if (!Event::instance()->fire('admin/System/components/modules/update_system/before')) { |
597
|
|
|
throw new ExitException(500); |
598
|
|
|
} |
599
|
|
|
if (!Packages_manipulation::update_extract(DIR, $tmp_location, DIR.'/core', $module_dir)) { |
600
|
|
|
throw new ExitException($L->system_files_unpacking_error, 500); |
601
|
|
|
} |
602
|
|
|
$module_data = $Config->components['modules'][$module]; |
603
|
|
|
// Run PHP update scripts and SQL queries if any |
604
|
|
|
Packages_manipulation::update_php_sql($module_dir, $existing_meta['version'], isset($module_data['db']) ? $module_data['db'] : null); |
605
|
|
|
Event::instance()->fire('admin/System/components/modules/update_system/after'); |
606
|
|
|
/** |
607
|
|
|
* Restore previous site mode |
608
|
|
|
*/ |
609
|
|
|
if ($site_mode) { |
610
|
|
|
$Config->core['site_mode'] = 1; |
611
|
|
|
static::admin_modules_save(); |
612
|
|
|
} |
613
|
|
|
static::admin_modules_cleanup(); |
614
|
|
|
} |
615
|
|
|
/** |
616
|
|
|
* Delete module completely |
617
|
|
|
* |
618
|
|
|
* @param \cs\Request $Request |
619
|
|
|
* |
620
|
|
|
* @throws ExitException |
621
|
|
|
*/ |
622
|
|
|
static function admin_modules_delete ($Request) { |
623
|
|
|
$Config = Config::instance(); |
624
|
|
|
$module = $Request->route_path(2); |
625
|
|
|
if ( |
626
|
|
|
$module == Config::SYSTEM_MODULE || |
627
|
|
|
!$Config->module($module)->uninstalled() |
|
|
|
|
628
|
|
|
) { |
629
|
|
|
throw new ExitException(400); |
630
|
|
|
} |
631
|
|
|
if (!rmdir_recursive(MODULES."/$module")) { |
632
|
|
|
throw new ExitException(500); |
633
|
|
|
} |
634
|
|
|
unset($Config->components['modules'][$module]); |
635
|
|
|
static::admin_modules_save(); |
636
|
|
|
} |
637
|
|
|
/** |
638
|
|
|
* Update information about present modules |
639
|
|
|
* |
640
|
|
|
* @throws ExitException |
641
|
|
|
*/ |
642
|
|
|
static function admin_modules_update_list () { |
643
|
|
|
$Config = Config::instance(); |
644
|
|
|
/** |
645
|
|
|
* List of currently presented modules in file system |
646
|
|
|
*/ |
647
|
|
|
$modules_in_fs = get_files_list(MODULES, false, 'd'); |
648
|
|
|
$modules_list = array_fill_keys( |
649
|
|
|
$modules_in_fs, |
650
|
|
|
[ |
651
|
|
|
'active' => -1, |
652
|
|
|
'db' => [], |
653
|
|
|
'storage' => [] |
654
|
|
|
] |
655
|
|
|
); |
656
|
|
|
/** |
657
|
|
|
* Already known modules |
658
|
|
|
*/ |
659
|
|
|
$modules = &$Config->components['modules']; |
660
|
|
|
$known_modules = array_keys($modules); |
661
|
|
|
if ($modules_in_fs != $known_modules) { |
662
|
|
|
/** |
663
|
|
|
* Delete permissions of modules that are mot present anymore |
664
|
|
|
*/ |
665
|
|
|
foreach ($known_modules as $module) { |
666
|
|
|
if (!isset($modules_list[$module])) { |
667
|
|
|
static::delete_permissions_for_module($module); |
668
|
|
|
} |
669
|
|
|
} |
670
|
|
|
unset($module); |
671
|
|
|
} |
672
|
|
|
unset($modules_in_fs, $known_modules); |
673
|
|
|
$modules = array_merge($modules_list, array_intersect_key($modules, $modules_list)); |
674
|
|
|
ksort($modules, SORT_STRING | SORT_FLAG_CASE); |
675
|
|
|
static::admin_modules_save(); |
676
|
|
|
static::admin_modules_cleanup(); |
677
|
|
|
} |
678
|
|
|
/** |
679
|
|
|
* Save changes |
680
|
|
|
* |
681
|
|
|
* @throws ExitException |
682
|
|
|
*/ |
683
|
|
|
protected static function admin_modules_save () { |
684
|
|
|
if (!Config::instance()->save()) { |
685
|
|
|
throw new ExitException(500); |
686
|
|
|
} |
687
|
|
|
} |
688
|
|
|
} |
689
|
|
|
|
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.