1: | <?php
2: | namespace Opencart\Admin\Controller\Common;
3: | /**
4: | * Class Security
5: | *
6: | * @package Opencart\Admin\Controller\Common
7: | */
8: | class Security extends \Opencart\System\Engine\Controller {
9: | /**
10: | * Index
11: | *
12: | * @return string
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: | * List
26: | *
27: | * @return void
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: | * getList
37: | *
38: | * @return string
39: | */
40: | public function getList(): string {
41: | // Install directory exists
42: | $path = DIR_OPENCART . 'install/';
43: |
44: | if (is_dir($path)) {
45: | $data['install'] = $path;
46: | } else {
47: | $data['install'] = '';
48: | }
49: |
50: | // Storage directory exists
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: | // Storage delete
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: | // Check admin directory ia renamed
85: | $path = DIR_OPENCART . 'admin/';
86: |
87: | if (DIR_APPLICATION == $path) {
88: | $data['admin'] = 'admin';
89: | } else {
90: | $data['admin'] = '';
91: | }
92: |
93: | // Admin delete
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: | * Install
113: | *
114: | * @return void
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: | // Make path into an array
137: | $directory = [$path];
138: |
139: | // While the path array is still populated keep looping through
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: | // If directory add to path array
146: | if (is_dir($file)) {
147: | $directory[] = $file;
148: | }
149: |
150: | // Add the file to the files to be deleted array
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: | * Storage
177: | *
178: | * @return void
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: | // Check current storage path exists
212: | if (!is_dir($base_old)) {
213: | $json['error'] = $this->language->get('error_storage');
214: | }
215: |
216: | // Check the chosen directory is not in the public webspace
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: | // Make path into an array
236: | $directory = [$base_old];
237: |
238: | // While the path array is still populated keep looping through
239: | while (count($directory) != 0) {
240: | $next = array_shift($directory);
241: |
242: | foreach (glob(rtrim($next, '/') . '/{*,.[!.]*,..?*}', GLOB_BRACE) as $file) {
243: | // If directory add to path array
244: | if (is_dir($file)) {
245: | $directory[] = $file;
246: | }
247: |
248: | // Add the file to the files to be deleted array
249: | $files[] = $file;
250: | }
251: | }
252: |
253: | // Create the new storage folder
254: | if (!is_dir($base_new)) {
255: | mkdir($base_new, 0777);
256: | }
257: |
258: | // Copy the
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: | // Must not have a path before files and directories can be moved
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: | // To fix storage location
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: | // Remove old directories and files
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: | // Modify the config files
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: | * Admin
345: | *
346: | * @return void
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: | // 1. // 1. We need to copy the files, as rename cannot be used on any directory, the executing script is running under
401: | $files = [];
402: |
403: | // Make path into an array
404: | $directory = [$base_old];
405: |
406: | // While the path array is still populated keep looping through
407: | while (count($directory) != 0) {
408: | $next = array_shift($directory);
409: |
410: | foreach (glob(rtrim($next, '/') . '/{*,.[!.]*,..?*}', GLOB_BRACE) as $file) {
411: | // If directory add to path array
412: | if (is_dir($file)) {
413: | $directory[] = $file;
414: | }
415: |
416: | // Add the file to the files to be deleted array
417: | $files[] = $file;
418: | }
419: | }
420: |
421: | // 2. Create the new admin folder name
422: | if (!is_dir($base_new)) {
423: | mkdir($base_new, 0777);
424: | }
425: |
426: | // 3. split the file copies into chunks.
427: | $total = count($files);
428: | $limit = 200;
429: |
430: | $start = ($page - 1) * $limit;
431: | $end = ($start > ($total - $limit)) ? $total : ($start + $limit);
432: |
433: | // 4. Copy the files across
434: | foreach (array_slice($files, $start, $end) as $file) {
435: | $destination = substr($file, strlen($base_old));
436: |
437: | // Must not have a path before files and directories can be moved
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: | // Update the old config files
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: | // 6. redirect to the new admin
500: | $json['redirect'] = str_replace('&amp;', '&', 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: | * Delete
510: | *
511: | * @return void
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: | // Storage directory exists
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: | // Admin directory exists
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: | // Delete old admin directory
556: | $directory = [$path];
557: |
558: | // Remove paths
559: | foreach ($directory as $path) {
560: | $files = [];
561: |
562: | // While the path array is still populated keep looping through
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: | // If directory add to path array
569: | if (is_dir($file)) {
570: | $directory[] = $file;
571: | }
572: |
573: | // Add the file to the files to be deleted array
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: |

OpenCart API API documentation generated by ApiGen dev-master