Passed
Push — master ( 0d3aa7...3fa478 )
by Nils
04:52
created

loadTreeStrategy()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 52
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 23
c 1
b 0
f 0
nc 5
nop 6
dl 0
loc 52
rs 9.2408

How to fix   Long Method   

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
declare(strict_types=1);
4
5
/**
6
 * Teampass - a collaborative passwords manager.
7
 * ---
8
 * This library is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @project   Teampass
13
 * @file      tree.php
14
 *
15
 * @author    Nils Laumaillé ([email protected])
16
 * @copyright 2009-2022 Teampass.net
17
 * @license   https://spdx.org/licenses/GPL-3.0-only.html#licenseText GPL-3.0
18
 *
19
 * @see       https://www.teampass.net
20
 */
21
22
23
require_once 'SecureHandler.php';
24
session_name('teampass_session');
25
session_start();
26
if (
27
    isset($_SESSION['CPM']) === false
28
    || $_SESSION['CPM'] !== 1
29
    || isset($_SESSION['key']) === false
30
    || empty($_SESSION['key']) === true
31
) {
32
    die('Hacking attempt...');
33
}
34
35
// Load config
36
if (file_exists('../includes/config/tp.config.php')) {
37
    include_once '../includes/config/tp.config.php';
38
} elseif (file_exists('./includes/config/tp.config.php')) {
39
    include_once './includes/config/tp.config.php';
40
} else {
41
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
42
}
43
44
// includes
45
require_once $SETTINGS['cpassman_dir'] . '/includes/config/include.php';
46
require_once $SETTINGS['cpassman_dir'] . '/sources/main.functions.php';
47
require_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
48
require_once $SETTINGS['cpassman_dir'] . '/includes/config/settings.php';
49
50
// header
51
header('Content-type: text/html; charset=utf-8');
52
header('Cache-Control: no-cache, must-revalidate');
53
54
// Define Timezone
55
if (isset($SETTINGS['timezone'])) {
56
    date_default_timezone_set($SETTINGS['timezone']);
57
} else {
58
    date_default_timezone_set('UTC');
59
}
60
61
// Connect to mysql server
62
require_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Database/Meekrodb/db.class.php';
63
if (defined('DB_PASSWD_CLEAR') === false) {
64
    define('DB_PASSWD_CLEAR', defuseReturnDecrypted(DB_PASSWD, $SETTINGS));
65
}
66
DB::$host = DB_HOST;
67
DB::$user = DB_USER;
68
DB::$password = DB_PASSWD_CLEAR;
69
DB::$dbName = DB_NAME;
70
DB::$port = DB_PORT;
71
DB::$encoding = DB_ENCODING;
72
DB::$ssl = DB_SSL;
73
DB::$connect_options = DB_CONNECT_OPTIONS;
74
75
// Superglobal load
76
require_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
77
$superGlobal = new protect\SuperGlobal\SuperGlobal();
78
79
// Prepare sanitization
80
$data = [
81
    'forbidenPfs' => isset($_SESSION['forbiden_pfs']) === true ? json_encode($_SESSION['forbiden_pfs']) : '',
82
    'visibleFolders' => isset($_SESSION['groupes_visibles']) === true ? json_encode($_SESSION['groupes_visibles']) : '',
83
    'userId' => isset($_SESSION['id']) === true ? $_SESSION['id'] : '',
84
    'userLogin' => isset($_SESSION['login']) === true ? $_SESSION['login'] : '',
85
    'userReadOnly' => isset($_SESSION['user_read_only']) === true ? $_SESSION['user_read_only'] : '',
86
    'limitedFolders' => isset($_SESSION['list_folders_limited']) === true ? json_encode($_SESSION['list_folders_limited']) : '',
87
    'readOnlyFolders' => isset($_SESSION['read_only_folders']) === true ? json_encode($_SESSION['read_only_folders']) : '',
88
    'personalVisibleFolders' => isset($_SESSION['personal_visible_groups']) === true ? json_encode($_SESSION['personal_visible_groups']) : '',
89
    'userTreeLastRefresh' => isset($_SESSION['user_tree_last_refresh_timestamp']) === true ? $_SESSION['user_tree_last_refresh_timestamp'] : '',
90
    'forceRefresh' => isset($_GET['force_refresh']) === true ? $_GET['force_refresh'] : '',
91
    'nodeId' => isset($_GET['id']) === true ? $_GET['id'] : '',
92
    'restrictedFoldersForItems' => isset($_GET['list_restricted_folders_for_items']) === true ? json_encode($_GET['list_restricted_folders_for_items']) : '',
93
    'noAccessFolders' => isset($_SESSION['no_access_folders']) === true ? json_encode($_SESSION['no_access_folders']) : '',
94
    'personalFolders' => isset($_SESSION['personal_folders']) === true ? json_encode($_SESSION['personal_folders']) : '',
95
    'userCanCreateRootFolder' => isset($_SESSION['can_create_root_folder']) === true ? json_encode($_SESSION['can_create_root_folder']) : '',
96
    'userTreeLoadStrategy' => isset($_SESSION['user_treeloadstrategy']) === true ? $_SESSION['user_treeloadstrategy'] : '',
97
];
98
99
$filters = [
100
    'forbidenPfs' => 'cast:array',
101
    'visibleFolders' => 'cast:array',
102
    'userId' => 'cast:integer',
103
    'userLogin' => 'trim|escape',
104
    'userReadOnly' => 'cast:boolean',
105
    'limitedFolders' => 'cast:array',
106
    'readOnlyFolders' => 'cast:array',
107
    'personalVisibleFolders' => 'cast:array',
108
    'userTreeLastRefresh' => 'cast:integer',
109
    'forceRefresh' => 'cast:integer',
110
    'nodeId' => 'cast:integer',
111
    'restrictedFoldersForItems' => 'cast:array',
112
    'noAccessFolders' => 'cast:array',
113
    'personalFolders' => 'cast:array',
114
    'userCanCreateRootFolder' => 'cast:array',
115
    'userTreeLoadStrategy' => 'trim|escape',
116
];
117
118
$inputData = dataSanitizer(
119
    $data,
120
    $filters,
121
    $SETTINGS['cpassman_dir']
122
);
123
124
$lastFolderChange = DB::queryfirstrow(
125
    'SELECT valeur FROM ' . prefixTable('misc') . '
126
    WHERE type = %s AND intitule = %s',
127
    'timestamp',
128
    'last_folder_change'
129
);
130
131
// Should we use a cache or refresh the tree
132
$goTreeRefresh = loadTreeStrategy(
133
    (int) $lastFolderChange['valeur'],
134
    (int) $inputData['userTreeLastRefresh'],
135
    $superGlobal->get('user_tree_structure', 'SESSION'),
136
    (int) $inputData['userId'],
137
    (int) $inputData['forceRefresh'],
138
    $SETTINGS
139
);
140
141
if ($goTreeRefresh['state'] === true) {
142
    // Build tree
143
    require_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Tree/NestedTree/NestedTree.php';
144
    $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
145
146
    if (
147
        isset($inputData['limitedFolders']) === true
148
        && is_array($inputData['limitedFolders']) === true
149
        && count($inputData['limitedFolders']) > 0
150
    ) {
151
        $listFoldersLimitedKeys = array_keys($inputData['limitedFolders']);
152
    } else {
153
        $listFoldersLimitedKeys = array();
154
    }
155
    
156
    // list of items accessible but not in an allowed folder
157
    if (
158
        isset($inputData['restrictedFoldersForItems']) === true
159
        && count($inputData['restrictedFoldersForItems']) > 0
160
    ) {
161
        $listRestrictedFoldersForItemsKeys = @array_keys($inputData['restrictedFoldersForItems']);
162
    } else {
163
        $listRestrictedFoldersForItemsKeys = array();
164
    }
165
    
166
    //$_SESSION['user_treeloadstrategy'] = 'sequential';
167
    $ret_json = array();
168
    $last_visible_parent = -1;
169
    $last_visible_parent_level = 1;
170
    $nodeId = isset($inputData['nodeId']) === true && is_int($inputData['nodeId']) === true ? $inputData['nodeId'] : 0;
171
172
    // build the tree to be displayed
173
    if (showFolderToUser(
174
        $nodeId,
175
        $inputData['forbidenPfs'],
176
        $inputData['visibleFolders'],
177
        $listFoldersLimitedKeys,
178
        $listRestrictedFoldersForItemsKeys
179
    ) === true)
180
    {
181
        if ($inputData['userTreeLoadStrategy'] === 'sequential') {
182
            // SEQUENTIAL MODE
183
            // Is this folder visible by user
184
            $ret_json = buildNodeTree(
185
                $nodeId,
186
                $listFoldersLimitedKeys,
187
                $listRestrictedFoldersForItemsKeys,
188
                /** @scrutinizer ignore-type */ $tree,
189
                $SETTINGS,
190
                $inputData['forbidenPfs'],
191
                $inputData['visibleFolders'],
192
                $inputData['restrictedFoldersForItems'],
193
                $inputData['userId'],
194
                $inputData['userLogin'],
195
                $inputData['noAccessFolders'],
196
                $inputData['limitedFolders'],
197
                $inputData['readOnlyFolders'],
198
                $inputData['personalFolders'],
199
                $inputData['personalVisibleFolders'],
200
                $inputData['userReadOnly']
201
            );
202
        } else {
203
            // FULL MODE
204
            $completTree = $tree->getTreeWithChildren();
205
            foreach ($completTree[0]->children as $child) {
206
                recursiveTree(
207
                    $child,
208
                    $completTree,
209
                    /** @scrutinizer ignore-type */ $tree,
210
                    $listFoldersLimitedKeys,
211
                    $listRestrictedFoldersForItemsKeys,
212
                    $last_visible_parent,
213
                    $last_visible_parent_level,
214
                    $SETTINGS,
215
                    $inputData['forbidenPfs'],
216
                    $inputData['visibleFolders'],
217
                    $inputData['restrictedFoldersForItems'],
218
                    $inputData['userId'],
219
                    $inputData['userLogin'],
220
                    $inputData['userReadOnly'],
221
                    $inputData['personalFolders'],
222
                    $inputData['limitedFolders'],
223
                    $inputData['readOnlyFolders'],
224
                    $inputData['personalVisibleFolders'],
225
                    $inputData['userCanCreateRootFolder'],
226
                    $ret_json
227
                );
228
            }
229
        }
230
    }
231
232
    // Save in SESSION
233
    $superGlobal->put('user_tree_structure', $ret_json, 'SESSION');
234
    $superGlobal->put('user_tree_last_refresh_timestamp', time(), 'SESSION');
235
236
    $ret_json = json_encode($ret_json);
237
238
    // Save user folders tree
239
    cacheTreeUserHandler(
240
        (int) $_SESSION['id'],
241
        $ret_json,
242
        $SETTINGS
243
    );
244
245
    // Send back
246
    echo $ret_json;
247
} else {
248
    echo $goTreeRefresh['data'];
249
}
250
251
/**
252
 * Check if user can see this folder based upon rights
253
 *
254
 * @param integer $nodeId
255
 * @param array $session_forbiden_pfs
256
 * @param array $session_groupes_visibles
257
 * @param array $listFoldersLimitedKeys
258
 * @param array $listRestrictedFoldersForItemsKeys
259
 * @return boolean
260
 */
