1: <?php
2: namespace Opencart\Admin\Controller\Catalog;
3: /**
4: * Class Download
5: *
6: * @package Opencart\Admin\Controller\Catalog
7: */
8: class Download extends \Opencart\System\Engine\Controller {
9: /**
10: * Index
11: *
12: * @return void
13: */
14: public function index(): void {
15: $this->load->language('catalog/download');
16:
17: $this->document->setTitle($this->language->get('heading_title'));
18:
19: $url = '';
20:
21: if (isset($this->request->get['sort'])) {
22: $url .= '&sort=' . $this->request->get['sort'];
23: }
24:
25: if (isset($this->request->get['order'])) {
26: $url .= '&order=' . $this->request->get['order'];
27: }
28:
29: if (isset($this->request->get['page'])) {
30: $url .= '&page=' . $this->request->get['page'];
31: }
32:
33: $data['breadcrumbs'] = [];
34:
35: $data['breadcrumbs'][] = [
36: 'text' => $this->language->get('text_home'),
37: 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
38: ];
39:
40: $data['breadcrumbs'][] = [
41: 'text' => $this->language->get('heading_title'),
42: 'href' => $this->url->link('catalog/download', 'user_token=' . $this->session->data['user_token'] . $url)
43: ];
44:
45: $data['add'] = $this->url->link('catalog/download.form', 'user_token=' . $this->session->data['user_token'] . $url);
46: $data['delete'] = $this->url->link('catalog/download.delete', 'user_token=' . $this->session->data['user_token']);
47:
48: $data['user_token'] = $this->session->data['user_token'];
49:
50: $data['list'] = $this->controller_catalog_download->getList();
51:
52: $data['header'] = $this->load->controller('common/header');
53: $data['column_left'] = $this->load->controller('common/column_left');
54: $data['footer'] = $this->load->controller('common/footer');
55:
56: $this->response->setOutput($this->load->view('catalog/download', $data));
57: }
58:
59: /**
60: * List
61: *
62: * @return void
63: */
64: public function list(): void {
65: $this->load->language('catalog/download');
66:
67: $this->response->setOutput($this->controller_catalog_download->getList());
68: }
69:
70: /**
71: * Get List
72: *
73: * @return string
74: */
75: protected function getList(): string {
76: if (isset($this->request->get['sort'])) {
77: $sort = (string)$this->request->get['sort'];
78: } else {
79: $sort = 'dd.name';
80: }
81:
82: if (isset($this->request->get['order'])) {
83: $order = (string)$this->request->get['order'];
84: } else {
85: $order = 'ASC';
86: }
87:
88: if (isset($this->request->get['page'])) {
89: $page = (int)$this->request->get['page'];
90: } else {
91: $page = 1;
92: }
93:
94: $url = '';
95:
96: if (isset($this->request->get['sort'])) {
97: $url .= '&sort=' . $this->request->get['sort'];
98: }
99:
100: if (isset($this->request->get['order'])) {
101: $url .= '&order=' . $this->request->get['order'];
102: }
103:
104: if (isset($this->request->get['page'])) {
105: $url .= '&page=' . $this->request->get['page'];
106: }
107:
108: $data['action'] = $this->url->link('catalog/download.list', 'user_token=' . $this->session->data['user_token'] . $url);
109:
110: $data['downloads'] = [];
111:
112: $filter_data = [
113: 'sort' => $sort,
114: 'order' => $order,
115: 'start' => ($page - 1) * $this->config->get('config_pagination_admin'),
116: 'limit' => $this->config->get('config_pagination_admin')
117: ];
118:
119: $this->load->model('catalog/download');
120:
121: $results = $this->model_catalog_download->getDownloads($filter_data);
122:
123: foreach ($results as $result) {
124: $data['downloads'][] = [
125: 'download_id' => $result['download_id'],
126: 'name' => $result['name'],
127: 'date_added' => date($this->language->get('date_format_short'), strtotime($result['date_added'])),
128: 'edit' => $this->url->link('catalog/download.form', 'user_token=' . $this->session->data['user_token'] . '&download_id=' . $result['download_id'] . $url)
129: ];
130: }
131:
132: $url = '';
133:
134: if ($order == 'ASC') {
135: $url .= '&order=DESC';
136: } else {
137: $url .= '&order=ASC';
138: }
139:
140: $data['sort_name'] = $this->url->link('catalog/download.list', 'user_token=' . $this->session->data['user_token'] . '&sort=dd.name' . $url);
141: $data['sort_date_added'] = $this->url->link('catalog/download.list', 'user_token=' . $this->session->data['user_token'] . '&sort=d.date_added' . $url);
142:
143: $url = '';
144:
145: if (isset($this->request->get['sort'])) {
146: $url .= '&sort=' . $this->request->get['sort'];
147: }
148:
149: if (isset($this->request->get['order'])) {
150: $url .= '&order=' . $this->request->get['order'];
151: }
152:
153: $download_total = $this->model_catalog_download->getTotalDownloads();
154:
155: $data['pagination'] = $this->load->controller('common/pagination', [
156: 'total' => $download_total,
157: 'page' => $page,
158: 'limit' => $this->config->get('config_pagination_admin'),
159: 'url' => $this->url->link('catalog/download.list', 'user_token=' . $this->session->data['user_token'] . $url . '&page={page}')
160: ]);
161:
162: $data['results'] = sprintf($this->language->get('text_pagination'), ($download_total) ? (($page - 1) * $this->config->get('config_pagination_admin')) + 1 : 0, ((($page - 1) * $this->config->get('config_pagination_admin')) > ($download_total - $this->config->get('config_pagination_admin'))) ? $download_total : ((($page - 1) * $this->config->get('config_pagination_admin')) + $this->config->get('config_pagination_admin')), $download_total, ceil($download_total / $this->config->get('config_pagination_admin')));
163:
164: $data['sort'] = $sort;
165: $data['order'] = $order;
166:
167: return $this->load->view('catalog/download_list', $data);
168: }
169:
170: /**
171: * Form
172: *
173: * @return void
174: */
175: public function form(): void {
176: $this->load->language('catalog/download');
177:
178: $this->document->setTitle($this->language->get('heading_title'));
179:
180: $data['text_form'] = !isset($this->request->get['download_id']) ? $this->language->get('text_add') : $this->language->get('text_edit');
181:
182: // Use the ini_get('upload_max_filesize') for the max file size
183: $data['error_upload_size'] = sprintf($this->language->get('error_upload_size'), ini_get('upload_max_filesize'));
184:
185: $data['config_file_max_size'] = ((int)preg_filter('/[^0-9]/', '', ini_get('upload_max_filesize')) * 1024 * 1024);
186:
187: $url = '';
188:
189: if (isset($this->request->get['sort'])) {
190: $url .= '&sort=' . $this->request->get['sort'];
191: }
192:
193: if (isset($this->request->get['order'])) {
194: $url .= '&order=' . $this->request->get['order'];
195: }
196:
197: if (isset($this->request->get['page'])) {
198: $url .= '&page=' . $this->request->get['page'];
199: }
200:
201: $data['breadcrumbs'] = [];
202:
203: $data['breadcrumbs'][] = [
204: 'text' => $this->language->get('text_home'),
205: 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
206: ];
207:
208: $data['breadcrumbs'][] = [
209: 'text' => $this->language->get('heading_title'),
210: 'href' => $this->url->link('catalog/download', 'user_token=' . $this->session->data['user_token'] . $url)
211: ];
212:
213: $data['save'] = $this->url->link('catalog/download.save', 'user_token=' . $this->session->data['user_token']);
214: $data['back'] = $this->url->link('catalog/download', 'user_token=' . $this->session->data['user_token'] . $url);
215: $data['upload'] = $this->url->link('catalog/download.upload', 'user_token=' . $this->session->data['user_token']);
216:
217: if (isset($this->request->get['download_id'])) {
218: $this->load->model('catalog/download');
219:
220: $download_info = $this->model_catalog_download->getDownload($this->request->get['download_id']);
221: }
222:
223: if (isset($this->request->get['download_id'])) {
224: $data['download_id'] = (int)$this->request->get['download_id'];
225: } else {
226: $data['download_id'] = 0;
227: }
228:
229: $this->load->model('localisation/language');
230:
231: $data['languages'] = $this->model_localisation_language->getLanguages();
232:
233: if (isset($this->request->get['download_id'])) {
234: $data['download_description'] = $this->model_catalog_download->getDescriptions($this->request->get['download_id']);
235: } else {
236: $data['download_description'] = [];
237: }
238:
239: if (!empty($download_info)) {
240: $data['filename'] = $download_info['filename'];
241: } else {
242: $data['filename'] = '';
243: }
244:
245: if (!empty($download_info)) {
246: $data['mask'] = $download_info['mask'];
247: } else {
248: $data['mask'] = '';
249: }
250:
251: $data['report'] = $this->getReport();
252:
253: $data['user_token'] = $this->session->data['user_token'];
254:
255: $data['header'] = $this->load->controller('common/header');
256: $data['column_left'] = $this->load->controller('common/column_left');
257: $data['footer'] = $this->load->controller('common/footer');
258:
259: $this->response->setOutput($this->load->view('catalog/download_form', $data));
260: }
261:
262: /**
263: * Save
264: *
265: * @return void
266: */
267: public function save(): void {
268: $this->load->language('catalog/download');
269:
270: $json = [];
271:
272: if (!$this->user->hasPermission('modify', 'catalog/download')) {
273: $json['error']['warning'] = $this->language->get('error_permission');
274: }
275:
276: foreach ($this->request->post['download_description'] as $language_id => $value) {
277: if (!oc_validate_length($value['name'], 3, 64)) {
278: $json['error']['name_' . $language_id] = $this->language->get('error_name');
279: }
280: }
281:
282: if (!oc_validate_length($this->request->post['filename'], 3, 128)) {
283: $json['error']['filename'] = $this->language->get('error_filename');
284: }
285:
286: if (substr(str_replace('\\', '/', realpath(DIR_DOWNLOAD . $this->request->post['filename'])), 0, strlen(DIR_DOWNLOAD)) != DIR_DOWNLOAD) {
287: $json['error']['filename'] = $this->language->get('error_directory');
288: }
289:
290: if (!is_file(DIR_DOWNLOAD . $this->request->post['filename'])) {
291: $json['error']['filename'] = $this->language->get('error_exists');
292: }
293:
294: if (!oc_validate_filename($this->request->post['filename'])) {
295: $json['error']['filename'] = $this->language->get('error_filename_character');
296: }
297:
298: if (!oc_validate_length($this->request->post['mask'], 3, 128)) {
299: $json['error']['mask'] = $this->language->get('error_mask');
300: }
301:
302: if (!oc_validate_filename($this->request->post['mask'])) {
303: $json['error']['mask'] = $this->language->get('error_mask_character');
304: }
305:
306: if (isset($json['error']) && !isset($json['error']['warning'])) {
307: $json['error']['warning'] = $this->language->get('error_warning');
308: }
309:
310: if (!$json) {
311: $this->load->model('catalog/download');
312:
313: if (!$this->request->post['download_id']) {
314: $json['download_id'] = $this->model_catalog_download->addDownload($this->request->post);
315: } else {
316: $this->model_catalog_download->editDownload($this->request->post['download_id'], $this->request->post);
317: }
318:
319: $json['success'] = $this->language->get('text_success');
320: }
321:
322: $this->response->addHeader('Content-Type: application/json');
323: $this->response->setOutput(json_encode($json));
324: }
325:
326: /**
327: * Delete
328: *
329: * @return void
330: */
331: public function delete(): void {
332: $this->load->language('catalog/download');
333:
334: $json = [];
335:
336: if (isset($this->request->post['selected'])) {
337: $selected = $this->request->post['selected'];
338: } else {
339: $selected = [];
340: }
341:
342: if (!$this->user->hasPermission('modify', 'catalog/download')) {
343: $json['error'] = $this->language->get('error_permission');
344: }
345:
346: $this->load->model('catalog/product');
347:
348: foreach ($selected as $download_id) {
349: $product_total = $this->model_catalog_product->getTotalDownloadsByDownloadId($download_id);
350:
351: if ($product_total) {
352: $json['error'] = sprintf($this->language->get('error_product'), $product_total);
353: }
354: }
355:
356: if (!$json) {
357: $this->load->model('catalog/download');
358:
359: foreach ($selected as $download_id) {
360: $this->model_catalog_download->deleteDownload($download_id);
361: }
362:
363: $json['success'] = $this->language->get('text_success');
364: }
365:
366: $this->response->addHeader('Content-Type: application/json');
367: $this->response->setOutput(json_encode($json));
368: }
369:
370: /**
371: * Report
372: *
373: * @return void
374: */
375: public function report(): void {
376: $this->load->language('catalog/download');
377:
378: $this->response->setOutput($this->getReport());
379: }
380:
381: /**
382: * Get Report
383: *
384: * @return string
385: */
386: private function getReport(): string {
387: if (isset($this->request->get['download_id'])) {
388: $download_id = (int)$this->request->get['download_id'];
389: } else {
390: $download_id = 0;
391: }
392:
393: if (isset($this->request->get['page']) && $this->request->get['route'] == 'catalog/download.report') {
394: $page = (int)$this->request->get['page'];
395: } else {
396: $page = 1;
397: }
398:
399: $limit = 10;
400:
401: $data['reports'] = [];
402:
403: $this->load->model('catalog/download');
404: $this->load->model('customer/customer');
405: $this->load->model('setting/store');
406:
407: $results = $this->model_catalog_download->getReports($download_id, ($page - 1) * $limit, $limit);
408:
409: foreach ($results as $result) {
410: $store_info = $this->model_setting_store->getStore($result['store_id']);
411:
412: if ($store_info) {
413: $store = $store_info['name'];
414: } elseif (!$result['store_id']) {
415: $store = $this->config->get('config_name');
416: } else {
417: $store = '';
418: }
419:
420: $data['reports'][] = [
421: 'ip' => $result['ip'],
422: 'account' => $this->model_customer_customer->getTotalCustomersByIp($result['ip']),
423: 'store' => $store,
424: 'country' => $result['country'],
425: 'date_added' => date($this->language->get('datetime_format'), strtotime($result['date_added'])),
426: 'filter_ip' => $this->url->link('customer/customer', 'user_token=' . $this->session->data['user_token'] . '&filter_ip=' . $result['ip'])
427: ];
428: }
429:
430: $report_total = $this->model_catalog_download->getTotalReports($download_id);
431:
432: $data['pagination'] = $this->load->controller('common/pagination', [
433: 'total' => $report_total,
434: 'page' => $page,
435: 'limit' => $limit,
436: 'url' => $this->url->link('catalog/download.report', 'user_token=' . $this->session->data['user_token'] . '&download_id=' . $download_id . '&page={page}')
437: ]);
438:
439: $data['results'] = sprintf($this->language->get('text_pagination'), ($report_total) ? (($page - 1) * $limit) + 1 : 0, ((($page - 1) * $limit) > ($report_total - $limit)) ? $report_total : ((($page - 1) * $limit) + $limit), $report_total, ceil($report_total / $limit));
440:
441: return $this->load->view('catalog/download_report', $data);
442: }
443:
444: /**
445: * Upload
446: *
447: * @return void
448: */
449: public function upload(): void {
450: $this->load->language('catalog/download');
451:
452: $json = [];
453:
454: // Check user has permission
455: if (!$this->user->hasPermission('modify', 'catalog/download')) {
456: $json['error'] = $this->language->get('error_permission');
457: }
458:
459: if (empty($this->request->files['file']['name']) || !is_file($this->request->files['file']['tmp_name'])) {
460: $json['error'] = $this->language->get('error_upload');
461: }
462:
463: if (!$json) {
464: // Sanitize the filename
465: $filename = basename(html_entity_decode($this->request->files['file']['name'], ENT_QUOTES, 'UTF-8'));
466:
467: // Validate the filename length
468: if ((oc_strlen($filename) < 3) || (oc_strlen($filename) > 128)) {
469: $json['error'] = $this->language->get('error_filename');
470: }
471:
472: // Allowed file extension types
473: $allowed = [];
474:
475: $extension_allowed = preg_replace('~\r?\n~', "\n", $this->config->get('config_file_ext_allowed'));
476:
477: $filetypes = explode("\n", $extension_allowed);
478:
479: foreach ($filetypes as $filetype) {
480: $allowed[] = trim($filetype);
481: }
482:
483: if (!in_array(strtolower(substr(strrchr($filename, '.'), 1)), $allowed)) {
484: $json['error'] = $this->language->get('error_file_type');
485: }
486:
487: // Allowed file mime types
488: $allowed = [];
489:
490: $mime_allowed = preg_replace('~\r?\n~', "\n", $this->config->get('config_file_mime_allowed'));
491:
492: $filetypes = explode("\n", $mime_allowed);
493:
494: foreach ($filetypes as $filetype) {
495: $allowed[] = trim($filetype);
496: }
497:
498: if (!in_array($this->request->files['file']['type'], $allowed)) {
499: $json['error'] = $this->language->get('error_file_type');
500: }
501:
502: // Return any upload error
503: if ($this->request->files['file']['error'] != UPLOAD_ERR_OK) {
504: $json['error'] = $this->language->get('error_upload_' . $this->request->files['file']['error']);
505: }
506: }
507:
508: if (!$json) {
509: $file = $filename . '.' . oc_token(32);
510:
511: move_uploaded_file($this->request->files['file']['tmp_name'], DIR_DOWNLOAD . $file);
512:
513: $json['filename'] = $file;
514: $json['mask'] = $filename;
515:
516: $json['success'] = $this->language->get('text_upload');
517: }
518:
519: $this->response->addHeader('Content-Type: application/json');
520: $this->response->setOutput(json_encode($json));
521: }
522:
523: /**
524: * Download
525: *
526: * @return void
527: */
528: public function download(): void {
529: $this->load->language('catalog/download');
530:
531: if (isset($this->request->get['filename'])) {
532: $filename = basename($this->request->get['filename']);
533: } else {
534: $filename = '';
535: }
536:
537: $file = DIR_DOWNLOAD . $filename;
538:
539: if (is_file($file)) {
540: if (!headers_sent()) {
541: header('Content-Type: application/octet-stream');
542: header('Content-Description: File Transfer');
543: header('Content-Disposition: attachment; filename="' . $filename . '"');
544: header('Content-Transfer-Encoding: binary');
545: header('Expires: 0');
546: header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
547: header('Pragma: public');
548: header('Content-Length: ' . filesize($file));
549:
550: readfile($file);
551: exit;
552: } else {
553: exit($this->language->get('error_headers_sent'));
554: }
555: } else {
556: $this->load->language('error/not_found');
557:
558: $this->document->setTitle($this->language->get('heading_title'));
559:
560: $data['breadcrumbs'] = [];
561:
562: $data['breadcrumbs'][] = [
563: 'text' => $this->language->get('text_home'),
564: 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
565: ];
566:
567: $data['breadcrumbs'][] = [
568: 'text' => $this->language->get('heading_title'),
569: 'href' => $this->url->link('error/not_found', 'user_token=' . $this->session->data['user_token'])
570: ];
571:
572: $data['header'] = $this->load->controller('common/header');
573: $data['column_left'] = $this->load->controller('common/column_left');
574: $data['footer'] = $this->load->controller('common/footer');
575:
576: $this->response->setOutput($this->load->view('error/not_found', $data));
577: }
578: }
579:
580: /**
581: * Autocomplete
582: *
583: * @return void
584: */
585: public function autocomplete(): void {
586: $json = [];
587:
588: if (isset($this->request->get['filter_name'])) {
589: $this->load->model('catalog/download');
590:
591: $filter_data = [
592: 'filter_name' => $this->request->get['filter_name'],
593: 'start' => 0,
594: 'limit' => 5
595: ];
596:
597: $results = $this->model_catalog_download->getDownloads($filter_data);
598:
599: foreach ($results as $result) {
600: $json[] = [
601: 'download_id' => $result['download_id'],
602: 'name' => strip_tags(html_entity_decode($result['name'], ENT_QUOTES, 'UTF-8'))
603: ];
604: }
605: }
606:
607: $sort_order = [];
608:
609: foreach ($json as $key => $value) {
610: $sort_order[$key] = $value['name'];
611: }
612:
613: array_multisort($sort_order, SORT_ASC, $json);
614:
615: $this->response->addHeader('Content-Type: application/json');
616: $this->response->setOutput(json_encode($json));
617: }
618: }
619: