Issues (2407)

administration/controller/tool/upload.php (11 issues)

1
<?php
2
3
/* 	Divine CMS - Open source CMS for widespread use.
4
    Copyright (c) 2019 Mykola Burakov ([email protected])
5
6
    See SOURCE.txt for other and additional information.
7
8
    This file is part of Divine CMS.
9
10
    This program is free software: you can redistribute it and/or modify
11
    it under the terms of the GNU General Public License as published by
12
    the Free Software Foundation, either version 3 of the License, or
13
    (at your option) any later version.
14
15
    This program is distributed in the hope that it will be useful,
16
    but WITHOUT ANY WARRANTY; without even the implied warranty of
17
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
    GNU General Public License for more details.
19
20
    You should have received a copy of the GNU General Public License
21
    along with this program. If not, see <http://www.gnu.org/licenses/>. */
22
23
class ControllerToolUpload extends \Divine\Engine\Core\Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
24
{
25
    private $error = array();
26
27
    public function index()
0 ignored issues
show
Expected 2 blank lines before function; 1 found
Loading history...
28
    {
29
        $this->load->language('tool/upload');
30
31
        $this->document->setTitle($this->language->get('heading_title'));
32
33
        $this->load->model('tool/upload');
34
35
        $this->getList();
0 ignored issues
show
The method getList() does not exist on ControllerToolUpload. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

35
        $this->/** @scrutinizer ignore-call */ 
36
               getList();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
36
    }
37
38
    public function delete()
39
    {
40
        $this->load->language('tool/upload');
41
42
        $this->document->setTitle($this->language->get('heading_title'));
43
44
        $this->load->model('tool/upload');
45
46
        if (isset($this->request->post['selected']) && $this->validateDelete()) {
0 ignored issues
show
The method validateDelete() does not exist on ControllerToolUpload. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
        if (isset($this->request->post['selected']) && $this->/** @scrutinizer ignore-call */ validateDelete()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
47
            foreach ($this->request->post['selected'] as $upload_id) {
48
                // Remove file before deleting DB record.
49
                $upload_info = $this->model_tool_upload->getUpload($upload_id);
50
51
                if ($upload_info && is_file($_SERVER['DOCUMENT_ROOT'] . '/storage/upload/' . $upload_info['filename'])) {
52
                    unlink($_SERVER['DOCUMENT_ROOT'] . '/storage/upload/' . $upload_info['filename']);
53
                }
54
55
                $this->model_tool_upload->deleteUpload($upload_id);
56
            }
57
58
            $this->session->data['success'] = $this->language->get('text_success');
59
60
            $url = '';
61
62
            if (isset($this->request->get['filter_name'])) {
63
                $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
64
            }
65
66
            if (isset($this->request->get['filter_date_added'])) {
67
                $url .= '&filter_date_added=' . $this->request->get['filter_date_added'];
68
            }
69
70
            if (isset($this->request->get['sort'])) {
71
                $url .= '&sort=' . $this->request->get['sort'];
72
            }
73
74
            if (isset($this->request->get['order'])) {
75
                $url .= '&order=' . $this->request->get['order'];
76
            }
77
78
            if (isset($this->request->get['page'])) {
79
                $url .= '&page=' . $this->request->get['page'];
80
            }
81
82
            $this->response->redirect($this->url->link('tool/upload', 'token=' . $this->session->data['token'] . $url, true));
83
        }
84
85
        $this->getList();
86
    }
87
88
    protected function getList()
89
    {
90
        if (isset($this->request->get['filter_name'])) {
91
            $filter_name = $this->request->get['filter_name'];
92
        } else {
93
            $filter_name = null;
94
        }
95
96
        if (isset($this->request->get['filter_date_added'])) {
97
            $filter_date_added = $this->request->get['filter_date_added'];
98
        } else {
99
            $filter_date_added = null;
100
        }
101
102
        if (isset($this->request->get['sort'])) {
103
            $sort = $this->request->get['sort'];
104
        } else {
105
            $sort = 'date_added';
106
        }
107
108
        if (isset($this->request->get['order'])) {
109
            $order = $this->request->get['order'];
110
        } else {
111
            $order = 'DESC';
112
        }
113
114
        if (isset($this->request->get['page'])) {
115
            $page = $this->request->get['page'];
116
        } else {
117
            $page = 1;
118
        }
119
120
        $url = '';
121
122
        if (isset($this->request->get['filter_name'])) {
123
            $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
124
        }
125
126
        if (isset($this->request->get['filter_date_added'])) {
127
            $url .= '&filter_date_added=' . $this->request->get['filter_date_added'];
128
        }
129
130
        if (isset($this->request->get['sort'])) {
131
            $url .= '&sort=' . $this->request->get['sort'];
132
        }
133
134
        if (isset($this->request->get['order'])) {
135
            $url .= '&order=' . $this->request->get['order'];
136
        }
137
138
        if (isset($this->request->get['page'])) {
139
            $url .= '&page=' . $this->request->get['page'];
140
        }
141
142
        $data['breadcrumbs'] = array();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
143
144
        $data['breadcrumbs'][] = array(
145
            'text' => $this->language->get('text_home'),
146
            'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], true)
147
        );
148
149
        $data['breadcrumbs'][] = array(
150
            'text' => $this->language->get('heading_title'),
151
            'href' => $this->url->link('tool/upload', 'token=' . $this->session->data['token'] . $url, true)
152
        );
153
154
        $data['delete'] = $this->url->link('tool/upload/delete', 'token=' . $this->session->data['token'] . $url, true);
155
156
        $data['uploads'] = array();
157
158
        $filter_data = array(
159
            'filter_name'        => $filter_name,
160
            'filter_date_added'    => $filter_date_added,
161
            'sort'              => $sort,
162
            'order'             => $order,
163
            'start'             => ($page - 1) * $this->config->get('config_limit_admin'),
164
            'limit'             => $this->config->get('config_limit_admin')
165
        );
166
167
        $upload_total = $this->model_tool_upload->getTotalUploads($filter_data);
168
169
        $results = $this->model_tool_upload->getUploads($filter_data);
170
171
        foreach ($results as $result) {
172
            $data['uploads'][] = array(
173
                'upload_id'  => $result['upload_id'],
174
                'name'       => $result['name'],
175
                'filename'   => $result['filename'],
176
                'date_added' => date($this->language->get('date_format_short'), strtotime($result['date_added'])),
177
                'download'   => $this->url->link('tool/upload/download', 'token=' . $this->session->data['token'] . '&code=' . $result['code'] . $url, true)
178
            );
179
        }
180
181
        $data['heading_title'] = $this->language->get('heading_title');
182
183
        $data['text_list'] = $this->language->get('text_list');
184
        $data['text_no_results'] = $this->language->get('text_no_results');
185
        $data['text_confirm'] = $this->language->get('text_confirm');
186
187
        $data['column_name'] = $this->language->get('column_name');
188
        $data['column_filename'] = $this->language->get('column_filename');
189
        $data['column_date_added'] = $this->language->get('column_date_added');
190
        $data['column_action'] = $this->language->get('column_action');
191
192
        $data['entry_name'] = $this->language->get('entry_name');
193
        $data['entry_date_added'] = $this->language->get('entry_date_added');
194
195
        $data['button_download'] = $this->language->get('button_download');
196
        $data['button_delete'] = $this->language->get('button_delete');
197
        $data['button_filter'] = $this->language->get('button_filter');
198
199
        $data['token'] = $this->session->data['token'];
200
201
        if (isset($this->error['warning'])) {
202
            $data['error_warning'] = $this->error['warning'];
203
        } else {
204
            $data['error_warning'] = '';
205
        }
206
207
        if (isset($this->session->data['success'])) {
208
            $data['success'] = $this->session->data['success'];
209
210
            unset($this->session->data['success']);
211
        } else {
212
            $data['success'] = '';
213
        }
214
215
        if (isset($this->request->post['selected'])) {
216
            $data['selected'] = (array)$this->request->post['selected'];
217
        } else {
218
            $data['selected'] = array();
219
        }
220
221
        $url = '';
222
223
        if (isset($this->request->get['filter_name'])) {
224
            $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
225
        }
226
227
        if (isset($this->request->get['filter_date_added'])) {
228
            $url .= '&filter_date_added=' . $this->request->get['filter_date_added'];
229
        }
230
231
        if ($order == 'ASC') {
232
            $url .= '&order=DESC';
233
        } else {
234
            $url .= '&order=ASC';
235
        }
236
237
        if (isset($this->request->get['page'])) {
238
            $url .= '&page=' . $this->request->get['page'];
239
        }
240
241
        $data['sort_name'] = $this->url->link('tool/upload', 'token=' . $this->session->data['token'] . '&sort=name' . $url, true);
242
        $data['sort_filename'] = $this->url->link('tool/upload', 'token=' . $this->session->data['token'] . '&sort=filename' . $url, true);
243
        $data['sort_date_added'] = $this->url->link('tool/upload', 'token=' . $this->session->data['token'] . '&sort=date_added' . $url, true);
244
245
        $url = '';
246
247
        if (isset($this->request->get['filter_name'])) {
248
            $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
249
        }
250
251
        if (isset($this->request->get['filter_date_added'])) {
252
            $url .= '&filter_date_added=' . $this->request->get['filter_date_added'];
253
        }
254
255
        if (isset($this->request->get['sort'])) {
256
            $url .= '&sort=' . $this->request->get['sort'];
257
        }
258
259
        if (isset($this->request->get['order'])) {
260
            $url .= '&order=' . $this->request->get['order'];
261
        }
262
263
        $pagination = new \Divine\Engine\Library\Pagination();
264
        $pagination->total = $upload_total;
265
        $pagination->page = $page;
266
        $pagination->limit = $this->config->get('config_limit_admin');
267
        $pagination->url = $this->url->link('tool/upload', 'token=' . $this->session->data['token'] . $url . '&page={page}', true);
268
269
        $data['pagination'] = $pagination->render();
270
271
        $data['results'] = sprintf($this->language->get('text_pagination'), ($upload_total) ? (($page - 1) * $this->config->get('config_limit_admin')) + 1 : 0, ((($page - 1) * $this->config->get('config_limit_admin')) > ($upload_total - $this->config->get('config_limit_admin'))) ? $upload_total : ((($page - 1) * $this->config->get('config_limit_admin')) + $this->config->get('config_limit_admin')), $upload_total, ceil($upload_total / $this->config->get('config_limit_admin')));
272
273
        $data['filter_name'] = $filter_name;
274
        $data['filter_date_added'] = $filter_date_added;
275
276
        $data['sort'] = $sort;
277
        $data['order'] = $order;
278
279
        $data['header'] = $this->load->controller('common/header');
280
        $data['column'] = $this->load->controller('common/column_left');
281
        $data['footer'] = $this->load->controller('common/footer');
282
283
        $this->response->setOutput($this->load->view('tool/upload', $data));
284
    }
285
286
    protected function validateDelete()
287
    {
288
        if (!$this->user->hasPermission('modify', 'tool/upload')) {
289
            $this->error['warning'] = $this->language->get('error_permission');
290
        }
291
292
        return !$this->error;
293
    }
294
295
    public function download()
296
    {
297
        $this->load->model('tool/upload');
298
299
        if (isset($this->request->get['code'])) {
300
            $code = $this->request->get['code'];
301
        } else {
302
            $code = 0;
303
        }
304
305
        $upload_info = $this->model_tool_upload->getUploadByCode($code);
306
307
        if ($upload_info) {
308
            $file = $_SERVER['DOCUMENT_ROOT'] . '/storage/upload/' . $upload_info['filename'];
309
            $mask = basename($upload_info['name']);
310
311
            if (!headers_sent()) {
312
                if (is_file($file)) {
313
                    header('Content-Type: application/octet-stream');
314
                    header('Content-Description: File Transfer');
315
                    header('Content-Disposition: attachment; filename="' . ($mask ? $mask : basename($file)) . '"');
316
                    header('Content-Transfer-Encoding: binary');
317
                    header('Expires: 0');
318
                    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
319
                    header('Pragma: public');
320
                    header('Content-Length: ' . filesize($file));
321
322
                    readfile($file, 'rb');
0 ignored issues
show
'rb' of type string is incompatible with the type boolean expected by parameter $use_include_path of readfile(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

322
                    readfile($file, /** @scrutinizer ignore-type */ 'rb');
Loading history...
323
                    exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
324
                } else {
325
                    exit('Error: Could not find file ' . $file . '!');
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
326
                }
327
            } else {
328
                exit('Error: Headers already sent out!');
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
329
            }
330
        } else {
331
            $this->load->language('error/not_found');
332
333
            $this->document->setTitle($this->language->get('heading_title'));
334
335
            $data['heading_title'] = $this->language->get('heading_title');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
336
337
            $data['text_not_found'] = $this->language->get('text_not_found');
338
339
            $data['breadcrumbs'] = array();
340
341
            $data['breadcrumbs'][] = array(
342
                'text' => $this->language->get('text_home'),
343
                'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], true)
344
            );
345
346
            $data['breadcrumbs'][] = array(
347
                'text' => $this->language->get('heading_title'),
348
                'href' => $this->url->link('error/not_found', 'token=' . $this->session->data['token'], true)
349
            );
350
351
            $data['header'] = $this->load->controller('common/header');
352
            $data['column'] = $this->load->controller('common/column_left');
353
            $data['footer'] = $this->load->controller('common/footer');
354
355
            $this->response->setOutput($this->load->view('error/not_found', $data));
356
        }
357
    }
358
359
    public function upload()
360
    {
361
        $this->load->language('sale/order');
362
363
        $json = array();
364
365
        // Check user has permission
366
        if (!$this->user->hasPermission('modify', 'tool/upload')) {
367
            $json['error'] = $this->language->get('error_permission');
368
        }
369
370
        if (!$json) {
371
            if (!empty($this->request->files['file']['name']) && is_file($this->request->files['file']['tmp_name'])) {
372
                // Sanitize the filename
373
                $filename = html_entity_decode($this->request->files['file']['name'], ENT_QUOTES, 'UTF-8');
374
375
                if ((\voku\helper\UTF8::strlen($filename) < 3) || (\voku\helper\UTF8::strlen($filename) > 128)) {
376
                    $json['error'] = $this->language->get('error_filename');
377
                }
378
379
                // Allowed file extension types
380
                $allowed = array();
381
382
                $extension_allowed = preg_replace('~\r?\n~', "\n", $this->config->get('config_file_ext_allowed'));
383
384
                $filetypes = explode("\n", $extension_allowed);
385
386
                foreach ($filetypes as $filetype) {
387
                    $allowed[] = trim($filetype);
388
                }
389
390
                if (!in_array(strtolower(substr(strrchr($filename, '.'), 1)), $allowed)) {
391
                    $json['error'] = $this->language->get('error_filetype');
392
                }
393
394
                // Allowed file mime types
395
                $allowed = array();
396
397
                $mime_allowed = preg_replace('~\r?\n~', "\n", $this->config->get('config_file_mime_allowed'));
398
399
                $filetypes = explode("\n", $mime_allowed);
400
401
                foreach ($filetypes as $filetype) {
402
                    $allowed[] = trim($filetype);
403
                }
404
405
                if (!in_array($this->request->files['file']['type'], $allowed)) {
406
                    $json['error'] = $this->language->get('error_filetype');
407
                }
408
409
                // Check to see if any PHP files are trying to be uploaded
410
                $content = file_get_contents($this->request->files['file']['tmp_name']);
411
412
                if (preg_match('/\<\?php/i', $content)) {
413
                    $json['error'] = $this->language->get('error_filetype');
414
                }
415
416
                // Return any upload error
417
                if ($this->request->files['file']['error'] != UPLOAD_ERR_OK) {
418
                    $json['error'] = $this->language->get('error_upload_' . $this->request->files['file']['error']);
419
                }
420
            } else {
421
                $json['error'] = $this->language->get('error_upload');
422
            }
423
        }
424
425
        if (!$json) {
426
            $file = $filename . '.' . (new \Tokenly\TokenGenerator\TokenGenerator())->generateToken(32, 'SR');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $filename does not seem to be defined for all execution paths leading up to this point.
Loading history...
427
428
            move_uploaded_file($this->request->files['file']['tmp_name'], $_SERVER['DOCUMENT_ROOT'] . '/storage/upload/' . $file);
429
430
            // Hide the uploaded file name so people can not link to it directly.
431
            $this->load->model('tool/upload');
432
433
            $json['code'] = $this->model_tool_upload->addUpload($filename, $file);
434
435
            $json['success'] = $this->language->get('text_upload');
436
        }
437
438
        $this->response->addHeader('Content-Type: application/json');
439
        $this->response->setOutput(json_encode($json));
440
    }
441
}
442