261
function showFolderToUser(
262
    int $nodeId,
263
    array $session_forbiden_pfs,
264
    array $session_groupes_visibles,
265
    array $listFoldersLimitedKeys,
266
    array $listRestrictedFoldersForItemsKeys
267
): bool
268
{
269
    if (
270
        in_array($nodeId, $session_forbiden_pfs) === false
271
        || in_array($nodeId, $session_groupes_visibles) === true
272
        || in_array($nodeId, $listFoldersLimitedKeys) === true
273
        || in_array($nodeId, $listRestrictedFoldersForItemsKeys) === true
274
    ) {
275
        return true;
276
    }
277
    return false;
278
}
279
280
/**
281
 * Get through asked folders
282
 *
283
 * @param int $nodeId
284
 * @param array $listFoldersLimitedKeys
285
 * @param array $listRestrictedFoldersForItemsKeys
286
 * @param array $tree
287
 * @param array $SETTINGS
288
 * @param array $session_forbiden_pfs
289
 * @param array $session_groupes_visibles
290
 * @param array $session_list_restricted_folders_for_items
291
 * @param int $session_user_id
292
 * @param string $session_login
293
 * @param array $session_no_access_folders
294
 * @param array $session_list_folders_limited
295
 * @param array $session_read_only_folders
296
 * @param array $session_personal_folders
297
 * @param array $session_personal_visible_groups
298
 * @param int $session_user_read_only
299
 * @return array
300
 */
