1: <?php
2: namespace Opencart\Admin\Controller\Marketplace;
3: /**
4: * Class Installer
5: *
6: * @package Opencart\Admin\Controller\Marketplace
7: */
8: class Installer extends \Opencart\System\Engine\Controller {
9: /**
10: * Index
11: *
12: * @return void
13: */
14: public function index(): void {
15: $this->load->language('marketplace/installer');
16:
17: $this->document->setTitle($this->language->get('heading_title'));
18:
19: $data['breadcrumbs'] = [];
20:
21: $data['breadcrumbs'][] = [
22: 'text' => $this->language->get('text_home'),
23: 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
24: ];
25:
26: $data['breadcrumbs'][] = [
27: 'text' => $this->language->get('heading_title'),
28: 'href' => $this->url->link('marketplace/installer', 'user_token=' . $this->session->data['user_token'])
29: ];
30:
31: // Use the configuration option to get the max file size
32: $data['error_upload_size'] = sprintf($this->language->get('error_file_size'), ini_get('upload_max_filesize'));
33:
34: $data['config_file_max_size'] = ((int)preg_filter('/[^0-9]/', '', ini_get('upload_max_filesize')) * 1024 * 1024);
35:
36: $data['upload'] = $this->url->link('tool/installer.upload', 'user_token=' . $this->session->data['user_token']);
37:
38: $data['list'] = $this->getList();
39:
40: if (isset($this->request->get['filter_extension_download_id'])) {
41: $data['filter_extension_download_id'] = (int)$this->request->get['filter_extension_download_id'];
42: } else {
43: $data['filter_extension_download_id'] = '';
44: }
45:
46: $data['user_token'] = $this->session->data['user_token'];
47:
48: $data['header'] = $this->load->controller('common/header');
49: $data['column_left'] = $this->load->controller('common/column_left');
50: $data['footer'] = $this->load->controller('common/footer');
51:
52: $this->response->setOutput($this->load->view('marketplace/installer', $data));
53: }
54:
55: /**
56: * List
57: *
58: * @return void
59: */
60: public function list(): void {
61: $this->load->language('marketplace/installer');
62:
63: $this->response->setOutput($this->getList());
64: }
65:
66: /**
67: * Get List
68: *
69: * @return string
70: */
71: public function getList(): string {
72: $this->load->language('marketplace/installer');
73:
74: if (isset($this->request->get['filter_extension_download_id'])) {
75: $filter_extension_download_id = (int)$this->request->get['filter_extension_download_id'];
76: } else {
77: $filter_extension_download_id = '';
78: }
79:
80: if (isset($this->request->get['sort'])) {
81: $sort = (string)$this->request->get['sort'];
82: } else {
83: $sort = 'name';
84: }
85:
86: if (isset($this->request->get['order'])) {
87: $order = (string)$this->request->get['order'];
88: } else {
89: $order = 'ASC';
90: }
91:
92: if (isset($this->request->get['page'])) {
93: $page = (int)$this->request->get['page'];
94: } else {
95: $page = 1;
96: }
97:
98: $this->load->model('setting/extension');
99:
100: // Look for any new extensions
101: $files = glob(DIR_STORAGE . 'marketplace/*.ocmod.zip');
102:
103: foreach ($files as $file) {
104: $code = basename($file, '.ocmod.zip');
105:
106: $install_info = $this->model_setting_extension->getInstallByCode($code);
107:
108: if (!$install_info) {
109: // Unzip the files
110: $zip = new \ZipArchive();
111:
112: if ($zip->open($file, \ZipArchive::RDONLY)) {
113: $install_info = json_decode($zip->getFromName('install.json'), true);
114:
115: if ($install_info) {
116: $keys = [
117: 'extension_id',
118: 'extension_download_id',
119: 'name',
120: 'description',
121: 'code',
122: 'version',
123: 'author',
124: 'link'
125: ];
126:
127: foreach ($keys as $key) {
128: if (!isset($install_info[$key])) {
129: $install_info[$key] = '';
130: }
131: }
132:
133: $extension_data = [
134: 'extension_id' => $install_info['extension_id'],
135: 'extension_download_id' => $install_info['extension_download_id'],
136: 'name' => strip_tags($install_info['name']),
137: 'description' => nl2br(strip_tags($install_info['description'])),
138: 'code' => $code,
139: 'version' => $install_info['version'],
140: 'author' => $install_info['author'],
141: 'link' => $install_info['link']
142: ];
143:
144: $this->model_setting_extension->addInstall($extension_data);
145: }
146:
147: $zip->close();
148: }
149: }
150: }
151:
152: $data['extensions'] = [];
153:
154: $filter_data = [
155: 'filter_extension_download_id' => $filter_extension_download_id,
156: 'sort' => $sort,
157: 'order' => $order,
158: 'start' => ($page - 1) * $this->config->get('config_pagination_admin'),
159: 'limit' => $this->config->get('config_pagination_admin')
160: ];
161:
162: $results = $this->model_setting_extension->getInstalls($filter_data);
163:
164: foreach ($results as $result) {
165: if ($result['extension_id']) {
166: $link = $this->url->link('marketplace/marketplace.info', 'user_token=' . $this->session->data['user_token'] . '&extension_id=' . $result['extension_id']);
167: } elseif ($result['link']) {
168: $link = $result['link'];
169: } else {
170: $link = '';
171: }
172:
173: $data['extensions'][] = [
174: 'extension_install_id' => $result['extension_install_id'],
175: 'name' => $result['name'],
176: 'description' => $result['description'],
177: 'code' => $result['code'],
178: 'version' => $result['version'],
179: 'author' => $result['author'],
180: 'status' => $result['status'],
181: 'link' => $link,
182: 'date_added' => date($this->language->get('date_format_short'), strtotime($result['date_added'])),
183: 'install' => $this->url->link('marketplace/installer.install', 'user_token=' . $this->session->data['user_token'] . '&extension_install_id=' . $result['extension_install_id']),
184: 'uninstall' => $this->url->link('marketplace/installer.uninstall', 'user_token=' . $this->session->data['user_token'] . '&extension_install_id=' . $result['extension_install_id']),
185: 'delete' => $this->url->link('marketplace/installer.delete', 'user_token=' . $this->session->data['user_token'] . '&extension_install_id=' . $result['extension_install_id'])
186: ];
187: }
188:
189: $url = '';
190:
191: if (isset($this->request->get['filter_extension_id'])) {
192: $url .= '&filter_extension_id=' . $this->request->get['filter_extension_id'];
193: }
194:
195: if ($order == 'ASC') {
196: $url .= '&order=DESC';
197: } else {
198: $url .= '&order=ASC';
199: }
200:
201: $data['sort_name'] = $this->url->link('marketplace/installer.list', 'user_token=' . $this->session->data['user_token'] . '&sort=name' . $url);
202: $data['sort_version'] = $this->url->link('marketplace/installer.list', 'user_token=' . $this->session->data['user_token'] . '&sort=version' . $url);
203: $data['sort_date_added'] = $this->url->link('marketplace/installer.list', 'user_token=' . $this->session->data['user_token'] . '&sort=date_added' . $url);
204:
205: $extension_total = $this->model_setting_extension->getTotalInstalls($filter_data);
206:
207: $data['pagination'] = $this->load->controller('common/pagination', [
208: 'total' => $extension_total,
209: 'page' => $page,
210: 'limit' => $this->config->get('config_pagination_admin'),
211: 'url' => $this->url->link('marketplace/installer.list', 'user_token=' . $this->session->data['user_token'] . '&page={page}')
212: ]);
213:
214: $data['results'] = sprintf($this->language->get('text_pagination'), ($extension_total) ? (($page - 1) * $this->config->get('config_pagination_admin')) + 1 : 0, ((($page - 1) * $this->config->get('config_pagination_admin')) > ($extension_total - $this->config->get('config_pagination_admin'))) ? $extension_total : ((($page - 1) * $this->config->get('config_pagination_admin')) + $this->config->get('config_pagination_admin')), $extension_total, ceil($extension_total / $this->config->get('config_pagination_admin')));
215:
216: $data['sort'] = $sort;
217: $data['order'] = $order;
218:
219: return $this->load->view('marketplace/installer_extension', $data);
220: }
221:
222: /**
223: * Upload
224: *
225: * @return void
226: */
227: public function upload(): void {
228: $this->load->language('marketplace/installer');
229:
230: $json = [];
231:
232: // 1. Validate the file uploaded.
233: if (isset($this->request->files['file']['name'])) {
234: $filename = basename($this->request->files['file']['name']);
235: $code = basename($filename, '.ocmod.zip');
236:
237: // 2. Validate the filename.
238: if (!oc_validate_length($filename, 1, 128)) {
239: $json['error'] = $this->language->get('error_filename');
240: }
241:
242: // 3. Validate is ocmod file.
243: if (substr($filename, -10) != '.ocmod.zip') {
244: $json['error'] = $this->language->get('error_file_type');
245: }
246:
247: // 4. check if there is already a file
248: $file = DIR_STORAGE . 'marketplace/' . $filename;
249:
250: if (is_file($file)) {
251: $json['error'] = $this->language->get('error_file_exists');
252:
253: unlink($this->request->files['file']['tmp_name']);
254: }
255:
256: if ($this->request->files['file']['error'] != UPLOAD_ERR_OK) {
257: $json['error'] = $this->language->get('error_upload_' . $this->request->files['file']['error']);
258: }
259:
260: if ($this->model_setting_extension->getInstallByCode($code)) {
261: $json['error'] = $this->language->get('error_installed');
262: }
263: } else {
264: $json['error'] = $this->language->get('error_upload');
265: }
266:
267: // 5. Validate if the file can be opened and there is install.json that can be read.
268: if (!$json) {
269: move_uploaded_file($this->request->files['file']['tmp_name'], $file);
270:
271: // Unzip the files
272: $zip = new \ZipArchive();
273:
274: if ($zip->open($file, \ZipArchive::RDONLY)) {
275: $install_info = json_decode($zip->getFromName('install.json'), true);
276:
277: if ($install_info) {
278: $keys = [
279: 'extension_id',
280: 'extension_download_id',
281: 'name',
282: 'description',
283: 'code',
284: 'version',
285: 'author',
286: 'link'
287: ];
288:
289: foreach ($keys as $key) {
290: if (!isset($install_info[$key])) {
291: $install_info[$key] = '';
292: }
293: }
294: } else {
295: $json['error'] = $this->language->get('error_install');
296: }
297:
298: $zip->close();
299: } else {
300: $json['error'] = $this->language->get('error_unzip');
301: }
302: }
303:
304: if (!$json) {
305: $extension_data = [
306: 'extension_id' => 0,
307: 'extension_download_id' => 0,
308: 'name' => $install_info['name'],
309: 'description' => $install_info['description'],
310: 'code' => $code,
311: 'version' => $install_info['version'],
312: 'author' => $install_info['author'],
313: 'link' => $install_info['link']
314: ];
315:
316: $this->load->model('setting/extension');
317:
318: $this->model_setting_extension->addInstall($extension_data);
319:
320: $json['success'] = $this->language->get('text_upload');
321: }
322:
323: $this->response->addHeader('Content-Type: application/json');
324: $this->response->setOutput(json_encode($json));
325: }
326:
327: /**
328: * Install
329: *
330: * @return void
331: */
332: public function install(): void {
333: $this->load->language('marketplace/installer');
334:
335: $json = [];
336:
337: if (isset($this->request->get['extension_install_id'])) {
338: $extension_install_id = (int)$this->request->get['extension_install_id'];
339: } else {
340: $extension_install_id = 0;
341: }
342:
343: if (isset($this->request->get['page'])) {
344: $page = (int)$this->request->get['page'];
345: } else {
346: $page = 1;
347: }
348:
349: if (!$this->user->hasPermission('modify', 'marketplace/installer')) {
350: $json['error'] = $this->language->get('error_permission');
351: }
352:
353: $this->load->model('setting/extension');
354:
355: $extension_install_info = $this->model_setting_extension->getInstall($extension_install_id);
356:
357: if ($extension_install_info) {
358: $file = DIR_STORAGE . 'marketplace/' . $extension_install_info['code'] . '.ocmod.zip';
359:
360: if (!is_file($file)) {
361: $json['error'] = sprintf($this->language->get('error_file'), $extension_install_info['code'] . '.ocmod.zip');
362: }
363:
364: if ($page == 1 && is_dir(DIR_EXTENSION . $extension_install_info['code'] . '/')) {
365: $json['error'] = sprintf($this->language->get('error_directory_exists'), $extension_install_info['code'] . '/');
366: }
367:
368: if ($page > 1 && !is_dir(DIR_EXTENSION . $extension_install_info['code'] . '/')) {
369: $json['error'] = sprintf($this->language->get('error_directory'), $extension_install_info['code'] . '/');
370: }
371: } else {
372: $json['error'] = $this->language->get('error_extension');
373: }
374:
375: if (!$json) {
376: // Unzip the files
377: $zip = new \ZipArchive();
378:
379: if ($zip->open($file, \ZipArchive::RDONLY)) {
380: $total = $zip->numFiles;
381: $limit = 200;
382:
383: $start = ($page - 1) * $limit;
384: $end = $start > ($total - $limit) ? $total : ($start + $limit);
385:
386: // Check if any of the files already exist.
387: for ($i = $start; $i < $end; $i++) {
388: $source = $zip->getNameIndex($i);
389:
390: $destination = str_replace('\\', '/', $source);
391:
392: // Only extract the contents of the upload folder
393: $path = $extension_install_info['code'] . '/' . $destination;
394: $base = DIR_EXTENSION;
395: $prefix = '';
396:
397: // OCMOD files should not be copied across
398: if (substr($destination, 0, 6) == 'ocmod/') {
399: continue;
400: }
401:
402: // image > image
403: if (substr($destination, 0, 6) == 'image/') {
404: $path = $destination;
405: $base = substr(DIR_IMAGE, 0, -6);
406: }
407:
408: // We need to store the path differently for vendor folders.
409: if (substr($destination, 0, 15) == 'system/storage/') {
410: $path = substr($destination, 15);
411: $base = DIR_STORAGE;
412: $prefix = 'system/storage/';
413: }
414:
415: // Must not have a path before files and directories can be moved
416: $path_new = '';
417:
418: $directories = explode('/', dirname($path));
419:
420: foreach ($directories as $directory) {
421: if (!$path_new) {
422: $path_new = $directory;
423: } else {
424: $path_new = $path_new . '/' . $directory;
425: }
426:
427: // To fix storage location
428: if (!is_dir($base . $path_new . '/') && mkdir($base . $path_new . '/', 0777)) {
429: $this->model_setting_extension->addPath($extension_install_id, $prefix . $path_new);
430: }
431: }
432:
433: // If check if the path is not directory and check there is no existing file
434: if (substr($source, -1) != '/') {
435: if (!is_file($base . $path) && file_put_contents($base . $path, $zip->getFromIndex($i)) !== false) {
436: $this->model_setting_extension->addPath($extension_install_id, $prefix . $path);
437: }
438: }
439: }
440:
441: $zip->close();
442:
443: $this->model_setting_extension->editStatus($extension_install_id, true);
444: } else {
445: $json['error'] = $this->language->get('error_unzip');
446: }
447: }
448:
449: if (!$json) {
450: $json['text'] = sprintf($this->language->get('text_install'), $start, $end, $total);
451:
452: $url = '';
453:
454: if (isset($this->request->get['extension_install_id'])) {
455: $url .= '&extension_install_id=' . $this->request->get['extension_install_id'];
456: }
457:
458: if ($end < $total) {
459: $json['next'] = $this->url->link('marketplace/installer.install', 'user_token=' . $this->session->data['user_token'] . $url . '&page=' . ($page + 1), true);
460: } else {
461: $json['next'] = $this->url->link('marketplace/installer.xml', 'user_token=' . $this->session->data['user_token'] . $url, true);
462: }
463: }
464:
465: $this->response->addHeader('Content-Type: application/json');
466: $this->response->setOutput(json_encode($json));
467: }
468:
469: /**
470: * Xml
471: *
472: * @return void
473: */
474: public function xml(): void {
475: $this->load->language('marketplace/installer');
476:
477: $json = [];
478:
479: if (isset($this->request->get['extension_install_id'])) {
480: $extension_install_id = $this->request->get['extension_install_id'];
481: } else {
482: $extension_install_id = 0;
483: }
484:
485: if (!$this->user->hasPermission('modify', 'marketplace/installer')) {
486: $json['error'] = $this->language->get('error_permission');
487: }
488:
489: $this->load->model('setting/extension');
490:
491: $extension_install_info = $this->model_setting_extension->getInstall($extension_install_id);
492:
493: if ($extension_install_info) {
494: $file = DIR_STORAGE . 'marketplace/' . $extension_install_info['code'] . '.ocmod.zip';
495:
496: if (!is_file($file)) {
497: $json['error'] = sprintf($this->language->get('error_file'), $extension_install_info['code'] . '.ocmod.zip');
498: }
499: } else {
500: $json['error'] = $this->language->get('error_extension');
501: }
502:
503: if (!$json) {
504: // Unzip the files
505: $zip = new \ZipArchive();
506:
507: if ($zip->open($file, \ZipArchive::RDONLY)) {
508: $this->load->model('setting/modification');
509:
510: // If xml file just put it straight into the DB
511: // Check if any of the files already exist.
512: for ($i = 0; $i < $zip->numFiles; $i++) {
513: $source = $zip->getNameIndex($i);
514:
515: if (substr($source, 0, 6) == 'ocmod/' && substr($source, -10) == '.ocmod.xml') {
516: $code = basename($source, '.ocmod.xml');
517:
518: // Check to see if the modification is already installed or not.
519: $modification_info = $this->model_setting_modification->getModificationByCode($code);
520:
521: if (!$modification_info) {
522: $xml = $zip->getFromName($source);
523:
524: if ($xml) {
525: try {
526: $dom = new \DOMDocument('1.0', 'UTF-8');
527: $dom->loadXml($xml);
528:
529: $name = $dom->getElementsByTagName('name')->item(0);
530:
531: if ($name) {
532: $name = $name->nodeValue;
533: } else {
534: $name = '';
535: }
536:
537: $description = $dom->getElementsByTagName('description')->item(0);
538:
539: if ($description) {
540: $description = $description->nodeValue;
541: } else {
542: $description = '';
543: }
544:
545: $author = $dom->getElementsByTagName('author')->item(0);
546:
547: if ($author) {
548: $author = $author->nodeValue;
549: } else {
550: $author = '';
551: }
552:
553: $version = $dom->getElementsByTagName('version')->item(0);
554:
555: if ($version) {
556: $version = $version->nodeValue;
557: } else {
558: $version = '';
559: }
560:
561: $link = $dom->getElementsByTagName('link')->item(0);
562:
563: if ($link) {
564: $link = $link->nodeValue;
565: } else {
566: $link = '';
567: }
568:
569: $modification_data = [
570: 'extension_install_id' => $extension_install_id,
571: 'name' => strip_tags($name),
572: 'description' => nl2br(strip_tags($description)),
573: 'code' => $code,
574: 'author' => $author,
575: 'version' => $version,
576: 'link' => $link,
577: 'xml' => $xml,
578: 'status' => 0
579: ];
580:
581: $this->model_setting_modification->addModification($modification_data);
582: } catch (\Exception $exception) {
583: $json['error'] = sprintf($this->language->get('error_exception'), $exception->getCode(), $exception->getMessage(), $exception->getFile(), $exception->getLine());
584: }
585: }
586: }
587: }
588: }
589: } else {
590: $json['error'] = $this->language->get('error_unzip');
591: }
592: }
593:
594: if (!$json) {
595: $json['text'] = $this->language->get('text_vendor');
596:
597: $json['next'] = str_replace('&amp;', '&', $this->url->link('marketplace/installer.vendor', 'user_token=' . $this->session->data['user_token'], true));
598: }
599:
600: $this->response->addHeader('Content-Type: application/json');
601: $this->response->setOutput(json_encode($json));
602: }
603:
604: /**
605: * Vendor
606: *
607: * Generate new autoloader file
608: *
609: * @return void
610: */
611: public function vendor(): void {
612: $this->load->language('marketplace/installer');
613:
614: $json = [];
615:
616: if (!$this->user->hasPermission('modify', 'marketplace/installer')) {
617: $json['error'] = $this->language->get('error_permission');
618: }
619:
620: if (!$json) {
621: // Generate php autoload file
622: $code = '<?php' . "\n";
623:
624: $files = glob(DIR_STORAGE . 'vendor/*/*/composer.json');
625:
626: foreach ($files as $file) {
627: $output = json_decode(file_get_contents($file), true);
628:
629: $code .= '// ' . $output['name'] . "\n";
630:
631: if (isset($output['autoload'])) {
632: $directory = substr(dirname($file), strlen(DIR_STORAGE . 'vendor/'));
633:
634: // Autoload psr-4 files
635: if (isset($output['autoload']['psr-4'])) {
636: $autoload = $output['autoload']['psr-4'];
637:
638: foreach ($autoload as $namespace => $path) {
639: if (!is_array($path)) {
640: $code .= '$autoloader->register(\'' . rtrim($namespace, '\\') . '\', DIR_STORAGE . \'vendor/' . $directory . '/' . rtrim($path, '/') . '/' . '\', true);' . "\n";
641: } else {
642: foreach ($path as $value) {
643: $code .= '$autoloader->register(\'' . rtrim($namespace, '\\') . '\', DIR_STORAGE . \'vendor/' . $directory . '/' . rtrim($value, '/') . '/' . '\', true);' . "\n";
644: }
645: }
646: }
647: }
648:
649: // Autoload psr-0 files
650: if (isset($output['autoload']['psr-0'])) {
651: $autoload = $output['autoload']['psr-0'];
652:
653: foreach ($autoload as $namespace => $path) {
654: if (!is_array($path)) {
655: $code .= '$autoloader->register(\'' . rtrim($namespace, '\\') . '\', DIR_STORAGE . \'vendor/' . $directory . '/' . rtrim($path, '/') . '/' . '\', true);' . "\n";
656: } else {
657: foreach ($path as $value) {
658: $code .= '$autoloader->register(\'' . rtrim($namespace, '\\') . '\', DIR_STORAGE . \'vendor/' . $directory . '/' . rtrim($value, '/') . '/' . '\', true);' . "\n";
659: }
660: }
661: }
662: }
663:
664: // Autoload classmap
665: if (isset($output['autoload']['classmap'])) {
666: $autoload = [];
667:
668: $classmaps = $output['autoload']['classmap'];
669:
670: foreach ($classmaps as $classmap) {
671: $directories = [dirname($file) . '/' . $classmap];
672:
673: while (count($directories) != 0) {
674: $next = array_shift($directories);
675:
676: if (is_dir($next)) {
677: foreach (glob(trim($next, '/') . '/{*,.[!.]*,..?*}', GLOB_BRACE) as $file) {
678: if (is_dir($file)) {
679: $directories[] = $file . '/';
680: }
681:
682: if (is_file($file)) {
683: $namespace = substr(dirname($file), strlen(DIR_STORAGE . 'vendor/' . $directory . $classmap) + 1);
684:
685: if ($namespace) {
686: $autoload[$namespace] = substr(dirname($file), strlen(DIR_STORAGE . 'vendor/'));
687: }
688: }
689: }
690: }
691: }
692: }
693:
694: foreach ($autoload as $namespace => $path) {
695: $code .= '$autoloader->register(\'' . rtrim($namespace, '\\') . '\', DIR_STORAGE . \'vendor/' . rtrim($path, '/') . '/' . '\', true);' . "\n";
696: }
697: }
698:
699: // Autoload files
700: if (isset($output['autoload']['files'])) {
701: $files = $output['autoload']['files'];
702:
703: foreach ($files as $file) {
704: $code .= 'if (is_file(DIR_STORAGE . \'vendor/' . $directory . '/' . $file . '\')) {' . "\n";
705: $code .= ' require_once(DIR_STORAGE . \'vendor/' . $directory . '/' . $file . '\');' . "\n";
706: $code .= '}' . "\n";
707: }
708: }
709: }
710:
711: $code .= "\n";
712: }
713:
714: file_put_contents(DIR_SYSTEM . 'vendor.php', trim($code));
715:
716: $json['success'] = $this->language->get('text_success');
717: }
718:
719: $this->response->addHeader('Content-Type: application/json');
720: $this->response->setOutput(json_encode($json));
721: }
722:
723: /**
724: * Uninstall
725: *
726: * @return void
727: */
728: public function uninstall(): void {
729: $this->load->language('marketplace/installer');
730:
731: $json = [];
732:
733: if (isset($this->request->get['extension_install_id'])) {
734: $extension_install_id = (int)$this->request->get['extension_install_id'];
735: } else {
736: $extension_install_id = 0;
737: }
738:
739: if (!$this->user->hasPermission('modify', 'marketplace/installer')) {
740: $json['error'] = $this->language->get('error_permission');
741: }
742:
743: $this->load->model('setting/extension');
744:
745: $extension_install_info = $this->model_setting_extension->getInstall($extension_install_id);
746:
747: if ($extension_install_info) {
748: if ($extension_install_info['code'] == 'opencart') {
749: $json['error'] = $this->language->get('error_default');
750: }
751:
752: // Validate if extension being uninstalled
753: $extension_total = $this->model_setting_extension->getTotalExtensionsByExtension($extension_install_info['code']);
754:
755: if ($extension_total) {
756: $json['error'] = sprintf($this->language->get('error_uninstall'), $extension_total);
757: }
758: } else {
759: $json['error'] = $this->language->get('error_extension');
760: }
761:
762: if (!$json) {
763: $files = [];
764:
765: // Make path into an array
766: $directory = [DIR_EXTENSION . $extension_install_info['code'] . '/'];
767:
768: // While the path array is still populated keep looping through
769: while (count($directory) != 0) {
770: $next = array_shift($directory);
771:
772: if (is_dir($next)) {
773: foreach (glob(rtrim($next, '/') . '/{*,.[!.]*,..?*}', GLOB_BRACE) as $file) {
774: // If directory add to path array
775: $directory[] = $file;
776: }
777: }
778:
779: // Add the file to the files to be deleted array
780: $files[] = $next;
781: }
782:
783: // Reverse sort the file array
784: rsort($files);
785:
786: foreach ($files as $file) {
787: // If file just delete
788: if (is_file($file)) {
789: unlink($file);
790: }
791:
792: // If directory use the remove directory function
793: if (is_dir($file)) {
794: rmdir($file);
795: }
796: }
797:
798: // Remove extension directory and files
799: $results = $this->model_setting_extension->getPathsByExtensionInstallId($extension_install_id);
800:
801: rsort($results);
802:
803: foreach ($results as $result) {
804: $path = '';
805:
806: // Remove images
807: if (substr($result['path'], 0, 6) == 'image/') {
808: $path = DIR_IMAGE . substr($result['path'], 6);
809: }
810:
811: // Remove vendor files or any connected extensions that was also installed.
812: if (substr($result['path'], 0, 15) == 'system/storage/') {
813: $path = DIR_STORAGE . substr($result['path'], 15);
814: }
815:
816: // Check if the location exists or not
817: $path_total = $this->model_setting_extension->getTotalPaths($result['path']);
818:
819: if ($path_total < 2) {
820: if (is_file($path)) {
821: unlink($path);
822: }
823:
824: if (is_dir($path)) {
825: rmdir($path);
826: }
827: }
828:
829: $this->model_setting_extension->deletePath($result['extension_path_id']);
830: }
831:
832: // Remove extension directory
833: $this->model_setting_extension->editStatus($extension_install_id, false);
834:
835: // Remove any OCMOD modifications
836: $this->load->model('setting/modification');
837:
838: $this->model_setting_modification->deleteModificationsByExtensionInstallId($extension_install_id);
839:
840: $json['text'] = $this->language->get('text_vendor');
841:
842: $url = '';
843:
844: if (isset($this->request->get['extension_install_id'])) {
845: $url .= '&extension_install_id=' . $this->request->get['extension_install_id'];
846: }
847:
848: $json['next'] = $this->url->link('marketplace/installer.vendor', 'user_token=' . $this->session->data['user_token'] . $url, true);
849: }
850:
851: $this->response->addHeader('Content-Type: application/json');
852: $this->response->setOutput(json_encode($json));
853: }
854:
855: /**
856: * Delete
857: *
858: * @return void
859: */
860: public function delete(): void {
861: $this->load->language('marketplace/installer');
862:
863: $json = [];
864:
865: if (isset($this->request->get['extension_install_id'])) {
866: $extension_install_id = (int)$this->request->get['extension_install_id'];
867: } else {
868: $extension_install_id = 0;
869: }
870:
871: if (!$this->user->hasPermission('modify', 'marketplace/installer')) {
872: $json['error'] = $this->language->get('error_permission');
873: }
874:
875: $this->load->model('setting/extension');
876:
877: $extension_install_info = $this->model_setting_extension->getInstall($extension_install_id);
878:
879: if ($extension_install_info && $extension_install_info['code'] == 'opencart') {
880: $json['error'] = $this->language->get('error_default');
881: }
882:
883: if (!$extension_install_info) {
884: $json['error'] = $this->language->get('error_extension');
885: }
886:
887: if (!$json) {
888: $file = DIR_STORAGE . 'marketplace/' . $extension_install_info['code'] . '.ocmod.zip';
889:
890: // Remove file
891: if (is_file($file)) {
892: unlink($file);
893: }
894:
895: $this->model_setting_extension->deleteInstall($extension_install_id);
896:
897: $json['success'] = $this->language->get('text_success');
898: }
899:
900: $this->response->addHeader('Content-Type: application/json');
901: $this->response->setOutput(json_encode($json));
902: }
903: }
904: