1: | <?php
|
2: | namespace Opencart\Admin\Controller\Common;
|
3: | |
4: | |
5: | |
6: | |
7: |
|
8: | class Security extends \Opencart\System\Engine\Controller {
|
9: | |
10: | |
11: | |
12: | |
13: |
|
14: | public function index(): string {
|
15: | $this->load->language('common/security');
|
16: |
|
17: | $data['list'] = $this->controller_common_security->getList();
|
18: |
|
19: | $data['user_token'] = $this->session->data['user_token'];
|
20: |
|
21: | return $this->load->view('common/security', $data);
|
22: | }
|
23: |
|
24: | |
25: | |
26: | |
27: | |
28: |
|
29: | public function list(): void {
|
30: | $this->load->language('common/security');
|
31: |
|
32: | $this->response->setOutput($this->controller_common_security->getList());
|
33: | }
|
34: |
|
35: | |
36: | |
37: | |
38: | |
39: |
|
40: | public function getList(): string {
|
41: |
|
42: | $path = DIR_OPENCART . 'install/';
|
43: |
|
44: | if (is_dir($path)) {
|
45: | $data['install'] = $path;
|
46: | } else {
|
47: | $data['install'] = '';
|
48: | }
|
49: |
|
50: |
|
51: | $path = DIR_SYSTEM . 'storage/';
|
52: |
|
53: | if (DIR_STORAGE == $path) {
|
54: | $data['storage'] = $path;
|
55: |
|
56: | $data['document_root'] = str_replace('\\', '/', realpath($this->request->server['DOCUMENT_ROOT'] . '/../')) . '/';
|
57: |
|
58: | $path = '';
|
59: |
|
60: | $data['paths'] = [];
|
61: |
|
62: | $parts = explode('/', rtrim($data['document_root'], '/'));
|
63: |
|
64: | foreach ($parts as $part) {
|
65: | $path .= $part . '/';
|
66: |
|
67: | $data['paths'][] = $path;
|
68: | }
|
69: |
|
70: | rsort($data['paths']);
|
71: | } else {
|
72: | $data['storage'] = '';
|
73: | }
|
74: |
|
75: |
|
76: | $path = DIR_SYSTEM . 'storage/';
|
77: |
|
78: | if (is_dir($path) && DIR_STORAGE != $path) {
|
79: | $data['storage_delete'] = $path;
|
80: | } else {
|
81: | $data['storage_delete'] = '';
|
82: | }
|
83: |
|
84: |
|
85: | $path = DIR_OPENCART . 'admin/';
|
86: |
|
87: | if (DIR_APPLICATION == $path) {
|
88: | $data['admin'] = 'admin';
|
89: | } else {
|
90: | $data['admin'] = '';
|
91: | }
|
92: |
|
93: |
|
94: | $path = DIR_OPENCART . 'admin/';
|
95: |
|
96: | if (is_dir($path) && DIR_APPLICATION != $path) {
|
97: | $data['admin_delete'] = $path;
|
98: | } else {
|
99: | $data['admin_delete'] = '';
|
100: | }
|
101: |
|
102: | $data['user_token'] = $this->session->data['user_token'];
|
103: |
|
104: | if ($data['install'] || $data['storage'] || $data['storage_delete'] || $data['admin'] || $data['admin_delete']) {
|
105: | return $this->load->view('common/security_list', $data);
|
106: | } else {
|
107: | return '';
|
108: | }
|
109: | }
|
110: |
|
111: | |
112: | |
113: | |
114: | |
115: |
|
116: | public function install(): void {
|
117: | $this->load->language('common/security');
|
118: |
|
119: | $json = [];
|
120: |
|
121: | if (!$this->user->hasPermission('modify', 'common/security')) {
|
122: | $json['error'] = $this->language->get('error_permission');
|
123: | }
|
124: |
|
125: | if (!$json) {
|
126: | if (!is_dir(DIR_OPENCART . 'install/')) {
|
127: | $json['error'] = $this->language->get('error_install');
|
128: | }
|
129: | }
|
130: |
|
131: | if (!$json) {
|
132: | $files = [];
|
133: |
|
134: | $path = DIR_OPENCART . 'install/';
|
135: |
|
136: |
|
137: | $directory = [$path];
|
138: |
|
139: |
|
140: | while (count($directory) != 0) {
|
141: | $next = array_shift($directory);
|
142: |
|
143: | if (is_dir($next)) {
|
144: | foreach (glob(rtrim($next, '/') . '/{*,.[!.]*,..?*}', GLOB_BRACE) as $file) {
|
145: |
|
146: | if (is_dir($file)) {
|
147: | $directory[] = $file;
|
148: | }
|
149: |
|
150: |
|
151: | $files[] = $file;
|
152: | }
|
153: | }
|
154: | }
|
155: |
|
156: | rsort($files);
|
157: |
|
158: | foreach ($files as $file) {
|
159: | if (is_file($file)) {
|
160: | unlink($file);
|
161: | } elseif (is_dir($file)) {
|
162: | rmdir($file);
|
163: | }
|
164: | }
|
165: |
|
166: | rmdir($path);
|
167: |
|
168: | $json['success'] = $this->language->get('text_install_success');
|
169: | }
|
170: |
|
171: | $this->response->addHeader('Content-Type: application/json');
|
172: | $this->response->setOutput(json_encode($json));
|
173: | }
|
174: |
|
175: | |
176: | |
177: | |
178: | |
179: |
|
180: | public function storage(): void {
|
181: | $this->load->language('common/security');
|
182: |
|
183: | $json = [];
|
184: |
|
185: | if (isset($this->request->get['page'])) {
|
186: | $page = (int)$this->request->get['page'];
|
187: | } else {
|
188: | $page = 1;
|
189: | }
|
190: |
|
191: | if (isset($this->request->get['name'])) {
|
192: | $name = preg_replace('/[^a-zA-Z0-9_\.]/', '', basename(html_entity_decode(trim($this->request->get['name']), ENT_QUOTES, 'UTF-8')));
|
193: | } else {
|
194: | $name = '';
|
195: | }
|
196: |
|
197: | if (isset($this->request->get['path'])) {
|
198: | $path = preg_replace('/[^a-zA-Z0-9_\:\/\.]/', '', html_entity_decode(trim($this->request->get['path']), ENT_QUOTES, 'UTF-8'));
|
199: | } else {
|
200: | $path = '';
|
201: | }
|
202: |
|
203: | if (!$this->user->hasPermission('modify', 'common/security')) {
|
204: | $json['error'] = $this->language->get('error_permission');
|
205: | }
|
206: |
|
207: | if (!$json) {
|
208: | $base_old = DIR_STORAGE;
|
209: | $base_new = $path . $name . '/';
|
210: |
|
211: |
|
212: | if (!is_dir($base_old)) {
|
213: | $json['error'] = $this->language->get('error_storage');
|
214: | }
|
215: |
|
216: |
|
217: | $root = str_replace('\\', '/', realpath($this->request->server['DOCUMENT_ROOT'] . '/../'));
|
218: |
|
219: | if ((substr($base_new, 0, strlen($root)) != $root) || ($root == $base_new)) {
|
220: | $json['error'] = $this->language->get('error_storage_root');
|
221: | }
|
222: |
|
223: | if (!str_starts_with($name, 'storage')) {
|
224: | $json['error'] = $this->language->get('error_storage_name');
|
225: | }
|
226: |
|
227: | if (!is_writable(DIR_OPENCART . 'config.php') || !is_writable(DIR_APPLICATION . 'config.php')) {
|
228: | $json['error'] = $this->language->get('error_writable');
|
229: | }
|
230: | }
|
231: |
|
232: | if (!$json) {
|
233: | $files = [];
|
234: |
|
235: |
|
236: | $directory = [$base_old];
|
237: |
|
238: |
|
239: | while (count($directory) != 0) {
|
240: | $next = array_shift($directory);
|
241: |
|
242: | foreach (glob(rtrim($next, '/') . '/{*,.[!.]*,..?*}', GLOB_BRACE) as $file) {
|
243: |
|
244: | if (is_dir($file)) {
|
245: | $directory[] = $file;
|
246: | }
|
247: |
|
248: |
|
249: | $files[] = $file;
|
250: | }
|
251: | }
|
252: |
|
253: |
|
254: | if (!is_dir($base_new)) {
|
255: | mkdir($base_new, 0777);
|
256: | }
|
257: |
|
258: |
|
259: | $total = count($files);
|
260: | $limit = 200;
|
261: |
|
262: | $start = ($page - 1) * $limit;
|
263: | $end = ($start > ($total - $limit)) ? $total : ($start + $limit);
|
264: |
|
265: | for ($i = $start; $i < $end; $i++) {
|
266: | $destination = substr($files[$i], strlen($base_old));
|
267: |
|
268: |
|
269: | $path_new = '';
|
270: |
|
271: | $directories = explode('/', dirname($destination));
|
272: |
|
273: | foreach ($directories as $directory) {
|
274: | if (!$path_new) {
|
275: | $path_new = $directory;
|
276: | } else {
|
277: | $path_new = $path_new . '/' . $directory;
|
278: | }
|
279: |
|
280: |
|
281: | if (!is_dir($base_new . $path_new)) {
|
282: | mkdir($base_new . $path_new, 0777);
|
283: | }
|
284: | }
|
285: |
|
286: | if (is_file($base_old . $destination) && !is_file($base_new . $destination)) {
|
287: | copy($base_old . $destination, $base_new . $destination);
|
288: | }
|
289: | }
|
290: |
|
291: | if ($end < $total) {
|
292: | $json['text'] = sprintf($this->language->get('text_storage_move'), $start, $end, $total);
|
293: |
|
294: | $json['next'] = $this->url->link('common/security.storage', '&user_token=' . $this->session->data['user_token'] . '&name=' . $name . '&path=' . $path . '&page=' . ($page + 1), true);
|
295: | } else {
|
296: |
|
297: | rsort($files);
|
298: |
|
299: | foreach ($files as $file) {
|
300: | if (is_file($file)) {
|
301: | unlink($file);
|
302: | } elseif (is_dir($file)) {
|
303: | rmdir($file);
|
304: | }
|
305: | }
|
306: |
|
307: | rmdir($base_old);
|
308: |
|
309: |
|
310: | $files = [
|
311: | DIR_APPLICATION . 'config.php',
|
312: | DIR_OPENCART . 'config.php'
|
313: | ];
|
314: |
|
315: | foreach ($files as $file) {
|
316: | $output = '';
|
317: |
|
318: | $lines = file($file);
|
319: |
|
320: | foreach ($lines as $line_id => $line) {
|
321: | if (strpos($line, 'define(\'DIR_STORAGE') !== false) {
|
322: | $output .= 'define(\'DIR_STORAGE\', \'' . $base_new . '\');' . "\n";
|
323: | } else {
|
324: | $output .= $line;
|
325: | }
|
326: | }
|
327: |
|
328: | $file = fopen($file, 'w');
|
329: |
|
330: | fwrite($file, $output);
|
331: |
|
332: | fclose($file);
|
333: | }
|
334: |
|
335: | $json['success'] = $this->language->get('text_storage_success');
|
336: | }
|
337: | }
|
338: |
|
339: | $this->response->addHeader('Content-Type: application/json');
|
340: | $this->response->setOutput(json_encode($json));
|
341: | }
|
342: |
|
343: | |
344: | |
345: | |
346: | |
347: |
|
348: | public function admin(): void {
|
349: | $this->load->language('common/security');
|
350: |
|
351: | $json = [];
|
352: |
|
353: | if (isset($this->request->get['page'])) {
|
354: | $page = (int)$this->request->get['page'];
|
355: | } else {
|
356: | $page = 1;
|
357: | }
|
358: |
|
359: | if (isset($this->request->get['name'])) {
|
360: | $name = preg_replace('[^a-zA-Z0-9]', '', basename(html_entity_decode(trim((string)$this->request->get['name']), ENT_QUOTES, 'UTF-8')));
|
361: | } else {
|
362: | $name = 'admin';
|
363: | }
|
364: |
|
365: | if (!$this->user->hasPermission('modify', 'common/security')) {
|
366: | $json['error'] = $this->language->get('error_permission');
|
367: | }
|
368: |
|
369: | if (!$json) {
|
370: | $base_old = DIR_OPENCART . 'admin/';
|
371: | $base_new = DIR_OPENCART . $name . '/';
|
372: |
|
373: | if (!is_dir($base_old)) {
|
374: | $json['error'] = $this->language->get('error_admin');
|
375: | }
|
376: |
|
377: | if ($page == 1 && is_dir($base_new)) {
|
378: | $json['error'] = $this->language->get('error_admin_exists');
|
379: | }
|
380: |
|
381: | $blocked = [
|
382: | 'admin',
|
383: | 'catalog',
|
384: | 'extension',
|
385: | 'image',
|
386: | 'install',
|
387: | 'system'
|
388: | ];
|
389: |
|
390: | if (in_array($name, $blocked)) {
|
391: | $json['error'] = sprintf($this->language->get('error_admin_allowed'), $name);
|
392: | }
|
393: |
|
394: | if (!is_writable(DIR_OPENCART . 'config.php') || !is_writable(DIR_APPLICATION . 'config.php')) {
|
395: | $json['error'] = $this->language->get('error_writable');
|
396: | }
|
397: | }
|
398: |
|
399: | if (!$json) {
|
400: |
|
401: | $files = [];
|
402: |
|
403: |
|
404: | $directory = [$base_old];
|
405: |
|
406: |
|
407: | while (count($directory) != 0) {
|
408: | $next = array_shift($directory);
|
409: |
|
410: | foreach (glob(rtrim($next, '/') . '/{*,.[!.]*,..?*}', GLOB_BRACE) as $file) {
|
411: |
|
412: | if (is_dir($file)) {
|
413: | $directory[] = $file;
|
414: | }
|
415: |
|
416: |
|
417: | $files[] = $file;
|
418: | }
|
419: | }
|
420: |
|
421: |
|
422: | if (!is_dir($base_new)) {
|
423: | mkdir($base_new, 0777);
|
424: | }
|
425: |
|
426: |
|
427: | $total = count($files);
|
428: | $limit = 200;
|
429: |
|
430: | $start = ($page - 1) * $limit;
|
431: | $end = ($start > ($total - $limit)) ? $total : ($start + $limit);
|
432: |
|
433: |
|
434: | foreach (array_slice($files, $start, $end) as $file) {
|
435: | $destination = substr($file, strlen($base_old));
|
436: |
|
437: |
|
438: | $path_new = '';
|
439: |
|
440: | $directories = explode('/', dirname($destination));
|
441: |
|
442: | foreach ($directories as $directory) {
|
443: | if (!$path_new) {
|
444: | $path_new = $directory;
|
445: | } else {
|
446: | $path_new = $path_new . '/' . $directory;
|
447: | }
|
448: |
|
449: | if (!is_dir($base_new . $path_new)) {
|
450: | mkdir($base_new . $path_new, 0777);
|
451: | }
|
452: | }
|
453: |
|
454: | if (is_file($base_old . $destination) && !is_file($base_new . $destination)) {
|
455: | copy($base_old . $destination, $base_new . $destination);
|
456: | }
|
457: | }
|
458: |
|
459: | if ($end < $total) {
|
460: | $json['text'] = sprintf($this->language->get('text_admin_move'), $start, $end, $total);
|
461: |
|
462: | $json['next'] = $this->url->link('common/security.admin', '&user_token=' . $this->session->data['user_token'] . '&name=' . $name . '&page=' . ($page + 1), true);
|
463: | } else {
|
464: |
|
465: | $file = $base_new . 'config.php';
|
466: |
|
467: | $output = '';
|
468: |
|
469: | $lines = file($file);
|
470: |
|
471: | foreach ($lines as $line_id => $line) {
|
472: | $status = true;
|
473: |
|
474: | if (strpos($line, 'define(\'HTTP_SERVER') !== false) {
|
475: | $output .= 'define(\'HTTP_SERVER\', \'' . substr(HTTP_SERVER, 0, strrpos(HTTP_SERVER, '/admin/')) . '/' . $name . '/\');' . "\n";
|
476: |
|
477: | $status = false;
|
478: | }
|
479: |
|
480: | if (strpos($line, 'define(\'DIR_APPLICATION') !== false) {
|
481: | $output .= 'define(\'DIR_APPLICATION\', DIR_OPENCART . \'' . $name . '/\');' . "\n";
|
482: |
|
483: | $status = false;
|
484: | }
|
485: |
|
486: | if ($status) {
|
487: | $output .= $line;
|
488: | }
|
489: | }
|
490: |
|
491: | $file = fopen($file, 'w');
|
492: |
|
493: | fwrite($file, $output);
|
494: |
|
495: | fclose($file);
|
496: |
|
497: | $this->session->data['success'] = $this->language->get('text_admin_success');
|
498: |
|
499: |
|
500: | $json['redirect'] = str_replace('&', '&', substr(HTTP_SERVER, 0, -6) . $name . '/index.php?route=common/login');
|
501: | }
|
502: | }
|
503: |
|
504: | $this->response->addHeader('Content-Type: application/json');
|
505: | $this->response->setOutput(json_encode($json));
|
506: | }
|
507: |
|
508: | |
509: | |
510: | |
511: | |
512: |
|
513: | public function delete(): void {
|
514: | $this->load->language('common/security');
|
515: |
|
516: | $json = [];
|
517: |
|
518: | if (isset($this->request->get['remove'])) {
|
519: | $remove = (string)$this->request->get['remove'];
|
520: | } else {
|
521: | $remove = '';
|
522: | }
|
523: |
|
524: | if (!$this->user->hasPermission('modify', 'common/security')) {
|
525: | $json['error'] = $this->language->get('error_permission');
|
526: | }
|
527: |
|
528: | if (!$json) {
|
529: | $path = '';
|
530: |
|
531: | if ($remove == 'storage') {
|
532: |
|
533: | $path = DIR_SYSTEM . 'storage/';
|
534: |
|
535: | if (!is_dir($path) || DIR_STORAGE == $path) {
|
536: | $json['error'] = $this->language->get('error_storage');
|
537: | }
|
538: | }
|
539: |
|
540: |
|
541: | if ($remove == 'admin') {
|
542: | $path = DIR_OPENCART . 'admin/';
|
543: |
|
544: | if (!is_dir($path) || DIR_APPLICATION == $path) {
|
545: | $json['error'] = $this->language->get('error_admin');
|
546: | }
|
547: | }
|
548: |
|
549: | if (!$path) {
|
550: | $json['error'] = $this->language->get('error_remove');
|
551: | }
|
552: | }
|
553: |
|
554: | if (!$json) {
|
555: |
|
556: | $directory = [$path];
|
557: |
|
558: |
|
559: | foreach ($directory as $path) {
|
560: | $files = [];
|
561: |
|
562: |
|
563: | while (count($directory) != 0) {
|
564: | $next = array_shift($directory);
|
565: |
|
566: | if (is_dir($next)) {
|
567: | foreach (glob(rtrim($next, '/') . '/{*,.[!.]*,..?*}', GLOB_BRACE) as $file) {
|
568: |
|
569: | if (is_dir($file)) {
|
570: | $directory[] = $file;
|
571: | }
|
572: |
|
573: |
|
574: | $files[] = $file;
|
575: | }
|
576: | }
|
577: | }
|
578: |
|
579: | rsort($files);
|
580: |
|
581: | foreach ($files as $file) {
|
582: | if (is_file($file)) {
|
583: | unlink($file);
|
584: | } elseif (is_dir($file)) {
|
585: | rmdir($file);
|
586: | }
|
587: | }
|
588: |
|
589: | rmdir($path);
|
590: | }
|
591: |
|
592: | $json['success'] = $this->language->get('text_' . $remove . '_delete_success');
|
593: | }
|
594: |
|
595: | $this->response->addHeader('Content-Type: application/json');
|
596: | $this->response->setOutput(json_encode($json));
|
597: | }
|
598: | }
|
599: | |