301
function buildNodeTree(
302
    $nodeId,
303
    $listFoldersLimitedKeys,
304
    $listRestrictedFoldersForItemsKeys,
305
    $tree,
306
    $SETTINGS,
307
    $session_forbiden_pfs,
308
    $session_groupes_visibles,
309
    $session_list_restricted_folders_for_items,
310
    $session_user_id,
311
    $session_login,
312
    $session_no_access_folders,
313
    $session_list_folders_limited,
314
    $session_read_only_folders,
315
    $session_personal_folders,
316
    $session_personal_visible_groups,
317
    $session_user_read_only
318
) {
319
    // Prepare variables
320
    $ret_json = array();
321
    $nbChildrenItems = 0;
322
323
    // Check if any allowed folder is part of the descendants of this node
324
    $nodeDescendants = $tree->getDescendants($nodeId, false, true, false);
325
    foreach ($nodeDescendants as $node) {
326
        if (showFolderToUser(
327
                $node->id,
328
                $session_forbiden_pfs,
329
                $session_groupes_visibles,
330
                $listFoldersLimitedKeys,
331
                $listRestrictedFoldersForItemsKeys
332
            ) === true
333
            && (in_array(
334
                $node->id,
335
                array_merge($session_groupes_visibles, $session_list_restricted_folders_for_items)
336
            ) === true
337
                || (is_array($listFoldersLimitedKeys) === true && in_array($node->id, $listFoldersLimitedKeys) === true)
338
                || (is_array($listRestrictedFoldersForItemsKeys) === true && in_array($node->id, $listRestrictedFoldersForItemsKeys) === true)
339
                || in_array($node->id, $session_no_access_folders) === true)
340
        ) {
341
            $nodeElements= buildNodeTreeElements(
342
                $node,
343
                $session_user_id,
344
                $session_login,
345
                $session_user_read_only,
346
                $session_personal_folders,
347
                $session_groupes_visibles,
348
                $session_read_only_folders,
349
                $session_personal_visible_groups,
350
                $nbChildrenItems,
351
                $nodeDescendants,
352
                $listFoldersLimitedKeys,
353
                $session_list_folders_limited,
354
                $listRestrictedFoldersForItemsKeys,
355
                $session_list_restricted_folders_for_items,
356
                $SETTINGS,
357
                $tree->numDescendants($node->id)
358
            );
359
360
            // json    
361
            array_push(
362
                $ret_json,
363
                array(
364
                    'id' => 'li_' . $node->id,
365
                    'parent' => $nodeElements['parent'],
366
                    'text' => '<i class="fas fa-folder mr-2"></i>'.($nodeElements['show_but_block'] === true ? '<i class="fas fa-times fa-xs text-danger mr-1"></i>' : '') . $nodeElements['text'],
367
                    'children' => ($nodeElements['childrenNb'] === 0 ? false : true),
368
                    'fa_icon' => 'folder',
369
                    'li_attr' => array(
370
                        'class' => ($nodeElements['show_but_block'] === true ? '' : 'jstreeopen'),
371
                        'title' => 'ID [' . $node->id . '] ' . ($nodeElements['show_but_block'] === true ? langHdl('no_access') : $nodeElements['title']),
372
                    ),
373
                    'a_attr' => $nodeElements['show_but_block'] === true ? (array(
374
                        'id' => 'fld_' . $node->id,
375
                        'class' => $nodeElements['folderClass'],
376
                        'onclick' => 'ListerItems(' . $node->id . ', ' . $nodeElements['restricted'] . ', 0, 1)',
377
                        'data-title' => $node->title,
378
                    )) : '',
379
                    'is_pf' => in_array($node->id, $session_personal_folders) === true ? 1 : 0,
380
                )
381
            );
382
        }
383
    }
384
385
    return $ret_json;
386
}
387
388
/**
389
 * Get some infos for this node
390
 *
391
 * @param integer   $nodeId
392
 * @param integer   $nodeLevel
393
 * @param string    $nodeTitle
394
 * @param integer   $userId
395
 * @param string    $userLogin
396
 * @param bool      $userIsRO
397
 * @param array     $userPF
398
 * @return array
399
 */
