browser::getDirInfo()   B
last analyzed

Complexity

Conditions 11
Paths 13

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 11
eloc 20
c 1
b 1
f 0
nc 13
nop 2
dl 0
loc 31
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/** This file is part of KCFinder project
4
 *
5
 * @desc      Browser actions class
6
 * @package   KCFinder
7
 * @version   3.12
8
 * @author    Pavel Tzonkov <[email protected]>
9
 * @copyright 2010-2014 KCFinder Project
10
 * @license   http://opensource.org/licenses/GPL-3.0 GPLv3
11
 * @license   http://opensource.org/licenses/LGPL-3.0 LGPLv3
12
 * @link      http://kcfinder.sunhater.com
13
 */
14
15
namespace kcfinder;
16
17
class browser extends uploader
18
{
19
    protected $action;
20
    protected $thumbsDir;
21
    protected $thumbsTypeDir;
22
23
    public function __construct()
24
    {
25
        parent::__construct();
26
27
        // SECURITY CHECK INPUT DIRECTORY
28
        if (isset($_POST['dir'])) {
29
            $dir = $this->checkInputDir($_POST['dir'], true, false);
30
            if (false === $dir) {
31
                unset($_POST['dir']);
32
            }
33
            $_POST['dir'] = $dir;
34
        }
35
36
        if (isset($_GET['dir'])) {
37
            $dir = $this->checkInputDir($_GET['dir'], true, false);
38
            if (false === $dir) {
39
                unset($_GET['dir']);
40
            }
41
            $_GET['dir'] = $dir;
42
        }
43
44
        $thumbsDir = $this->config['uploadDir'] . '/' . $this->config['thumbsDir'];
45
        if (!$this->config['disabled']
46
            && ((!is_dir($thumbsDir)
47
                 && !@mkdir($thumbsDir, $this->config['dirPerms']))
48
                || !is_readable($thumbsDir)
49
                || !dir::isWritable($thumbsDir)
50
                || (!is_dir("$thumbsDir/{$this->type}")
51
                    && !@mkdir("$thumbsDir/{$this->type}", $this->config['dirPerms'])))) {
52
            $this->errorMsg('Cannot access or create thumbnails folder.');
53
        }
54
55
        $this->thumbsDir     = $thumbsDir;
56
        $this->thumbsTypeDir = "$thumbsDir/{$this->type}";
57
58
        // Remove temporary zip downloads if exists
59
        if (!$this->config['disabled']) {
60
            $files = dir::content(
61
                $this->config['uploadDir'],
62
                [
63
                    'types'   => 'file',
64
                    'pattern' => '/^.*\.zip$/i'
65
                ]
66
            );
67
68
            if (is_array($files) && count($files)) {
0 ignored issues
show
introduced by
The condition is_array($files) is always false.
Loading history...
69
                $time = time();
70
                foreach ($files as $file) {
71
                    if (is_file($file) && ($time - filemtime($file) > 3600)) {
72
                        unlink($file);
73
                    }
74
                }
75
            }
76
        }
77
78
        if (isset($_GET['theme'])
79
            && $this->checkFilename($_GET['theme'])
80
            && is_dir("themes/{$_GET['theme']}")) {
81
            $this->config['theme'] = $_GET['theme'];
82
        }
83
    }
84
85
    public function action()
86
    {
87
        $act = isset($_GET['act']) ? $_GET['act'] : 'browser';
88
        if (!method_exists($this, "act_$act")) {
89
            $act = 'browser';
90
        }
91
        $this->action = $act;
92
        $method       = "act_$act";
93
94
        if ($this->config['disabled']) {
95
            $message = $this->label("You don't have permissions to browse server.");
96
            if (in_array($act, ['browser', 'upload'])
97
                || ('download' == substr($act, 0, 8))) {
98
                $this->backMsg($message);
99
            } else {
100
                header("Content-Type: text/plain; charset={$this->charset}");
101
                die(json_encode(['error' => $message]));
102
            }
103
        }
104
105
        if (!isset($this->session['dir'])) {
106
            $this->session['dir'] = $this->type;
107
        } else {
108
            $type = $this->getTypeFromPath($this->session['dir']);
109
            $dir  = $this->config['uploadDir'] . '/' . $this->session['dir'];
110
            if (($type != $this->type) || !is_dir($dir) || !is_readable($dir)) {
111
                $this->session['dir'] = $this->type;
112
            }
113
        }
114
        $this->session['dir'] = path::normalize($this->session['dir']);
115
116
        // Render the browser
117
        if ('browser' == $act) {
118
            header('X-UA-Compatible: chrome=1');
119
            header("Content-Type: text/html; charset={$this->charset}");
120
            // Ajax requests
121
        } elseif (('download' != substr($act, 0, 8))
122
                  && !in_array($act, ['thumb', 'upload'])) {
123
            header("Content-Type: text/plain; charset={$this->charset}");
124
        }
125
126
        $return = $this->$method();
127
        echo (true === $return) ? '{}' : $return;
128
    }
129
130
    protected function act_browser()
131
    {
132
        if (isset($_GET['dir'])) {
133
            $dir = "{$this->typeDir}/{$_GET['dir']}";
134
            if ($this->checkFilePath($dir) && is_dir($dir) && is_readable($dir)) {
135
                $this->session['dir'] = path::normalize("{$this->type}/{$_GET['dir']}");
136
            }
137
        }
138
        return $this->output();
139
    }
140
141
    protected function act_init()
142
    {
143
        $tree         = $this->getDirInfo($this->typeDir);
144
        $tree['dirs'] = $this->getTree($this->session['dir']);
145
        if (!is_array($tree['dirs']) || !count($tree['dirs'])) {
146
            unset($tree['dirs']);
147
        }
148
        $files       = $this->getFiles($this->session['dir']);
149
        $dirWritable = dir::isWritable("{$this->config['uploadDir']}/{$this->session['dir']}");
150
        $data        = [
151
            'tree'        => &$tree,
152
            'files'       => &$files,
153
            'dirWritable' => $dirWritable
154
        ];
155
        return json_encode($data);
156
    }
157
158
    protected function act_thumb()
159
    {
160
        if (!isset($_GET['file'])
161
            || !isset($_GET['dir'])
162
            || !$this->checkFilename($_GET['file'])) {
163
            $this->sendDefaultThumb();
164
        }
165
166
        $dir  = $this->getDir();
167
        $file = "{$this->thumbsTypeDir}/{$_GET['dir']}/${_GET['file']}";
168
169
        // Create thumbnail
170
        if (!is_file($file) || !is_readable($file)) {
171
            $file = "$dir/{$_GET['file']}";
172
            if (!is_file($file) || !is_readable($file)) {
173
                $this->sendDefaultThumb($file);
174
            }
175
            $image = image::factory($this->imageDriver, $file);
176
            if ($image->initError) {
177
                $this->sendDefaultThumb($file);
178
            }
179
180
            $img  = new fastImage($file);
181
            $type = $img->getType();
182
            $img->close();
183
184
            if (in_array($type, ['gif', 'jpeg', 'png'])
185
                && ($image->width <= $this->config['thumbWidth'])
186
                && ($image->height <= $this->config['thumbHeight'])) {
187
                $mime = "image/$type";
188
                httpCache::file($file, $mime);
189
            } else {
190
                $this->sendDefaultThumb($file);
191
            }
192
            // Get type from already-existing thumbnail
193
        } else {
194
            $img  = new fastImage($file);
195
            $type = $img->getType();
196
            $img->close();
197
        }
198
        httpCache::file($file, "image/$type");
199
    }
200
201
    protected function act_expand()
202
    {
203
        return json_encode(['dirs' => $this->getDirs($this->postDir())]);
204
    }
205
206
    protected function act_chDir()
207
    {
208
        $this->postDir(); // Just for existing check
209
        $this->session['dir'] = "{$this->type}/{$_POST['dir']}";
210
        $dirWritable          = dir::isWritable("{$this->config['uploadDir']}/{$this->session['dir']}");
211
        return json_encode(
212
            [
213
                'files'       => $this->getFiles($this->session['dir']),
214
                'dirWritable' => $dirWritable
215
            ]
216
        );
217
    }
218
219
    protected function act_newDir()
220
    {
221
        if (!$this->config['access']['dirs']['create']
222
            || !isset($_POST['dir'])
223
            || !isset($_POST['newDir'])
224
            || !$this->checkFilename($_POST['newDir'])) {
225
            $this->errorMsg('Unknown error.');
226
        }
227
228
        $dir    = $this->postDir();
229
        $newDir = $this->normalizeDirname(trim($_POST['newDir']));
230
        if (!strlen($newDir)) {
231
            $this->errorMsg('Please enter new folder name.');
232
        }
233
        if (preg_match('/[\/\\\\]/s', $newDir)) {
234
            $this->errorMsg('Unallowable characters in folder name.');
235
        }
236
        if ('.' == substr($newDir, 0, 1)) {
237
            $this->errorMsg("Folder name shouldn't begins with '.'");
238
        }
239
        if (file_exists("$dir/$newDir")) {
240
            $this->errorMsg('A file or folder with that name already exists.');
241
        }
242
        if (!@mkdir("$dir/$newDir", $this->config['dirPerms'])) {
243
            $this->errorMsg('Cannot create {dir} folder.', ['dir' => $this->htmlData($newDir)]);
244
        }
245
        return true;
246
    }
247
248
    protected function act_renameDir()
249
    {
250
        if (!$this->config['access']['dirs']['rename']
251
            || !isset($_POST['dir'])
252
            || !strlen(rtrim(rtrim(trim($_POST['dir']), '/'), "\\"))
253
            || !isset($_POST['newName'])
254
            || !$this->checkFilename($_POST['newName'])) {
255
            $this->errorMsg('Unknown error.');
256
        }
257
258
        $dir     = $this->postDir();
259
        $newName = $this->normalizeDirname(trim($_POST['newName']));
260
        if (!strlen($newName)) {
261
            $this->errorMsg('Please enter new folder name.');
262
        }
263
        if (preg_match('/[\/\\\\]/s', $newName)) {
264
            $this->errorMsg('Unallowable characters in folder name.');
265
        }
266
        if ('.' == substr($newName, 0, 1)) {
267
            $this->errorMsg("Folder name shouldn't begins with '.'");
268
        }
269
        if (!@rename($dir, dirname($dir) . "/$newName")) {
270
            $this->errorMsg('Cannot rename the folder.');
271
        }
272
        $thumbDir = "$this->thumbsTypeDir/{$_POST['dir']}";
273
        if (is_dir($thumbDir)) {
274
            @rename($thumbDir, dirname($thumbDir) . "/$newName");
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

274
            /** @scrutinizer ignore-unhandled */ @rename($thumbDir, dirname($thumbDir) . "/$newName");

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
275
        }
276
        return json_encode(['name' => $newName]);
277
    }
278
279
    protected function act_deleteDir()
280
    {
281
        if (!$this->config['access']['dirs']['delete']
282
            || !isset($_POST['dir'])
283
            || !strlen(rtrim(rtrim(trim($_POST['dir']), '/'), "\\"))) {
284
            $this->errorMsg('Unknown error.');
285
        }
286
287
        $dir = $this->postDir();
288
289
        if (!dir::isWritable($dir)) {
290
            $this->errorMsg('Cannot delete the folder.');
291
        }
292
        $result = !dir::prune($dir, false);
293
        if (is_array($result) && count($result)) {
0 ignored issues
show
introduced by
The condition is_array($result) is always false.
Loading history...
294
            $this->errorMsg(
295
                'Failed to delete {count} files/folders.',
296
                ['count' => count($result)]
297
            );
298
        }
299
        $thumbDir = "$this->thumbsTypeDir/{$_POST['dir']}";
300
        if (is_dir($thumbDir)) {
301
            dir::prune($thumbDir);
302
        }
303
        return true;
304
    }
305
306
    protected function act_upload()
307
    {
308
        header("Content-Type: text/plain; charset={$this->charset}");
309
310
        if (!$this->config['access']['files']['upload']
311
            || (!isset($_POST['dir']) && !isset($_GET['dir']))) {
312
            $this->errorMsg('Unknown error.');
313
        }
314
315
        $dir = isset($_GET['dir']) ? $this->getDir() : $this->postDir();
316
317
        if (!dir::isWritable($dir)) {
318
            $this->errorMsg('Cannot access or write to upload folder.');
319
        }
320
321
        if (is_array($this->file['name'])) {
322
            $return = [];
323
            foreach ($this->file['name'] as $i => $name) {
324
                $return[] = $this->moveUploadFile(
325
                    [
326
                        'name'     => $name,
327
                        'tmp_name' => $this->file['tmp_name'][$i],
328
                        'error'    => $this->file['error'][$i]
329
                    ],
330
                    $dir
331
                );
332
            }
333
            return implode("\n", $return);
334
        } else {
335
            return $this->moveUploadFile($this->file, $dir);
336
        }
337
    }
338
339
    protected function act_dragUrl()
340
    {
341
        if (!$this->config['access']['files']['upload']
342
            || !isset($_GET['dir'])
343
            || !isset($_POST['url'])
344
            || !isset($_POST['type'])) {
345
            $this->errorMsg('Unknown error.');
346
        }
347
348
        $dir = $this->getDir();
349
350
        if (!dir::isWritable($dir)) {
351
            $this->errorMsg('Cannot access or write to upload folder.');
352
        }
353
354
        if (is_array($_POST['url'])) {
355
            foreach ($_POST['url'] as $url) {
356
                $this->downloadURL($url, $dir);
357
            }
358
        } else {
359
            $this->downloadURL($_POST['url'], $dir);
360
        }
361
362
        return true;
363
    }
364
365
    protected function act_download()
366
    {
367
        $dir = $this->postDir();
368
        if (!isset($_POST['dir'])
369
            || !isset($_POST['file'])
370
            || !$this->checkFilename($_POST['file'])
371
            || (false === ($file = "$dir/{$_POST['file']}"))
372
            || !file_exists($file)
373
            || !is_readable($file)) {
374
            $this->errorMsg('Unknown error.');
375
        }
376
377
        header('Pragma: public');
378
        header('Expires: 0');
379
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
380
        header('Cache-Control: private', false);
381
        header('Content-Type: application/octet-stream');
382
        header('Content-Disposition: attachment; filename="' . str_replace('"', '_', $_POST['file']) . '"');
383
        header('Content-Transfer-Encoding: binary');
384
        header('Content-Length: ' . filesize($file));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $file does not seem to be defined for all execution paths leading up to this point.
Loading history...
385
        readfile($file);
386
        die;
0 ignored issues
show
Best Practice introduced by
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...
387
    }
388
389
    protected function act_rename()
390
    {
391
        $dir = $this->postDir();
392
        if (!$this->config['access']['files']['rename']
393
            || !isset($_POST['dir'])
394
            || !isset($_POST['file'])
395
            || !isset($_POST['newName'])
396
            || !$this->checkFilename($_POST['file'])
397
            || !$this->checkFilename($_POST['newName'])
398
            || (false === ($file = "$dir/{$_POST['file']}"))
399
            || !file_exists($file)
400
            || !is_readable($file)
401
            || !file::isWritable($file)) {
402
            $this->errorMsg('Unknown error.');
403
        }
404
405
        if (isset($this->config['denyExtensionRename'])
406
            && $this->config['denyExtensionRename']
407
            && (file::getExtension($_POST['file'], true) !== file::getExtension($_POST['newName'], true))) {
408
            $this->errorMsg('You cannot rename the extension of files!');
409
        }
410
411
        $newName = $this->normalizeFilename(trim($_POST['newName']));
412
        if (!strlen($newName)) {
413
            $this->errorMsg('Please enter new file name.');
414
        }
415
        if (preg_match('/[\/\\\\]/s', $newName)) {
416
            $this->errorMsg('Unallowable characters in file name.');
417
        }
418
        if ('.' == substr($newName, 0, 1)) {
419
            $this->errorMsg("File name shouldn't begins with '.'");
420
        }
421
        $newName = "$dir/$newName";
422
        if (file_exists($newName)) {
423
            $this->errorMsg('A file or folder with that name already exists.');
424
        }
425
        $ext = file::getExtension($newName);
426
        if (!$this->validateExtension($ext, $this->type)) {
427
            $this->errorMsg('Denied file extension.');
428
        }
429
        if (!@rename($file, $newName)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $file does not seem to be defined for all execution paths leading up to this point.
Loading history...
430
            $this->errorMsg('Unknown error.');
431
        }
432
433
        $thumbDir  = "{$this->thumbsTypeDir}/{$_POST['dir']}";
434
        $thumbFile = "$thumbDir/{$_POST['file']}";
435
436
        if (file_exists($thumbFile)) {
437
            @rename($thumbFile, "$thumbDir/" . basename($newName));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

437
            /** @scrutinizer ignore-unhandled */ @rename($thumbFile, "$thumbDir/" . basename($newName));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
438
        }
439
        return true;
440
    }
441
442
    protected function act_delete()
443
    {
444
        $dir = $this->postDir();
445
        if (!$this->config['access']['files']['delete']
446
            || !isset($_POST['dir'])
447
            || !isset($_POST['file'])
448
            || !$this->checkFilename($_POST['file'])
449
            || (false === ($file = "$dir/{$_POST['file']}"))
450
            || !file_exists($file)
451
            || !is_readable($file)
452
            || !file::isWritable($file)
453
            || !@unlink($file)) {
454
            $this->errorMsg('Unknown error.');
455
        }
456
457
        $thumb = "{$this->thumbsTypeDir}/{$_POST['dir']}/{$_POST['file']}";
458
        if (file_exists($thumb)) {
459
            @unlink($thumb);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

459
            /** @scrutinizer ignore-unhandled */ @unlink($thumb);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
460
        }
461
        return true;
462
    }
463
464
    protected function act_cp_cbd()
465
    {
466
        $dir = $this->postDir();
467
        if (!$this->config['access']['files']['copy']
468
            || !isset($_POST['dir'])
469
            || !is_dir($dir)
470
            || !is_readable($dir)
471
            || !dir::isWritable($dir)
472
            || !isset($_POST['files'])
473
            || !is_array($_POST['files'])
474
            || !count($_POST['files'])) {
475
            $this->errorMsg('Unknown error.');
476
        }
477
478
        $error = [];
479
        foreach ($_POST['files'] as $file) {
480
            $file = path::normalize($file);
481
            if ('.' == substr($file, 0, 1)) {
482
                continue;
483
            }
484
            $type = explode('/', $file);
485
            $type = $type[0];
486
            if ($type != $this->type) {
487
                continue;
488
            }
489
            $path = "{$this->config['uploadDir']}/$file";
490
            if (!$this->checkFilePath($path)) {
491
                continue;
492
            }
493
            $base    = basename($file);
494
            $replace = ['file' => $this->htmlData($base)];
495
            $ext     = file::getExtension($base);
496
            if (!file_exists($path)) {
497
                $error[] = $this->label("The file '{file}' does not exist.", $replace);
498
            } elseif ('.' == substr($base, 0, 1)) {
499
                $error[] = $this->htmlData($base) . ': ' . $this->label("File name shouldn't begins with '.'");
500
            } elseif (!$this->validateExtension($ext, $type)) {
501
                $error[] = $this->htmlData($base) . ': ' . $this->label('Denied file extension.');
502
            } elseif (file_exists("$dir/$base")) {
503
                $error[] = $this->htmlData($base) . ': ' . $this->label('A file or folder with that name already exists.');
504
            } elseif (!is_readable($path) || !is_file($path)) {
505
                $error[] = $this->label("Cannot read '{file}'.", $replace);
506
            } elseif (!@copy($path, "$dir/$base")) {
507
                $error[] = $this->label("Cannot copy '{file}'.", $replace);
508
            } else {
509
                if (function_exists('chmod')) {
510
                    @chmod("$dir/$base", $this->config['filePerms']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

510
                    /** @scrutinizer ignore-unhandled */ @chmod("$dir/$base", $this->config['filePerms']);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
511
                }
512
                $fromThumb = "{$this->thumbsDir}/$file";
513
                if (is_file($fromThumb) && is_readable($fromThumb)) {
514
                    $toThumb = "{$this->thumbsTypeDir}/{$_POST['dir']}";
515
                    if (!is_dir($toThumb)) {
516
                        @mkdir($toThumb, $this->config['dirPerms'], true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

516
                        /** @scrutinizer ignore-unhandled */ @mkdir($toThumb, $this->config['dirPerms'], true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
517
                    }
518
                    $toThumb .= "/$base";
519
                    @copy($fromThumb, $toThumb);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for copy(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

519
                    /** @scrutinizer ignore-unhandled */ @copy($fromThumb, $toThumb);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
520
                }
521
            }
522
        }
523
        if (count($error)) {
524
            return json_encode(['error' => $error]);
525
        }
526
        return true;
527
    }
528
529
    protected function act_mv_cbd()
530
    {
531
        $dir = $this->postDir();
532
        if (!$this->config['access']['files']['move']
533
            || !isset($_POST['dir'])
534
            || !is_dir($dir)
535
            || !is_readable($dir)
536
            || !dir::isWritable($dir)
537
            || !isset($_POST['files'])
538
            || !is_array($_POST['files'])
539
            || !count($_POST['files'])) {
540
            $this->errorMsg('Unknown error.');
541
        }
542
543
        $error = [];
544
        foreach ($_POST['files'] as $file) {
545
            $file = path::normalize($file);
546
            if ('.' == substr($file, 0, 1)) {
547
                continue;
548
            }
549
            $type = explode('/', $file);
550
            $type = $type[0];
551
            if ($type != $this->type) {
552
                continue;
553
            }
554
            $path = "{$this->config['uploadDir']}/$file";
555
            if (!$this->checkFilePath($path)) {
556
                continue;
557
            }
558
            $base    = basename($file);
559
            $replace = ['file' => $this->htmlData($base)];
560
            $ext     = file::getExtension($base);
561
            if (!file_exists($path)) {
562
                $error[] = $this->label("The file '{file}' does not exist.", $replace);
563
            } elseif ('.' == substr($base, 0, 1)) {
564
                $error[] = $this->htmlData($base) . ': ' . $this->label("File name shouldn't begins with '.'");
565
            } elseif (!$this->validateExtension($ext, $type)) {
566
                $error[] = $this->htmlData($base) . ': ' . $this->label('Denied file extension.');
567
            } elseif (file_exists("$dir/$base")) {
568
                $error[] = $this->htmlData($base) . ': ' . $this->label('A file or folder with that name already exists.');
569
            } elseif (!is_readable($path) || !is_file($path)) {
570
                $error[] = $this->label("Cannot read '{file}'.", $replace);
571
            } elseif (!file::isWritable($path) || !@rename($path, "$dir/$base")) {
572
                $error[] = $this->label("Cannot move '{file}'.", $replace);
573
            } else {
574
                if (function_exists('chmod')) {
575
                    @chmod("$dir/$base", $this->config['filePerms']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

575
                    /** @scrutinizer ignore-unhandled */ @chmod("$dir/$base", $this->config['filePerms']);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
576
                }
577
                $fromThumb = "{$this->thumbsDir}/$file";
578
                if (is_file($fromThumb) && is_readable($fromThumb)) {
579
                    $toThumb = "{$this->thumbsTypeDir}/{$_POST['dir']}";
580
                    if (!is_dir($toThumb)) {
581
                        @mkdir($toThumb, $this->config['dirPerms'], true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

581
                        /** @scrutinizer ignore-unhandled */ @mkdir($toThumb, $this->config['dirPerms'], true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
582
                    }
583
                    $toThumb .= "/$base";
584
                    @rename($fromThumb, $toThumb);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

584
                    /** @scrutinizer ignore-unhandled */ @rename($fromThumb, $toThumb);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
585
                }
586
            }
587
        }
588
        if (count($error)) {
589
            return json_encode(['error' => $error]);
590
        }
591
        return true;
592
    }
593
594
    protected function act_rm_cbd()
595
    {
596
        if (!$this->config['access']['files']['delete']
597
            || !isset($_POST['files'])
598
            || !is_array($_POST['files'])
599
            || !count($_POST['files'])) {
600
            $this->errorMsg('Unknown error.');
601
        }
602
603
        $error = [];
604
        foreach ($_POST['files'] as $file) {
605
            $file = path::normalize($file);
606
            if ('.' == substr($file, 0, 1)) {
607
                continue;
608
            }
609
            $type = explode('/', $file);
610
            $type = $type[0];
611
            if ($type != $this->type) {
612
                continue;
613
            }
614
            $path = "{$this->config['uploadDir']}/$file";
615
            if (!$this->checkFilePath($path)) {
616
                continue;
617
            }
618
            $base    = basename($file);
619
            $replace = ['file' => $this->htmlData($base)];
620
            if (!is_file($path)) {
621
                $error[] = $this->label("The file '{file}' does not exist.", $replace);
622
            } elseif (!@unlink($path)) {
623
                $error[] = $this->label("Cannot delete '{file}'.", $replace);
624
            } else {
625
                $thumb = "{$this->thumbsDir}/$file";
626
                if (is_file($thumb)) {
627
                    @unlink($thumb);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

627
                    /** @scrutinizer ignore-unhandled */ @unlink($thumb);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
628
                }
629
            }
630
        }
631
        if (count($error)) {
632
            return json_encode(['error' => $error]);
633
        }
634
        return true;
635
    }
636
637
    protected function act_downloadDir()
638
    {
639
        $dir = $this->postDir();
640
        if (!isset($_POST['dir']) || $this->config['denyZipDownload']) {
641
            $this->errorMsg('Unknown error.');
642
        }
643
        $filename = basename($dir) . '.zip';
644
        do {
645
            $file = md5(time() . session_id());
646
            $file = "{$this->config['uploadDir']}/$file.zip";
647
        } while (file_exists($file));
648
        new zipFolder($file, $dir);
649
        header('Content-Type: application/x-zip');
650
        header('Content-Disposition: attachment; filename="' . str_replace('"', '_', $filename) . '"');
651
        header('Content-Length: ' . filesize($file));
652
        readfile($file);
653
        unlink($file);
654
        die;
0 ignored issues
show
Best Practice introduced by
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...
655
    }
656
657
    protected function act_downloadSelected()
658
    {
659
        $dir = $this->postDir();
660
        if (!isset($_POST['dir'])
661
            || !isset($_POST['files'])
662
            || !is_array($_POST['files'])
663
            || $this->config['denyZipDownload']) {
664
            $this->errorMsg('Unknown error.');
665
        }
666
667
        $zipFiles = [];
668
        foreach ($_POST['files'] as $file) {
669
            $file = path::normalize($file);
670
            if (('.' == substr($file, 0, 1)) || (false !== strpos($file, '/'))) {
671
                continue;
672
            }
673
            $file = "$dir/$file";
674
            if (!is_file($file) || !is_readable($file) || !$this->checkFilePath($file)) {
675
                continue;
676
            }
677
            $zipFiles[] = $file;
678
        }
679
680
        do {
681
            $file = md5(time() . session_id());
682
            $file = "{$this->config['uploadDir']}/$file.zip";
683
        } while (file_exists($file));
684
685
        $zip = new \ZipArchive();
686
        $res = $zip->open($file, \ZipArchive::CREATE);
687
        if (true === $res) {
688
            foreach ($zipFiles as $cfile) {
689
                $zip->addFile($cfile, basename($cfile));
690
            }
691
            $zip->close();
692
        }
693
        header('Content-Type: application/x-zip');
694
        header('Content-Disposition: attachment; filename="selected_files_' . basename($file) . '"');
695
        header('Content-Length: ' . filesize($file));
696
        readfile($file);
697
        unlink($file);
698
        die;
0 ignored issues
show
Best Practice introduced by
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...
699
    }
700
701
    protected function act_downloadClipboard()
702
    {
703
        if (!isset($_POST['files'])
704
            || !is_array($_POST['files'])
705
            || $this->config['denyZipDownload']) {
706
            $this->errorMsg('Unknown error.');
707
        }
708
709
        $zipFiles = [];
710
        foreach ($_POST['files'] as $file) {
711
            $file = path::normalize($file);
712
            if (('.' == substr($file, 0, 1))) {
713
                continue;
714
            }
715
            $type = explode('/', $file);
716
            $type = $type[0];
717
            if ($type != $this->type) {
718
                continue;
719
            }
720
            $file = $this->config['uploadDir'] . "/$file";
721
            if (!is_file($file) || !is_readable($file) || !$this->checkFilePath($file)) {
722
                continue;
723
            }
724
            $zipFiles[] = $file;
725
        }
726
727
        do {
728
            $file = md5(time() . session_id());
729
            $file = "{$this->config['uploadDir']}/$file.zip";
730
        } while (file_exists($file));
731
732
        $zip = new \ZipArchive();
733
        $res = $zip->open($file, \ZipArchive::CREATE);
734
        if (true === $res) {
735
            foreach ($zipFiles as $cfile) {
736
                $zip->addFile($cfile, basename($cfile));
737
            }
738
            $zip->close();
739
        }
740
        header('Content-Type: application/x-zip');
741
        header('Content-Disposition: attachment; filename="clipboard_' . basename($file) . '"');
742
        header('Content-Length: ' . filesize($file));
743
        readfile($file);
744
        unlink($file);
745
        die;
0 ignored issues
show
Best Practice introduced by
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...
746
    }
747
748
    protected function act_check4Update()
749
    {
750
        if ($this->config['denyUpdateCheck']) {
751
            return json_encode(['version' => false]);
752
        }
753
754
        // Caching HTTP request for 6 hours
755
        if (isset($this->session['checkVersion'])
756
            && isset($this->session['checkVersionTime'])
757
            && ((time() - $this->session['checkVersionTime']) < 21600)) {
758
            return json_encode(['version' => $this->session['checkVersion']]);
759
        }
760
761
        $ver = phpGet::get('http://kcfinder.sunhater.com/checkVersion.php');
762
763
        if (isset($ver) && preg_match('/^\d+\.\d+$/', $ver)) {
764
            $this->session['checkVersion']     = $ver;
765
            $this->session['checkVersionTime'] = time();
766
            return json_encode(['version' => $ver]);
767
        } else {
768
            return json_encode(['version' => false]);
769
        }
770
    }
771
772
    protected function moveUploadFile($file, $dir)
773
    {
774
        $message = $this->checkUploadedFile($file);
775
776
        if (true !== $message) {
777
            if (isset($file['tmp_name'])) {
778
                @unlink($file['tmp_name']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

778
                /** @scrutinizer ignore-unhandled */ @unlink($file['tmp_name']);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
779
            }
780
            return "{$file['name']}: $message";
781
        }
782
783
        $filename = $this->normalizeFilename($file['name']);
784
        $target   = "$dir/" . file::getInexistantFilename($filename, $dir);
785
786
        if (!@move_uploaded_file($file['tmp_name'], $target)
787
            && !@rename($file['tmp_name'], $target)
788
            && !@copy($file['tmp_name'], $target)) {
789
            @unlink($file['tmp_name']);
790
            return $this->htmlData($file['name']) . ': ' . $this->label('Cannot move uploaded file to target folder.');
791
        } elseif (function_exists('chmod')) {
792
            chmod($target, $this->config['filePerms']);
793
        }
794
795
        $this->makeThumb($target);
796
        return '/' . basename($target);
797
    }
798
799
    protected function sendDefaultThumb($file = null)
800
    {
801
        if (null !== $file) {
802
            $ext   = file::getExtension($file);
803
            $thumb = "themes/{$this->config['theme']}/img/files/big/$ext.png";
804
        }
805
        if (!isset($thumb) || !file_exists($thumb)) {
806
            $thumb = "themes/{$this->config['theme']}/img/files/big/..png";
807
        }
808
        header('Content-Type: image/png');
809
        readfile($thumb);
810
        die;
0 ignored issues
show
Best Practice introduced by
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...
811
    }
812
813
    protected function getFiles($dir)
814
    {
815
        $thumbDir = "{$this->config['uploadDir']}/{$this->config['thumbsDir']}/$dir";
816
        $dir      = "{$this->config['uploadDir']}/$dir";
817
        $return   = [];
818
        $files    = dir::content($dir, ['types' => 'file']);
819
        if (false === $files) {
0 ignored issues
show
introduced by
The condition false === $files is always true.
Loading history...
820
            return $return;
821
        }
822
823
        foreach ($files as $file) {
824
            $img  = new fastImage($file);
825
            $type = $img->getType();
826
827
            if (false !== $type) {
828
                $size = $img->getSize($file);
829
                if (is_array($size) && count($size)) {
830
                    $thumb_file = "$thumbDir/" . basename($file);
831
                    if (!is_file($thumb_file)) {
832
                        $this->makeThumb($file, false);
833
                    }
834
                    $smallThumb = ($size[0] <= $this->config['thumbWidth'])
835
                                  && ($size[1] <= $this->config['thumbHeight'])
836
                                  && in_array($type, ['gif', 'jpeg', 'png']);
837
                } else {
838
                    $smallThumb = false;
839
                }
840
            } else {
841
                $smallThumb = false;
842
            }
843
844
            $img->close();
845
846
            $stat = stat($file);
847
            if (false === $stat) {
848
                continue;
849
            }
850
            $name      = basename($file);
851
            $ext       = file::getExtension($file);
852
            $bigIcon   = file_exists("themes/{$this->config['theme']}/img/files/big/$ext.png");
853
            $smallIcon = file_exists("themes/{$this->config['theme']}/img/files/small/$ext.png");
854
            $thumb     = file_exists("$thumbDir/$name");
855
            $return[]  = [
856
                'name'       => stripcslashes($name),
857
                'size'       => $stat['size'],
858
                'mtime'      => $stat['mtime'],
859
                'date'       => @strftime($this->dateTimeSmall, $stat['mtime']),
860
                'readable'   => is_readable($file),
861
                'writable'   => file::isWritable($file),
862
                'bigIcon'    => $bigIcon,
863
                'smallIcon'  => $smallIcon,
864
                'thumb'      => $thumb,
865
                'smallThumb' => $smallThumb
866
            ];
867
        }
868
        return $return;
869
    }
870
871
    protected function getTree($dir, $index = 0)
872
    {
873
        $path = explode('/', $dir);
874
875
        $pdir = '';
876
        for ($i = 0; ($i <= $index && $i < count($path)); $i++) {
877
            $pdir .= "/{$path[$i]}";
878
        }
879
        if (strlen($pdir)) {
880
            $pdir = substr($pdir, 1);
881
        }
882
883
        $fdir = "{$this->config['uploadDir']}/$pdir";
884
885
        $dirs = $this->getDirs($fdir);
886
887
        if (is_array($dirs) && count($dirs) && ($index <= count($path) - 1)) {
888
            foreach ($dirs as $i => $cdir) {
889
                if ($cdir['hasDirs']
890
                    && (($index == count($path) - 1)
891
                        || ($cdir['name'] == $path[$index + 1]))) {
892
                    $dirs[$i]['dirs'] = $this->getTree($dir, $index + 1);
893
                    if (!is_array($dirs[$i]['dirs']) || !count($dirs[$i]['dirs'])) {
894
                        unset($dirs[$i]['dirs']);
895
                        continue;
896
                    }
897
                }
898
            }
899
        } else {
900
            return false;
901
        }
902
903
        return $dirs;
904
    }
905
906
    protected function postDir($existent = true)
907
    {
908
        $dir = $this->typeDir;
909
        if (isset($_POST['dir'])) {
910
            $dir .= '/' . $_POST['dir'];
911
        }
912
        if (!$this->checkFilePath($dir)) {
913
            $this->errorMsg('Unknown error.');
914
        }
915
        if ($existent && (!is_dir($dir) || !is_readable($dir))) {
916
            $this->errorMsg('Inexistant or inaccessible folder.');
917
        }
918
        return $dir;
919
    }
920
921
    protected function getDir($existent = true)
922
    {
923
        $dir = $this->typeDir;
924
        if (isset($_GET['dir'])) {
925
            $dir .= '/' . $_GET['dir'];
926
        }
927
        if (!$this->checkFilePath($dir)) {
928
            $this->errorMsg('Unknown error.');
929
        }
930
        if ($existent && (!is_dir($dir) || !is_readable($dir))) {
931
            $this->errorMsg('Inexistant or inaccessible folder.');
932
        }
933
        return $dir;
934
    }
935
936
    protected function getDirs($dir)
937
    {
938
        $dirs   = dir::content($dir, ['types' => 'dir']);
939
        $return = [];
940
        if (is_array($dirs)) {
0 ignored issues
show
introduced by
The condition is_array($dirs) is always false.
Loading history...
941
            $writable = dir::isWritable($dir);
942
            foreach ($dirs as $cdir) {
943
                $info = $this->getDirInfo($cdir);
944
                if (false === $info) {
945
                    continue;
946
                }
947
                $info['removable'] = $writable && $info['writable'];
948
                $return[]          = $info;
949
            }
950
        }
951
        return $return;
952
    }
953
954
    protected function getDirInfo($dir, $removable = false)
955
    {
956
        if (('.' == substr(basename($dir), 0, 1)) || !is_dir($dir) || !is_readable($dir)) {
957
            return false;
958
        }
959
        $dirs = dir::content($dir, ['types' => 'dir']);
960
        if (is_array($dirs)) {
0 ignored issues
show
introduced by
The condition is_array($dirs) is always false.
Loading history...
961
            foreach ($dirs as $key => $cdir) {
962
                if ('.' == substr(basename($cdir), 0, 1)) {
963
                    unset($dirs[$key]);
964
                }
965
            }
966
            $hasDirs = count($dirs) ? true : false;
967
        } else {
968
            $hasDirs = false;
969
        }
970
971
        $writable = dir::isWritable($dir);
972
        $info     = [
973
            'name'      => stripslashes(basename($dir)),
974
            'readable'  => is_readable($dir),
975
            'writable'  => $writable,
976
            'removable' => $removable && $writable && dir::isWritable(dirname($dir)),
977
            'hasDirs'   => $hasDirs
978
        ];
979
980
        if ("{$this->config['uploadDir']}/{$this->session['dir']}" == $dir) {
981
            $info['current'] = true;
982
        }
983
984
        return $info;
985
    }
986
987
    protected function output($data = null, $template = null)
988
    {
989
        if (!is_array($data)) {
990
            $data = [];
991
        }
992
        if (null === $template) {
993
            $template = $this->action;
994
        }
995
996
        if (file_exists("tpl/tpl_$template.php")) {
997
            ob_start();
998
            $eval = 'unset($data);unset($template);unset($eval);';
999
            $_    = $data;
0 ignored issues
show
Unused Code introduced by
The assignment to $_ is dead and can be removed.
Loading history...
1000
            foreach (array_keys($data) as $key) {
1001
                if (preg_match('/^[a-z\d_]+$/i', $key)) {
1002
                    $eval .= "\$$key=\$_['$key'];";
1003
                }
1004
            }
1005
            $eval .= "unset(\$_);require \"tpl/tpl_$template.php\";";
1006
            eval($eval);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
1007
            return ob_get_clean();
1008
        }
1009
1010
        return '';
1011
    }
1012
1013
    protected function errorMsg($message, array $data = null)
1014
    {
1015
        if (in_array($this->action, ['thumb', 'upload', 'download', 'downloadDir'])) {
1016
            die($this->label($message, $data));
0 ignored issues
show
Best Practice introduced by
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...
1017
        }
1018
        if ((null === $this->action) || ('browser' == $this->action)) {
1019
            $this->backMsg($message, $data);
1020
        } else {
1021
            $message = $this->label($message, $data);
1022
            die(json_encode(['error' => $message]));
0 ignored issues
show
Best Practice introduced by
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...
1023
        }
1024
    }
1025
1026
    protected function htmlData($str)
1027
    {
1028
        return htmlentities($str, null, strtoupper($this->charset));
0 ignored issues
show
Bug introduced by
null of type null is incompatible with the type integer expected by parameter $flags of htmlentities(). ( Ignorable by Annotation )

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

1028
        return htmlentities($str, /** @scrutinizer ignore-type */ null, strtoupper($this->charset));
Loading history...
1029
    }
1030
1031
    protected function downloadURL($url, $dir)
1032
    {
1033
        if (!preg_match(phpGet::$urlExpr, $url, $match)) {
1034
            return;
1035
        }
1036
1037
        if ((isset($match[7]) && strlen($match[7]))) {
1038
            $furl = explode('&', $match[7]);
1039
        }
1040
1041
        $filename = isset($furl) ? basename($furl[0]) : 'web_image.jpg';
1042
1043
        $file = tempnam(sys_get_temp_dir(), $filename);
1044
1045
        if (phpGet::get($url, $file)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression kcfinder\phpGet::get($url, $file) of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1046
            $this->moveUploadFile(
1047
                [
1048
                    'name'     => $filename,
1049
                    'tmp_name' => $file,
1050
                    'error'    => UPLOAD_ERR_OK
1051
                ],
1052
                $dir
1053
            );
1054
        } else {
1055
            @unlink($file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

1055
            /** @scrutinizer ignore-unhandled */ @unlink($file);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1056
        }
1057
    }
1058
1059
    protected function getLangs()
1060
    {
1061
        if (isset($this->session['langs'])) {
1062
            return $this->session['langs'];
1063
        }
1064
1065
        $files = dir::content(
1066
            'lang',
1067
            [
1068
                'pattern' => '/^[a-z]{2,3}(\-[a-z]{2})?\.php$/',
1069
                'types'   => 'file'
1070
            ]
1071
        );
1072
1073
        $langs = [];
1074
        if (is_array($files)) {
0 ignored issues
show
introduced by
The condition is_array($files) is always false.
Loading history...
1075
            foreach ($files as $file) {
1076
                include $file;
1077
                $id         = substr(basename($file), 0, -4);
1078
                $langs[$id] = isset($lang['_native']) ? $lang['_native'] : (isset($lang['_lang']) ? $lang['_lang'] : $id);
1079
            }
1080
        }
1081
1082
        $this->session['langs'] = $langs;
1083
        return $langs;
1084
    }
1085
}
1086