Issues (2407)

administration/controller/common/filemanager.php (12 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 ControllerCommonFileManager 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
    public function index()
0 ignored issues
show
Expected 2 blank lines before function; 0 found
Loading history...
26
    {
27
        $this->load->language('common/filemanager');
28
29
        if (isset($this->request->get['filter_name'])) {
30
            $filter_name = rtrim(str_replace('*', '', $this->request->get['filter_name']), '/');
31
        } else {
32
            $filter_name = null;
33
        }
34
35
        // Make sure we have the correct directory
36
        if (isset($this->request->get['directory'])) {
37
            $directory = rtrim($_SERVER['DOCUMENT_ROOT'] . '/images/application/' . str_replace('*', '', $this->request->get['directory']), '/');
38
        } else {
39
            $directory = $_SERVER['DOCUMENT_ROOT'] . '/images/application';
40
        }
41
42
        if (isset($this->request->get['page'])) {
43
            $page = $this->request->get['page'];
44
        } else {
45
            $page = 1;
46
        }
47
48
        $directories = array();
0 ignored issues
show
The assignment to $directories is dead and can be removed.
Loading history...
49
        $files = array();
0 ignored issues
show
The assignment to $files is dead and can be removed.
Loading history...
50
51
        $data['images'] = 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...
52
53
        
54
55
        //if (substr(str_replace('\\', '/', realpath($directory . '/' . $filter_name)), 0, strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/' . 'catalog')) == $_SERVER['DOCUMENT_ROOT'] . '/images/application') {
56
        // Get directories
57
        $directories = glob($directory . '/' . $filter_name . '*', GLOB_ONLYDIR);
58
59
        if (!$directories) {
60
            $directories = array();
61
        }
62
63
        // Get files
64
        $files = glob($directory . '/' . $filter_name . '*.{jpg,jpeg,png,gif,JPG,JPEG,PNG,GIF}', GLOB_BRACE);
65
66
        if (!$files) {
67
            $files = array();
68
        }
69
        //}
70
71
        // Merge directories and files
72
        $images = array_merge($directories, $files);
73
74
        // Get total number of files and directories
75
        $image_total = count($images);
76
77
        // Split the array based on current page number and max number of items per page of 10
78
        $images = array_splice($images, ($page - 1) * 16, 16);
79
80
        foreach ($images as $image) {
81
            $name = str_split(basename($image), 14);
82
83
            if (is_dir($image)) {
84
                $url = '';
85
86
                if (isset($this->request->get['target'])) {
87
                    $url .= '&target=' . $this->request->get['target'];
88
                }
89
90
                if (isset($this->request->get['thumb'])) {
91
                    $url .= '&thumb=' . $this->request->get['thumb'];
92
                }
93
94
                $data['images'][] = array(
95
                    'thumb' => '',
96
                    'name'  => implode(' ', $name),
97
                    'type'  => 'directory',
98
                    'path'  => \voku\helper\UTF8::substr($image, \voku\helper\UTF8::strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/')),
0 ignored issues
show
It seems like voku\helper\UTF8::strlen...c_html/assets/images/') can also be of type false; however, parameter $offset of voku\helper\UTF8::substr() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

98
                    'path'  => \voku\helper\UTF8::substr($image, /** @scrutinizer ignore-type */ \voku\helper\UTF8::strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/')),
Loading history...
99
                    'href'  => $this->url->link('common/filemanager', 'token=' . $this->session->data['token'] . '&directory=' . urlencode(\voku\helper\UTF8::substr($image, \voku\helper\UTF8::strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/' . 'application/'))) . $url, true)
0 ignored issues
show
It seems like voku\helper\UTF8::substr...es/' . 'application/')) can also be of type false; however, parameter $str of urlencode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

99
                    'href'  => $this->url->link('common/filemanager', 'token=' . $this->session->data['token'] . '&directory=' . urlencode(/** @scrutinizer ignore-type */ \voku\helper\UTF8::substr($image, \voku\helper\UTF8::strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/' . 'application/'))) . $url, true)
Loading history...
100
                );
101
            } elseif (is_file($image)) {
102
                $data['images'][] = array(
103
                    'thumb' => '/public_html/assets/images/' . \voku\helper\UTF8::substr($image, \voku\helper\UTF8::strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/')),
0 ignored issues
show
Are you sure voku\helper\UTF8::substr..._html/assets/images/')) of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

103
                    'thumb' => '/public_html/assets/images/' . /** @scrutinizer ignore-type */ \voku\helper\UTF8::substr($image, \voku\helper\UTF8::strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/')),
Loading history...
104
                    'name'  => implode(' ', $name),
105
                    'type'  => 'image',
106
                    'path'  => \voku\helper\UTF8::substr($image, \voku\helper\UTF8::strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/')),
107
                    'href'  => '/public_html/assets/images/' . \voku\helper\UTF8::substr($image, \voku\helper\UTF8::strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/'))
108
                );
109
            }
110
        }
111
112
        $data['heading_title'] = $this->language->get('heading_title');
113
114
        $data['text_no_results'] = $this->language->get('text_no_results');
115
        $data['text_confirm'] = $this->language->get('text_confirm');
116
117
        $data['entry_search'] = $this->language->get('entry_search');
118
        $data['entry_folder'] = $this->language->get('entry_folder');
119
120
        $data['button_parent'] = $this->language->get('button_parent');
121
        $data['button_refresh'] = $this->language->get('button_refresh');
122
        $data['button_upload'] = $this->language->get('button_upload');
123
        $data['button_folder'] = $this->language->get('button_folder');
124
        $data['button_delete'] = $this->language->get('button_delete');
125
        $data['button_search'] = $this->language->get('button_search');
126
127
        $data['token'] = $this->session->data['token'];
128
129
        if (isset($this->request->get['directory'])) {
130
            $data['directory'] = urlencode($this->request->get['directory']);
131
        } else {
132
            $data['directory'] = '';
133
        }
134
135
        if (isset($this->request->get['filter_name'])) {
136
            $data['filter_name'] = $this->request->get['filter_name'];
137
        } else {
138
            $data['filter_name'] = '';
139
        }
140
141
        // Return the target ID for the file manager to set the value
142
        if (isset($this->request->get['target'])) {
143
            $data['target'] = $this->request->get['target'];
144
        } else {
145
            $data['target'] = '';
146
        }
147
148
        // Return the thumbnail for the file manager to show a thumbnail
149
        if (isset($this->request->get['thumb'])) {
150
            $data['thumb'] = $this->request->get['thumb'];
151
        } else {
152
            $data['thumb'] = '';
153
        }
154
155
        // Parent
156
        $url = '';
157
158
        if (isset($this->request->get['directory'])) {
159
            $pos = strrpos($this->request->get['directory'], '/');
160
161
            if ($pos) {
162
                $url .= '&directory=' . urlencode(substr($this->request->get['directory'], 0, $pos));
163
            }
164
        }
165
166
        if (isset($this->request->get['target'])) {
167
            $url .= '&target=' . $this->request->get['target'];
168
        }
169
170
        if (isset($this->request->get['thumb'])) {
171
            $url .= '&thumb=' . $this->request->get['thumb'];
172
        }
173
174
        $data['parent'] = $this->url->link('common/filemanager', 'token=' . $this->session->data['token'] . $url, true);
175
176
        // Refresh
177
        $url = '';
178
179
        if (isset($this->request->get['directory'])) {
180
            $url .= '&directory=' . urlencode($this->request->get['directory']);
181
        }
182
183
        if (isset($this->request->get['target'])) {
184
            $url .= '&target=' . $this->request->get['target'];
185
        }
186
187
        if (isset($this->request->get['thumb'])) {
188
            $url .= '&thumb=' . $this->request->get['thumb'];
189
        }
190
191
        $data['refresh'] = $this->url->link('common/filemanager', 'token=' . $this->session->data['token'] . $url, true);
192
193
        $url = '';
194
195
        if (isset($this->request->get['directory'])) {
196
            $url .= '&directory=' . urlencode(html_entity_decode($this->request->get['directory'], ENT_QUOTES, 'UTF-8'));
197
        }
198
199
        if (isset($this->request->get['filter_name'])) {
200
            $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
201
        }
202
203
        if (isset($this->request->get['target'])) {
204
            $url .= '&target=' . $this->request->get['target'];
205
        }
206
207
        if (isset($this->request->get['thumb'])) {
208
            $url .= '&thumb=' . $this->request->get['thumb'];
209
        }
210
211
        $pagination = new \Divine\Engine\Library\Pagination();
212
        $pagination->total = $image_total;
213
        $pagination->page = $page;
214
        $pagination->limit = 16;
215
        $pagination->url = $this->url->link('common/filemanager', 'token=' . $this->session->data['token'] . $url . '&page={page}', true);
216
217
        $data['pagination'] = $pagination->render();
218
219
        $this->response->setOutput($this->load->view('common/filemanager', $data));
220
    }
221
222
    public function upload()
223
    {
224
        $this->load->language('common/filemanager');
225
226
        $json = array();
227
228
        // Check user has permission
229
        if (!$this->user->hasPermission('modify', 'common/filemanager')) {
230
            $json['error'] = $this->language->get('error_permission');
231
        }
232
233
        // Make sure we have the correct directory
234
        if (isset($this->request->get['directory'])) {
235
            $directory = rtrim($_SERVER['DOCUMENT_ROOT'] . '/images/application/' . $this->request->get['directory'], '/');
236
        } else {
237
            $directory = $_SERVER['DOCUMENT_ROOT'] . '/images/application';
238
        }
239
240
        // Check its a directory
241
        if (!is_dir($directory) || substr(str_replace('\\', '/', realpath($directory)), 0, strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/' . 'catalog')) != $_SERVER['DOCUMENT_ROOT'] . '/images/application') {
242
            $json['error'] = $this->language->get('error_directory');
243
        }
244
245
        if (!$json) {
246
            // Check if multiple files are uploaded or just one
247
            $files = array();
248
249
            if (!empty($this->request->files['file']['name']) && is_array($this->request->files['file']['name'])) {
250
                foreach (array_keys($this->request->files['file']['name']) as $key) {
251
                    $files[] = array(
252
                        'name'     => $this->request->files['file']['name'][$key],
253
                        'type'     => $this->request->files['file']['type'][$key],
254
                        'tmp_name' => $this->request->files['file']['tmp_name'][$key],
255
                        'error'    => $this->request->files['file']['error'][$key],
256
                        'size'     => $this->request->files['file']['size'][$key]
257
                    );
258
                }
259
            }
260
261
            foreach ($files as $file) {
262
                if (is_file($file['tmp_name'])) {
263
                    // Sanitize the filename
264
                    $filename = basename(html_entity_decode($file['name'], ENT_QUOTES, 'UTF-8'));
265
266
                    // Validate the filename length
267
                    if ((\voku\helper\UTF8::strlen($filename) < 3) || (\voku\helper\UTF8::strlen($filename) > 255)) {
268
                        $json['error'] = $this->language->get('error_filename');
269
                    }
270
271
                    // Allowed file extension types
272
                    $allowed = array(
273
                        'jpg',
274
                        'jpeg',
275
                        'gif',
276
                        'png'
277
                    );
278
279
                    if (!in_array(\voku\helper\UTF8::strtolower(\voku\helper\UTF8::substr(strrchr($filename, '.'), 1)), $allowed)) {
0 ignored issues
show
It seems like voku\helper\UTF8::substr...chr($filename, '.'), 1) can also be of type false; however, parameter $str of voku\helper\UTF8::strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

279
                    if (!in_array(\voku\helper\UTF8::strtolower(/** @scrutinizer ignore-type */ \voku\helper\UTF8::substr(strrchr($filename, '.'), 1)), $allowed)) {
Loading history...
280
                        $json['error'] = $this->language->get('error_filetype');
281
                    }
282
283
                    // Allowed file mime types
284
                    $allowed = array(
285
                        'image/jpeg',
286
                        'image/pjpeg',
287
                        'image/png',
288
                        'image/x-png',
289
                        'image/gif'
290
                    );
291
292
                    if (!in_array($file['type'], $allowed)) {
293
                        $json['error'] = $this->language->get('error_filetype');
294
                    }
295
296
                    // Return any upload error
297
                    if ($file['error'] != UPLOAD_ERR_OK) {
298
                        $json['error'] = $this->language->get('error_upload_' . $file['error']);
299
                    }
300
                } else {
301
                    $json['error'] = $this->language->get('error_upload');
302
                }
303
304
                if (!$json) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $json of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
305
                    move_uploaded_file($file['tmp_name'], $directory . '/' . $filename);
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...
306
                }
307
            }
308
        }
309
310
        if (!$json) {
311
            $json['success'] = $this->language->get('text_uploaded');
312
        }
313
314
        $this->response->addHeader('Content-Type: application/json');
315
        $this->response->setOutput(json_encode($json));
316
    }
317
318
    public function folder()
319
    {
320
        $this->load->language('common/filemanager');
321
322
        $json = array();
323
324
        // Check user has permission
325
        if (!$this->user->hasPermission('modify', 'common/filemanager')) {
326
            $json['error'] = $this->language->get('error_permission');
327
        }
328
329
        // Make sure we have the correct directory
330
        if (isset($this->request->get['directory'])) {
331
            $directory = rtrim($_SERVER['DOCUMENT_ROOT'] . '/images/application/' . $this->request->get['directory'], '/');
332
        } else {
333
            $directory = $_SERVER['DOCUMENT_ROOT'] . '/images/application';
334
        }
335
336
        // Check its a directory
337
        if (!is_dir($directory) || substr(str_replace('\\', '/', realpath($directory)), 0, strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/' . 'catalog')) != $_SERVER['DOCUMENT_ROOT'] . '/images/application') {
338
            $json['error'] = $this->language->get('error_directory');
339
        }
340
341
        if ($this->request->server['REQUEST_METHOD'] == 'POST') {
342
            // Sanitize the folder name
343
            $folder = basename(html_entity_decode($this->request->post['folder'], ENT_QUOTES, 'UTF-8'));
344
345
            // Validate the filename length
346
            if ((\voku\helper\UTF8::strlen($folder) < 3) || (\voku\helper\UTF8::strlen($folder) > 128)) {
347
                $json['error'] = $this->language->get('error_folder');
348
            }
349
350
            // Check if directory already exists or not
351
            if (is_dir($directory . '/' . $folder)) {
352
                $json['error'] = $this->language->get('error_exists');
353
            }
354
        }
355
356
        if (!isset($json['error'])) {
357
            mkdir($directory . '/' . $folder, 0777);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $folder does not seem to be defined for all execution paths leading up to this point.
Loading history...
358
            chmod($directory . '/' . $folder, 0777);
359
360
            // @touch($directory . '/' . $folder . '/' . 'index.html');
361
362
            $json['success'] = $this->language->get('text_directory');
363
        }
364
365
        $this->response->addHeader('Content-Type: application/json');
366
        $this->response->setOutput(json_encode($json));
367
    }
368
369
    public function delete()
370
    {
371
        $this->load->language('common/filemanager');
372
373
        $json = array();
374
375
        // Check user has permission
376
        if (!$this->user->hasPermission('modify', 'common/filemanager')) {
377
            $json['error'] = $this->language->get('error_permission');
378
        }
379
380
        if (isset($this->request->post['path'])) {
381
            $paths = $this->request->post['path'];
382
        } else {
383
            $paths = array();
384
        }
385
386
        // Loop through each path to run validations
387
        foreach ($paths as $path) {
388
            // Check path exsists
389
            if ($path == $_SERVER['DOCUMENT_ROOT'] . '/images/application' || substr(str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/' . $path)), 0, strlen($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/' . 'catalog')) != $_SERVER['DOCUMENT_ROOT'] . '/images/application') {
390
                $json['error'] = $this->language->get('error_delete');
391
392
                break;
393
            }
394
        }
395
396
        if (!$json) {
397
            // Loop through each path
398
            foreach ($paths as $path) {
399
                $path = rtrim($_SERVER['DOCUMENT_ROOT'] . '/public_html/assets/images/' . $path, '/');
400
401
                // If path is just a file delete it
402
                if (is_file($path)) {
403
                    unlink($path);
404
405
                // If path is a directory beging deleting each file and sub folder
406
                } elseif (is_dir($path)) {
407
                    $files = array();
408
409
                    // Make path into an array
410
                    $path = array($path . '*');
411
412
                    // While the path array is still populated keep looping through
413
                    while (count($path) != 0) {
414
                        $next = array_shift($path);
415
416
                        foreach (glob($next) as $file) {
417
                            // If directory add to path array
418
                            if (is_dir($file)) {
419
                                $path[] = $file . '/*';
420
                            }
421
422
                            // Add the file to the files to be deleted array
423
                            $files[] = $file;
424
                        }
425
                    }
426
427
                    // Reverse sort the file array
428
                    rsort($files);
429
430
                    foreach ($files as $file) {
431
                        // If file just delete
432
                        if (is_file($file)) {
433
                            unlink($file);
434
435
                        // If directory use the remove directory function
436
                        } elseif (is_dir($file)) {
437
                            rmdir($file);
438
                        }
439
                    }
440
                }
441
            }
442
443
            $json['success'] = $this->language->get('text_delete');
444
        }
445
446
        $this->response->addHeader('Content-Type: application/json');
447
        $this->response->setOutput(json_encode($json));
448
    }
449
}
450