400
function getNodeInfos(
401
    int $nodeId,
402
    int $nodeLevel,
403
    string $nodeTitle,
404
    int $userId,
405
    string $userLogin,
406
    bool $userIsRO,
407
    array $userPF
408
) : array
409
{
410
    $ret = [];
411
    // get count of Items in this folder
412
    DB::query(
413
        'SELECT *
414
        FROM ' . prefixTable('items') . '
415
        WHERE inactif=%i AND id_tree = %i',
416
        0,
417
        $nodeId
418
    );
419
    $ret['itemsNb'] = DB::count();
420
421
    // get info about current folder
422
    DB::query(
423
        'SELECT *
424
        FROM ' . prefixTable('nested_tree') . '
425
        WHERE parent_id = %i',
426
        $nodeId
427
    );
428
    $ret['childrenNb'] = DB::count();
429
430
    // Manage node title
431
    if ($userIsRO === true && in_array($nodeId, $userPF) === false) {
432
        // special case for READ-ONLY folder
433
        $ret['title'] = langHdl('read_only_account');
434
    } else {
435
        // If personal Folder, convert id into user name
436
        $ret['title'] = (string) $nodeTitle === (string) $userId && (int) $nodeLevel === 1 ?
437
        $userLogin :
438
        htmlspecialchars_decode($nodeTitle, ENT_QUOTES);
439
    }
440
441
    $ret['text'] = str_replace(
442
        '&',
443
        '&amp;',
444
        $ret['nodeTitle']
445
    );
446
447
    return $ret;
448
}
449
450
function buildNodeTreeElements(
451
    $node,
452
    $session_user_id,
453
    $session_login,
454
    $session_user_read_only,
455
    $session_personal_folders,
456
    $session_groupes_visibles,
457
    $session_read_only_folders,
458
    $session_personal_visible_groups,
459
    $nbChildrenItems,
460
    $nodeDescendants,
461
    $listFoldersLimitedKeys,
462
    $session_list_folders_limited,
463
    $listRestrictedFoldersForItemsKeys,
464
    $session_list_restricted_folders_for_items,
465
    $SETTINGS,
466
    $numDescendants
467
)
468
{
469
    // Get info for this node
470
    $nodeInfos = getNodeInfos(
471
        $node->id,
472
        $node->nlevel,
473
        $node->title,
474
        $session_user_id,
475
        $session_login,
476
        $session_user_read_only,
477
        $session_personal_folders
478
    );
479
    $itemsNb = $nodeInfos['itemsNb'];
480
    $childrenNb = $nodeInfos['childrenNb'];
481
    $title = $nodeInfos['title'];
482
    $text = $nodeInfos['text'];
483
484
    // prepare json return for current node
485
    $parent = $node->parent_id === 0 ? '#' : 'li_' . $node->parent_id;
486
487
    if (in_array($node->id, $session_groupes_visibles) === true) {
488
        if (in_array($node->id, $session_read_only_folders) === true) {
489
            return array(
490
                'text' => '<i class="far fa-eye fa-xs mr-1 ml-1"></i>' . $text
491
                    .' <span class=\'badge badge-danger ml-2 items_count\' id=\'itcount_' . $node->id . '\'>' . $itemsNb . '</span>'
492
                    .(isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true ?
493
                        '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)
494
                        : '')
495
                    .'</span>',
496
                'title' => langHdl('read_only_account'),
497
                'restricted' => 1,
498
                'folderClass' => 'folder_not_droppable',
499
                'show_but_block' => false,
500
                'parent' => $parent,
501
                'childrenNb' => $childrenNb,
502
                'itemsNb' => $itemsNb,
503
            );
504
        }
505
        
506
        return array(
507
            'text' => ($session_user_read_only === true && in_array($node->id, $session_personal_visible_groups) === false) ?
508
                ('<i class="far fa-eye fa-xs mr-1 ml-1"></i>' . $text
509
                .' <span class=\'badge badge-danger ml-2 items_count\' id=\'itcount_' . $node->id . '\'>' . $itemsNb . '</span>'
510
                .(isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true ?
511
                    '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  :
512
                    '')
513
                .'</span>') :
514
                (' <span class=\'badge badge-danger ml-2 items_count\' id=\'itcount_' . $node->id . '\'>' . $itemsNb . '</span>'
515
                .(isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true ?
516
                    '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  :
517
                    '')
518
                .'</span>'),
519
            'title' => langHdl('read_only_account'),
520
            'restricted' => 1,
521
            'folderClass' => 'folder_not_droppable',
522
            'show_but_block' => false,
523
            'parent' => $parent,
524
            'childrenNb' => $childrenNb,
525
            'itemsNb' => $itemsNb,
526
        );
527
    }
528
    
529
    if (in_array($node->id, $listFoldersLimitedKeys) === true) {
530
        return array(
531
            'text' => $text . ($session_user_read_only === true ?
532
                '<i class="far fa-eye fa-xs mr-1 ml-1"></i>' :
533
                '<span class="badge badge-danger ml-2 items_count" id="itcount_' . $node->id . '">' . count($session_list_folders_limited[$node->id]) . '</span>'
534
            ),
535
            'title' => $title,
536
            'restricted' => 1,
537
            'folderClass' => 'folder',
538
            'show_but_block' => false,
539
            'parent' => $parent,
540
            'childrenNb' => $childrenNb,
541
            'itemsNb' => $itemsNb,
542
        );
543
    }
544
    
545
    if (in_array($node->id, $listRestrictedFoldersForItemsKeys) === true) {        
546
        return array(
547
            'text' => $text . ($session_user_read_only === true ? 
548
                '<i class="far fa-eye fa-xs mr-1 ml-1"></i>' :
549
                '<span class="badge badge-danger ml-2 items_count" id="itcount_' . $node->id . '">' . count($session_list_restricted_folders_for_items[$node->id]) . '</span>'
550
            ),
551
            'title' => $title,
552
            'restricted' => 1,
553
            'folderClass' => 'folder',
554
            'show_but_block' => false,
555
            'parent' => $parent,
556
            'childrenNb' => $childrenNb,
557
            'itemsNb' => $itemsNb,
558
        );
559
    }
560
561
    // default case
562
    if (isKeyExistingAndEqual('show_only_accessible_folders', 1, $SETTINGS) === true
563
        && (int) $numDescendants === 0)
564
    {
565
        return array();
566
    }
567
568
    return array(
569
        'text' => $text,
570
        'title' => $title,
571
        'restricted' => 1,
572
        'folderClass' => 'folder_not_droppable',
573
        'show_but_block' => true,   // folder is visible but not accessible by user
574
        'parent' => $parent,
575
        'childrenNb' => $childrenNb,
576
        'itemsNb' => $itemsNb,
577
    );
578
}
579
580
/**
581
 * Get through complete tree
582
 *
583
 * @param int     $nodeId                            Id
584
 * @param array   $completTree                       Tree info
585
 * @param array   $tree                              The tree
586
 * @param array   $listFoldersLimitedKeys            Limited
587
 * @param array   $listRestrictedFoldersForItemsKeys Restricted
588
 * @param int     $last_visible_parent               Visible parent
589
 * @param int     $last_visible_parent_level         Parent level
590
 * @param array   $SETTINGS                          Teampass settings
591
 * @param string  $session_forbiden_pfs,
592
 * @param string  $session_groupes_visibles,
593
 * @param string  $session_list_restricted_folders_for_items,
594
 * @param int     $session_user_id,
595
 * @param string  $session_login,
596
 * @param string  $session_user_read_only,
597
 * @param array   $session_personal_folder,
598
 * @param string  $session_list_folders_limited,
599
 * @param string  $session_read_only_folders,
600
 * @param string  $session_personal_visible_groups
601
 * @param int     $can_create_root_folder
602
 * @param array   $ret_json                          Array
603
 *
604
 * @return array
605
 */
606
function recursiveTree(
607
    $nodeId,
608
    $completTree,
609
    $tree,
610
    $listFoldersLimitedKeys,
611
    $listRestrictedFoldersForItemsKeys,
612
    $last_visible_parent,
613
    $last_visible_parent_level,
614
    $SETTINGS,
615
    $session_forbiden_pfs,
616
    $session_groupes_visibles,
617
    $session_list_restricted_folders_for_items,
618
    $session_user_id,
619
    $session_login,
620
    $session_user_read_only,
621
    $session_personal_folder,
622
    $session_list_folders_limited,
623
    $session_read_only_folders,
624
    $session_personal_visible_groups,
625
    $can_create_root_folder,
626
    &$ret_json = array()
627
) {
628
    $text = '';
629
    $title = '';
630
    $show_but_block = false;
631
632
    // Load config
633
    if (file_exists('../includes/config/tp.config.php')) {
634
        include '../includes/config/tp.config.php';
635
    } elseif (file_exists('./includes/config/tp.config.php')) {
636
        include './includes/config/tp.config.php';
637
    } else {
638
        throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
639
    }
640
    
641
    // Be sure that user can only see folders he/she is allowed to
642
    if (
643
        in_array($completTree[$nodeId]->id, $session_forbiden_pfs) === false
644
        || in_array($completTree[$nodeId]->id, $session_groupes_visibles) === true
645
    ) {
646
        $displayThisNode = false;
647
        $nbChildrenItems = 0;
648
        $nodeDirectDescendants = $tree->getDescendants($completTree[$nodeId]->id, false, false, true);
649
650
        // Check if any allowed folder is part of the descendants of this node
651
        $nodeDescendants = $tree->getDescendants($completTree[$nodeId]->id, true, false, true);
652
        foreach ($nodeDescendants as $node) {
653
            // manage tree counters
654
            if (
655
                isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true
656
                && in_array(
657
                    $node,
658
                    array_merge(
659
                        $session_groupes_visibles,
660
                        is_null($session_list_restricted_folders_for_items) === true ? [] : $session_list_restricted_folders_for_items
661
                    )
662
                ) === true
663
            ) {
664
                DB::query(
665
                    'SELECT * FROM ' . prefixTable('items') . '
666
                    WHERE inactif=%i AND id_tree = %i',
667
                    0,
668
                    $node
669
                );
670
                $nbChildrenItems += DB::count();
671
            }
672
673
            if (
674
                in_array($node, $session_groupes_visibles) === true
675
            ) {
676
                // Final check - is PF allowed?
677
                $nodeDetails = $tree->getNode($node);
678
                if (
679
                    (int) $nodeDetails->personal_folder === 1
680
                    && (int) $SETTINGS['enable_pf_feature'] === 1
681
                    && in_array($node, $session_personal_folder) === false
682
                ) {
683
                    $displayThisNode = false;
684
                } else {
685
                    $displayThisNode = true;
686
                    // not adding a break in order to permit a correct count of items
687
                }
688
                $text = '';
689
            }
690
        }
691
        
692
        if ($displayThisNode === true) {
693
            handleNode(
694
                $nodeId,
695
                $completTree,
696
                $tree,
697
                $listFoldersLimitedKeys,
698
                $listRestrictedFoldersForItemsKeys,
699
                $last_visible_parent,
700
                $last_visible_parent_level,
701
                $SETTINGS,
702
                $session_forbiden_pfs,
703
                $session_groupes_visibles,
704
                $session_list_restricted_folders_for_items,
705
                $session_user_id,
706
                $session_login,
707
                $session_user_read_only,
708
                $session_personal_folder,
709
                $session_list_folders_limited,
710
                $session_read_only_folders,
711
                $session_personal_visible_groups,
712
                $text,
713
                $nbChildrenItems,
714
                $nodeDescendants,
715
                $nodeDirectDescendants,
716
                $can_create_root_folder,
717
                $ret_json
718
            );
719
        }
720
    }
721
    return $ret_json;
722
}
723
724
725
function handleNode(
726
    $nodeId,
727
    $completTree,
728
    $tree,
729
    $listFoldersLimitedKeys,
730
    $listRestrictedFoldersForItemsKeys,
731
    $last_visible_parent,
732
    $last_visible_parent_level,
733
    $SETTINGS,
734
    $session_forbiden_pfs,
735
    $session_groupes_visibles,
736
    $session_list_restricted_folders_for_items,
737
    $session_user_id,
738
    $session_login,
739
    $session_user_read_only,
740
    $session_personal_folder,
741
    $session_list_folders_limited,
742
    $session_read_only_folders,
743
    $session_personal_visible_groups,
744
    $text,
745
    $nbChildrenItems,
746
    $nodeDescendants,
747
    $nodeDirectDescendants,
748
    $can_create_root_folder, 
749
    &$ret_json = array()
750
)
751
{
752
    // get info about current folder
753
    DB::query(
754
        'SELECT * FROM ' . prefixTable('items') . '
755
        WHERE inactif=%i AND id_tree = %i',
756
        0,
757
        $completTree[$nodeId]->id
758
    );
759
    $itemsNb = DB::count();
760
761
    // If personal Folder, convert id into user name
762
    if ((int) $completTree[$nodeId]->title === (int) $session_user_id && (int) $completTree[$nodeId]->nlevel === 1) {
763
        $completTree[$nodeId]->title = $session_login;
764
    }
765
766
    // Decode if needed
767
    $completTree[$nodeId]->title = htmlspecialchars_decode($completTree[$nodeId]->title, ENT_QUOTES);
768
769
    $nodeData = prepareNodeData(
770
        $completTree,
771
        (int) $completTree[$nodeId]->id,
772
        $session_groupes_visibles,
773
        $session_read_only_folders,
774
        $session_personal_visible_groups,
775
        (int) $nbChildrenItems,
776
        $nodeDescendants,
777
        (int) $itemsNb,
778
        $session_list_folders_limited,
779
        (int) $SETTINGS['show_only_accessible_folders'],
780
        $nodeDirectDescendants,
781
        isset($SETTINGS['tree_counters']) === true ? (int) $SETTINGS['tree_counters'] : '',
782
        (int) $session_user_read_only,
783
        $listFoldersLimitedKeys,
784
        $listRestrictedFoldersForItemsKeys,
785
        $session_list_restricted_folders_for_items,
786
        $session_personal_folder
787
    );
788
789
    // prepare json return for current node
790
    $parent = $completTree[$nodeId]->parent_id === '0' ? '#' : 'li_' . $completTree[$nodeId]->parent_id;
791
792
    // handle displaying
793
    if (isKeyExistingAndEqual('show_only_accessible_folders', 1, $SETTINGS) === true) {
794
        if ($nodeData['hide_node'] === true) {
795
            $last_visible_parent = (int) $parent;
796
            $last_visible_parent_level = $completTree[$nodeId]->nlevel--;
797
        } elseif ($completTree[$nodeId]->nlevel < $last_visible_parent_level) {
798
            $last_visible_parent = -1;
799
        }
800
    }
801
802
    // json
803
    if ($nodeData['hide_node'] === false && $nodeData['show_but_block'] === false) {
804
        array_push(
805
            $ret_json,
806
            array(
807
                'id' => 'li_' . $completTree[$nodeId]->id,
808
                'parent' => $last_visible_parent === -1 ? $parent : $last_visible_parent,
809
                'text' => '<i class="'.$completTree[$nodeId]->fa_icon.' tree-folder mr-2" data-folder="'.$completTree[$nodeId]->fa_icon.'"  data-folder-selected="'.$completTree[$nodeId]->fa_icon_selected.'"></i>'.$text.$completTree[$nodeId]->title.$nodeData['html'],
810
                'li_attr' => array(
811
                    'class' => 'jstreeopen',
812
                    'title' => 'ID [' . $completTree[$nodeId]->id . '] ' . $nodeData['title'],
813
                ),
814
                'a_attr' => array(
815
                    'id' => 'fld_' . $completTree[$nodeId]->id,
816
                    'class' => $nodeData['folderClass'],
817
                    'onclick' => 'ListerItems(' . $completTree[$nodeId]->id . ', ' . $nodeData['restricted'] . ', 0, 1)',
818
                    'data-title' => $completTree[$nodeId]->title,
819
                ),
820
                'is_pf' => in_array($completTree[$nodeId]->id, $session_personal_folder) === true ? 1 : 0,
821
                'can_edit' => (int) $can_create_root_folder,
822
            )
823
        );
824
    } elseif ($nodeData['show_but_block'] === true) {
825
        array_push(
826
            $ret_json,
827
            array(
828
                'id' => 'li_' . $completTree[$nodeId]->id,
829
                'parent' => $last_visible_parent === -1 ? $parent : $last_visible_parent,
830
                'text' => '<i class="'.$completTree[$nodeId]->fa_icon.' tree-folder mr-2" data-folder="'.$completTree[$nodeId]->fa_icon.'"  data-folder-selected="'.$completTree[$nodeId]->fa_icon_selected.'"></i>'.'<i class="fas fa-times fa-xs text-danger mr-1 ml-1"></i>'.$text.$completTree[$nodeId]->title.$nodeData['html'],
831
                'li_attr' => array(
832
                    'class' => '',
833
                    'title' => 'ID [' . $completTree[$nodeId]->id . '] ' . langHdl('no_access'),
834
                ),
835
            )
836
        );
837
    }
838
    
839
    foreach ($completTree[$nodeId]->children as $child) {
840
        recursiveTree(
841
            $child,
842
            $completTree,
843
            /** @scrutinizer ignore-type */ $tree,
844
            $listFoldersLimitedKeys,
845
            $listRestrictedFoldersForItemsKeys,
846
            $last_visible_parent,
847
            $last_visible_parent_level,
848
            $SETTINGS,
849
            $session_forbiden_pfs,
850
            $session_groupes_visibles,
851
            $session_list_restricted_folders_for_items,
852
            $session_user_id,
853
            $session_login,
854
            $session_user_read_only,
855
            $session_personal_folder,
856
            $session_list_folders_limited,
857
            $session_read_only_folders,
858
            $session_personal_visible_groups,
859
            $can_create_root_folder,
860
            $ret_json
861
        );
862
    }
863
}
864
865
866
867
function prepareNodeData(
868
    $completTree,
869
    $nodeId,
870
    $session_groupes_visibles,
871
    $session_read_only_folders,
872
    $session_personal_visible_groups,
873
    $nbChildrenItems,
874
    $nodeDescendants,
875
    $itemsNb,
876
    $session_list_folders_limited,
877
    $show_only_accessible_folders,
878
    $nodeDirectDescendants,
879
    $tree_counters,
880
    $session_user_read_only,
881
    $listFoldersLimitedKeys,
882
    $listRestrictedFoldersForItemsKeys,
883
    $session_list_restricted_folders_for_items,
884
    $session_personal_folder
885
): array
886
{
887
    // special case for READ-ONLY folder
888
    $title = '';
889
    if (
890
        $session_user_read_only === true
891
        && in_array($completTree[$nodeId]->id, $session_user_read_only) === false
892
    ) {
893
        $title = langHdl('read_only_account');
894
    }
895
896
    if (in_array($nodeId, $session_groupes_visibles) === true) {
897
        if (in_array($nodeId, $session_read_only_folders) === true) {
898
            return [
899
                'html' => '<i class="far fa-eye fa-xs mr-1 ml-1"></i><span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . $itemsNb .
900
                    ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
901
                'title' => langHdl('read_only_account'),
902
                'restricted' => 1,
903
                'folderClass' => 'folder_not_droppable',
904
                'show_but_block' => false,
905
                'hide_node' => false,
906
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
907
            ];
908
909
        } elseif (
910
            $session_user_read_only === true
911
            && in_array($nodeId, $session_personal_visible_groups) === false
912
        ) {
913
            return [
914
                'html' => '<i class="far fa-eye fa-xs mr-1"></i><span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . $itemsNb .
915
                    ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
916
                'title' => $title,
917
                'restricted' => 0,
918
                'folderClass' => 'folder',
919
                'show_but_block' => false,
920
                'hide_node' => false,
921
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
922
            ];
923
        }
924
        
925
        return [
926
            'html' => '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . $itemsNb .
927
                ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
928
            'title' => $title,
929
            'restricted' => 0,
930
            'folderClass' => 'folder',
931
            'show_but_block' => false,
932
            'hide_node' => false,
933
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
934
        ];
935
936
    } elseif (in_array($nodeId, $listFoldersLimitedKeys) === true) {
937
        return [
938
            'html' => ($session_user_read_only === true ? '<i class="far fa-eye fa-xs mr-1"></i>' : '') .
939
                '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . count($session_list_folders_limited[$nodeId]) . '</span>',
940
            'title' => $title,
941
            'restricted' => 1,
942
            'folderClass' => 'folder',
943
            'show_but_block' => false,
944
            'hide_node' => false,
945
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
946
        ];
947
948
    } elseif (in_array($nodeId, $listRestrictedFoldersForItemsKeys) === true) {
949
        return [
950
            'html' => $session_user_read_only === true ? '<i class="far fa-eye fa-xs mr-1"></i>' : '' .
951
                '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . count($session_list_restricted_folders_for_items[$nodeId]) . '</span>',
952
            'title' => $title,
953
            'restricted' => 1,
954
            'folderClass' => 'folder',
955
            'show_but_block' => false,
956
            'hide_node' => false,
957
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
958
        ];
959
960
    } elseif ((int) $show_only_accessible_folders === 1
961
        && (int) $nbChildrenItems === 0
962
    ) {
963
        // folder should not be visible
964
        // only if it has no descendants
965
        if (
966
            count(
967
                array_diff(
968
                    $nodeDirectDescendants,
969
                    array_merge(
970
                        $session_groupes_visibles,
971
                        array_keys($session_list_restricted_folders_for_items)
972
                    )
973
                )
974
            ) !== count($nodeDirectDescendants)
975
        ) {
976
            // show it but block it
977
            return [
978
                'html' => '',
979
                'title' => $title,
980
                'restricted' => 1,
981
                'folderClass' => 'folder_not_droppable',
982
                'show_but_block' => true,
983
                'hide_node' => false,
984
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
985
            ];
986
        }
987
        
988
        // hide it
989
        return [
990
            'html' => '',
991
            'title' => $title,
992
            'restricted' => 1,
993
            'folderClass' => 'folder_not_droppable',
994
            'show_but_block' => false,
995
            'hide_node' => true,
996
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
997
        ];
998
    }
999
1000
    return [
1001
        'html' => '',
1002
        'title' => isset($title) === true ? $title : '',
1003
        'restricted' => 1,
1004
        'folderClass' => 'folder_not_droppable',
1005
        'show_but_block' => true,
1006
        'hide_node' => false,
1007
        'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
1008
    ];
1009
}
1010
1011
1012
/**
1013
 * Permits to check if we can user a cache instead of loading from DB
1014
 *
1015
 * @param integer $lastTreeChange
1016
 * @param integer $userTreeLastRefresh
1017
 * @param array $userSessionTreeStructure
1018
 * @param integer $userId
1019
 * @param integer $forceRefresh
1020
 * @param array $SETTINGS
1021
 * @return array
1022
 */
1023
function loadTreeStrategy(
1024
    int $lastTreeChange,
1025
    int $userTreeLastRefresh,
1026
    array $userSessionTreeStructure,
1027
    int $userId,
1028
    int $forceRefresh,
1029
    array $SETTINGS
0 ignored issues
show
Unused Code introduced by
The parameter $SETTINGS is not used and could be removed. ( Ignorable by Annotation )

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

1029
    /** @scrutinizer ignore-unused */ array $SETTINGS

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1030
): array
1031
{
1032
    // Case when refresh is EXPECTED / MANDATORY
1033
    if ((int) $forceRefresh === 1) {
1034
        return [
1035
            'state' => true,
1036
            'data' => [],
1037
        ];
1038
    }
1039
1040
    // Case when an update in the tree has been done
1041
    // Refresh is then mandatory
1042
    if ((int) $lastTreeChange > (int) $userTreeLastRefresh) {
1043
        return [
1044
            'state' => true,
1045
            'data' => [],
1046
        ];
1047
    }
1048
1049
    // Does this user has the tree structure in session?
1050
    // If yes then use it
1051
    if (is_null($userSessionTreeStructure) === false) {
0 ignored issues
show
introduced by
The condition is_null($userSessionTreeStructure) === false is always true.
Loading history...
1052
        return [
1053
            'state' => false,
1054
            'data' => json_encode($userSessionTreeStructure),
1055
        ];
1056
    }
1057
1058
    // Does this user has a tree cache
1059
    $userCacheTree = DB::queryfirstrow(
1060
        'SELECT data
1061
        FROM ' . prefixTable('cache_tree') . '
1062
        WHERE user_id = %i',
1063
        $userId
1064
    );
1065
    if (empty($userCacheTree['data']) === false) {
1066
        return [
1067
            'state' => false,
1068
            'data' => $userCacheTree['data'],
1069
        ];
1070
    }
1071
1072
    return [
1073
        'state' => true,
1074
        'data' => [],
1075
    ];
1076
}