Passed
Pull Request — master (#4794)
by Nils
06:30
created

createFolder()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 82
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 49
c 1
b 0
f 0
nc 6
nop 5
dl 0
loc 82
rs 8.8016

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 file is part of the TeamPass project.
9
 *
10
 * TeamPass is free software: you can redistribute it and/or modify it
11
 * under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, version 3 of the License.
13
 *
14
 * TeamPass is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21
 *
22
 * Certain components of this file may be under different licenses. For
23
 * details, see the `licenses` directory or individual file headers.
24
 * ---
25
 * @file      import.queries.php
26
 * @author    Nils Laumaillé ([email protected])
27
 * @copyright 2009-2025 Teampass.net
28
 * @license   GPL-3.0
29
 * @see       https://www.teampass.net
30
 */
31
32
33
use Goodby\CSV\Import\Standard\Lexer;
34
use Goodby\CSV\Import\Standard\Interpreter;
35
use Goodby\CSV\Import\Standard\LexerConfig;
36
use voku\helper\AntiXSS;
37
use TeampassClasses\NestedTree\NestedTree;
38
use TeampassClasses\SessionManager\SessionManager;
39
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
40
use TeampassClasses\Language\Language;
41
use TeampassClasses\PerformChecks\PerformChecks;
42
use TeampassClasses\ConfigManager\ConfigManager;
43
44
// Load functions
45
require_once 'main.functions.php';
46
47
// init
48
loadClasses('DB');
49
$session = SessionManager::getSession();
50
$request = SymfonyRequest::createFromGlobals();
51
$lang = new Language($session->get('user-language') ?? 'english');
52
$antiXss = new AntiXSS();
53
54
// Load config
55
$configManager = new ConfigManager();
56
$SETTINGS = $configManager->getAllSettings();
57
58
// Do checks
59
// Instantiate the class with posted data
60
$checkUserAccess = new PerformChecks(
61
    dataSanitizer(
62
        [
63
            'type' => htmlspecialchars($request->request->get('type', ''), ENT_QUOTES, 'UTF-8'),
64
        ],
65
        [
66
            'type' => 'trim|escape',
67
        ],
68
    ),
69
    [
70
        'user_id' => returnIfSet($session->get('user-id'), null),
71
        'user_key' => returnIfSet($session->get('key'), null),
72
    ]
73
);
74
// Handle the case
75
echo $checkUserAccess->caseHandler();
76
if (
77
    $checkUserAccess->userAccessPage('import') === false ||
78
    $checkUserAccess->checkSession() === false
79
) {
80
    // Not allowed page
81
    $session->set('system-error_code', ERR_NOT_ALLOWED);
82
    include $SETTINGS['cpassman_dir'] . '/error.php';
83
    exit;
84
}
85
86
// Define Timezone
87
date_default_timezone_set($SETTINGS['timezone'] ?? 'UTC');
88
89
// Set header properties
90
header('Content-type: text/html; charset=utf-8');
91
header('Cache-Control: no-cache, no-store, must-revalidate');
92
error_reporting(E_ERROR);
93
set_time_limit(0);
94
95
// --------------------------------- //
96
97
// Set some constants for program readability
98
define('KP_PATH', 0);
99
define('KP_GROUP', 1);
100
define('KP_TITLE', 2);
101
define('KP_PASSWORD', 3);
102
define('KP_USERNAME', 4);
103
define('KP_URL', 5);
104
define('KP_UUID', 6);
105
define('KP_NOTES', 7);
106
107
108
// Prepare POST variables
109
$data = [
110
    'type' => $request->request->filter('type', '', FILTER_SANITIZE_SPECIAL_CHARS),
111
    'data' => $request->request->filter('data', '', FILTER_SANITIZE_SPECIAL_CHARS),
112
    'key' => $request->request->filter('key', '', FILTER_SANITIZE_SPECIAL_CHARS),
113
    'file' => $request->request->filter('file', '', FILTER_SANITIZE_SPECIAL_CHARS),
114
];
115
116
$filters = [
117
    'type' => 'trim|escape',
118
    'data' => 'trim|escape',
119
    'key' => 'trim|escape',
120
    'file' => 'cast:integer',
121
];
122
123
$inputData = dataSanitizer(
124
    $data,
125
    $filters
126
);
127
128
129
$tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
130
131
// Build query
132
switch ($inputData['type']) {
133
    //Check if import CSV file format is what expected
134
    case 'import_file_format_csv':
135
        // Check KEY and rights
136
        if ($inputData['key'] !== $session->get('key')) {
137
            echo prepareExchangedData(
138
                array(
139
                    'error' => true,
140
                    'message' => $lang->get('key_is_not_correct'),
141
                ),
142
                'encode'
143
            );
144
            break;
145
        }
146
147
        //load full tree
148
        $tree->rebuild();
149
        $tree = $tree->getDescendants();
150
151
        // Init post variable
152
        $post_operation_id = $inputData['file'];
153
154
        // Get filename from database
155
        $data = DB::queryFirstRow(
156
            'SELECT valeur
157
            FROM '.prefixTable('misc').'
158
            WHERE increment_id = %i AND type = "temp_file"',
159
            $post_operation_id
160
        );
161
162
        // Delete operation id
163
        DB::delete(
164
            prefixTable('misc'),
165
            "increment_id = %i AND type = 'temp_file'",
166
            $post_operation_id
167
        );
168
169
        // Initialisation
170
        $file = $SETTINGS['path_to_files_folder'] . '/' . $data['valeur'];
171
        $importation_possible = true;
172
        $valuesToImport = [];
173
        $items_number = 0;
174
        $batchInsert = [];
175
        $uniqueFolders = [];
176
        $comment = '';
177
178
        // Vérifier si le fichier est accessible
179
        if (!file_exists($file) || !is_readable($file)) {
180
            echo prepareExchangedData(
181
                array('error' => true, 'message' => $lang->get('cannot_open_file')),
182
                'encode'
183
            );
184
            unlink($file);
185
            break;
186
        }
187
188
        // Ouvrir le fichier pour récupérer l'en-tête
189
        $fp = fopen($file, 'r');
190
        $header = fgetcsv($fp);
191
        fclose($fp);
192
193
        // Vérifier si l'en-tête est valide
194
        if ($header === false || empty($header)) {
195
            echo prepareExchangedData(
196
                array('error' => true, 'message' => $lang->get('import_error_no_read_possible')),
197
                'encode'
198
            );
199
            unlink($file);
200
            break;
201
        }
202
203
        // Initialize the array to store values to import
204
        $valuesToImport = [];
205
206
        // Configuration du parser CSV
207
        $config = new LexerConfig();
208
        $lexer = new Lexer($config);
209
        $config->setIgnoreHeaderLine(true);
210
211
        /**
212
         * Get the list of available encodings.
213
         *
214
         * @return array List of available encodings.
215
         */
216
        function getAvailableEncodings(): array
217
        {
218
            // List of encodings we want to support (in order of priority)
219
            $desiredEncodings = [
220
                'UTF-8',
221
                'UTF-16',
222
                'UTF-16LE',
223
                'UTF-16BE',
224
                'ISO-8859-1',
225
                'ISO-8859-15',
226
                'Windows-1252',
227
                'Windows-1251',  // Cyrillique
228
                'CP1251',        // Cyrillique alternatif
229
                'KOI8-R',        // Cyrillique russe
230
                'Shift_JIS',     // Japonais
231
                'EUC-JP',        // Japonais
232
                'ISO-2022-JP',   // Japonais
233
                'TIS-620',       // Thaï
234
                'Windows-874',   // Thaï Windows
235
                'Big5',          // Chinois traditionnel
236
                'GB2312',        // Chinois simplifié
237
                'GBK',           // Chinois simplifié étendu
238
                'EUC-KR',        // Coréen
239
                'ISO-8859-2',    // Europe centrale
240
                'ISO-8859-5',    // Cyrillique ISO
241
                'ISO-8859-7',    // Grec
242
                'Windows-1250',  // Europe centrale
243
                'Windows-1253',  // Grec
244
                'Windows-1254',  // Turc
245
                'Windows-1255',  // Hébreu
246
                'Windows-1256',  // Arabe
247
            ];
248
249
            // Get the list of encodings supported by the system
250
            $systemEncodings = mb_list_encodings();
251
252
            // Filter to keep only those that are available
253
            $availableEncodings = [];
254
            foreach ($desiredEncodings as $encoding) {
255
                if (in_array($encoding, $systemEncodings)) {
256
                    $availableEncodings[] = $encoding;
257
                }
258
            }
259
260
            // Ensure UTF-8 is always present
261
            if (!in_array('UTF-8', $availableEncodings)) {
262
                array_unshift($availableEncodings, 'UTF-8');
263
            }
264
265
            return $availableEncodings;
266
        }
267
268
        /**
269
         * Detects the encoding of a file using available encodings.
270
         * @param string $filepath The path to the file to be checked.
271
         * @return string The detected encoding or 'UTF-8' if detection fails.
272
         */
273
        function detectFileEncoding($filepath): string
274
        {
275
            $content = file_get_contents($filepath);
276
            $availableEncodings = getAvailableEncodings();
277
278
            $detected = mb_detect_encoding($content, $availableEncodings, true);
279
            return $detected ?: 'UTF-8';
280
        }
281
282
        // Detect file encoding and set it in the config
283
        $detectedEncoding = detectFileEncoding($file);
284
        $config->setFromCharset($detectedEncoding);
285
        $config->setToCharset('UTF-8');
286
287
        // Get the data and ensure columns are correctly mapped
288
        $interpreter = new Interpreter();
289
        $interpreter->addObserver(function (array $row) use (&$valuesToImport, $header) {
290
            $rowData = array_combine($header, $row);
291
292
            if ($rowData !== false) {
293
                $valuesToImport[] = array(
294
                    'Label' => isset($rowData['label']) ? trim($rowData['label']) : '',
295
                    'Login' => isset($rowData['login']) ? trim($rowData['login']) : '',
296
                    'Password' => isset($rowData['password']) ? trim($rowData['password']) : '',
297
                    'url' => isset($rowData['url']) ? trim($rowData['url']) : '',
298
                    'Comments' => isset($rowData['description']) ? trim($rowData['description']) : '',
299
                    'Folder' => isset($rowData['folder']) ? trim($rowData['folder']) : '',
300
                );
301
            }
302
        });
303
304
        // Launch parsing with `Lexer`
305
        $lexer->parse($file, $interpreter);
306
307
        // Check if some date were imported
308
        if (empty($valuesToImport)) {
309
            echo prepareExchangedData(
310
                array('error' => true, 'message' => $lang->get('import_error_no_read_possible')),
311
                'encode'
312
            );
313
            unlink($file);
314
            break;
315
        }
316
317
        // Process lines
318
        $continue_on_next_line = false;
319
        $comment = "";
320
        foreach ($valuesToImport as $row) {
321
            // Check that each line has 6 columns
322
            if (count($row) !== 6) {
323
                echo prepareExchangedData(
324
                    array('error' => true, 'message' => $lang->get('import_error_invalid_structure')),
325
                    'encode'
326
                );
327
                unlink($file);
328
                break;
329
            }
330
331
            // CLean data
332
            $label    = cleanInput($row['Label']);
333
            $login    = cleanInput($row['Login']);
334
            $pwd      = cleanInput($row['Password']);
335
            $url      = cleanInput($row['url']);
336
            $folder   = cleanInput($row['Folder']);
337
            $comments = cleanInput($row['Comments']);
338
339
            // Handle multiple lignes description
340
            if (strpos($comments, '<br>') !== false || strpos($label, '<br>') !== false) {
341
                $continue_on_next_line = true;
342
                $comment .= " " . $label . " " . $comments;
343
            } else {
344
                // Insert previous line if changing line
345
                if (!empty($label)) {
346
                    $items_number++;
347
348
                    // Insert in batch
349
                    $batchInsert[] = array(
350
                        'label'        => $label,
351
                        'description'  => $comment . $comments,
352
                        'pwd'          => $pwd,
353
                        'url'          => $url,
354
                        'folder'       => ((int) $session->get('user-admin') === 1 || (int) $session->get('user-manager') === 1 || (int) $session->get('user-can_manage_all_users') === 1) ? $folder : '',
355
                        'login'        => $login,
356
                        'operation_id' => $post_operation_id,
357
                    );
358
359
                    // Store unique folders
360
                    // Each folder is the unique element of the path located inside $folder and delimited by '/' or '\'
361
                    $folders = preg_split('/[\/\\\\]/', $folder);
362
                    foreach ($folders as $folder) {
363
                        if (!empty($folder)) {
364
                            $uniqueFolders[$folder] = $folder;
365
                        }
366
                    }
367
                    $label = '';
368
                }
369
                // Update current variables
370
                $comment = '';
371
                $continue_on_next_line = false;
372
            }
373
        }
374
375
        // Insert last line
376
        if (!empty($label)) {
377
            $items_number++;
378
379
            // Insert in batch
380
            $batchInsert[] = array(
381
                'label'        => $label,
382
                'description'  => $comment . $comments,
383
                'pwd'          => $pwd,
384
                'url'          => $url,
385
                'folder'       => ((int) $session->get('user-admin') === 1 || (int) $session->get('user-manager') === 1 || (int) $session->get('user-can_manage_all_users') === 1) ? $folder : '',
386
                'login'        => $login,
387
                'operation_id' => $post_operation_id,
388
            );
389
390
            // Store unique folders
391
            // Each folder is the unique element of the path located inside $folder and delimited by '/' or '\'
392
            $folders = preg_split('/[\/\\\\]/', $folder);
393
            foreach ($folders as $folder) {
394
                if (!empty($folder)) {
395
                    $uniqueFolders[$folder] = $folder;
396
                }
397
            }
398
        }
399
400
        // Insert in database (with batch optimisation)
401
        if (!empty($batchInsert)) {
402
            $tableName = prefixTable('items_importations');
403
            $values = [];
404
405
            foreach ($batchInsert as $data) {
406
                $values[] = "('" . implode("','", array_map('addslashes', $data)) . "')";
407
            }
408
409
            $sql = "INSERT INTO `$tableName` (`label`, `description`, `pwd`, `url`, `folder`, `login`, `operation_id`) VALUES " . implode(',', $values);
410
411
            DB::query($sql);
412
        }
413
414
        // Display results
415
        echo prepareExchangedData(
416
            array('error' => false,
417
                'operation_id' => $post_operation_id,
418
                'items_number' => $items_number,
419
                'folders_number' => count($uniqueFolders),
420
                'userCanManageFolders' => ((int) $session->get('user-admin') === 1 || (int) $session->get('user-manager') === 1 || (int) $session->get('user-can_manage_all_users') === 1) ? 1 : 0
421
            ),
422
            'encode'
423
        );
424
425
        // Delete file after processing
426
        unlink($file);
427
        break;
428
429
    // Create new folders
430
    case 'import_csv_folders':
431
        // Check KEY and rights
432
        if ($inputData['key'] !== $session->get('key')) {
433
            echo prepareExchangedData(
434
                array(
435
                    'error' => true,
436
                    'message' => $lang->get('key_is_not_correct'),
437
                ),
438
                'encode'
439
            );
440
            break;
441
        }
442
443
        // Check if user is manager at least.
444
        if ((int) $session->get('user-admin') === 0 && (int) $session->get('user-manager') === 0 && (int) $session->get('user-can_manage_all_users') === 0) {
445
            echo prepareExchangedData(
446
                array(
447
                    'error' => true,
448
                    'message' => $lang->get('import_error_no_rights'),
449
                ),
450
                'encode'
451
            );
452
            break;
453
        }
454
455
        // Decrypt and retreive data in JSON format
456
        $dataReceived = prepareExchangedData(
457
            $inputData['data'],
458
            'decode'
459
        );
460
461
        // Is this a personal folder?
462
        $personalFolder = in_array($dataReceived['folderId'], $session->get('user-personal_folders')) ? 1 : 0;
463
464
        // Get all folders from objects in DB
465
        $itemsPath = DB::query(
466
            'SELECT folder, increment_id
467
            FROM '.prefixTable('items_importations').'
468
            WHERE operation_id = %i
469
            LIMIT %i, %i',
470
            $dataReceived['csvOperationId'],
471
            $dataReceived['offset'],
472
            $dataReceived['limit']
473
        );
474
475
476
        // Save matches "path -> ID" to prevent against multiple insertions
477
        $folderIdMap = $dataReceived['folderIdMap'] ?? [];
478
479
        require_once 'folders.class.php';
480
        $folderManager = new FolderManager($lang);
481
482
        // Get all folders from objects in DB
483
        foreach ($itemsPath as $item) {
484
            $path = $item['folder'];
485
            $importId = $item['increment_id']; // Entry ID in items_importations
486
487
            $parts = explode("\\", $path); // Décomposer le chemin en sous-dossiers
488
            $currentPath = "";
489
            $parentId = $dataReceived['folderId']; // Strating with provided folder
490
491
            foreach ($parts as $part) {
492
                $currentPath = trim($currentPath . "/" . $part, "/");
493
                $currentFolder = $part;
494
495
                // Check if this folder has already been created
496
                if (isset($folderIdMap[$currentPath]) || empty($currentFolder)) {
497
                    $parentId = $folderIdMap[$currentPath];
498
                    continue; // Jump to next iteration
499
                }
500
501
                // Vérifier si le dossier existe déjà en base
502
                $existingId = DB::queryFirstField(
503
                    'SELECT id FROM '.prefixTable('nested_tree').' WHERE title = %s AND parent_id = %i',
504
                    $currentFolder, // Searching only by name
505
                    $parentId // Ensure we search the correct parent
506
                );
507
508
                if ($existingId) {
509
                    $folderIdMap[$currentPath] = $existingId;
510
                    $parentId = $existingId;
511
                } else {
512
                    // Insert folder and get its ID
513
                    $params = [
514
                        'title' => (string) $currentFolder,
515
                        'parent_id' => isset($parentId) && $parentId !== null ? (int) $parentId : 0,
516
                        'personal_folder' => (int) $personalFolder,
517
                        'complexity' => $dataReceived['folderPasswordComplexity'] ?? 0,
518
                        'duration' => 0,
519
                        'access_rights' => $dataReceived['folderAccessRight'] ?? '',
520
                        'user_is_admin' => (int) $session->get('user-admin'),
521
                        'user_accessible_folders' => (array) $session->get('user-accessible_folders'),
522
                        'user_is_manager' => (int) $session->get('user-manager'),
523
                        'user_can_create_root_folder' => (int) $session->get('user-can_create_root_folder'),
524
                        'user_can_manage_all_users' => (int) $session->get('user-can_manage_all_users'),
525
                        'user_id' => (int) $session->get('user-id'),
526
                        'user_roles' => (string) $session->get('user-roles')
527
                    ];
528
                    $options = [
529
                        'rebuildFolderTree' => false,
530
                        'setFolderCategories' => false,
531
                        'manageFolderPermissions' => true,
532
                        'copyCustomFieldsCategories' => false,
533
                        'refreshCacheForUsersWithSimilarRoles' => true,
534
                    ];
535
                    $creationStatus = $folderManager->createNewFolder($params, $options);
536
                    $folderCreationDone = $creationStatus['error'];
537
538
                    if ((int) $folderCreationDone === 0) {
539
                        $newFolderId = $creationStatus['newId'];
540
                        // User created the folder
541
                        // Add new ID to list of visible ones
542
                        if ((int) $session->get('user-admin') === 0 && $creationStatus['error'] === false && $newFolderId !== 0) {
543
                            SessionManager::addRemoveFromSessionArray('user-accessible_folders', [$newFolderId], 'add');
544
                        }
545
546
                        // Save ID in map to avoid recreating it
547
                        $folderIdMap[$currentPath] = $newFolderId;
548
                        $parentId = $newFolderId;
549
                    } else {
550
                        // Get ID of existing folder
551
                        $ret = DB::queryFirstRow(
552
                            'SELECT *
553
                            FROM ' . prefixTable('nested_tree') . '
554
                            WHERE title = %s',
555
                            $currentFolder
556
                        );
557
                        $newFolderId = $ret['id'];
558
                        $parentId = $newFolderId;
559
                    }
560
                }
561
            }
562
563
            // Update the importation entry with the new folder ID
564
            DB::update(prefixTable('items_importations'), [
565
                'folder_id' => $parentId
566
            ], "increment_id=%i", $importId);
567
        }
568
569
        echo prepareExchangedData(
570
            array(
571
                'error' => false,
572
                'message' => '',
573
                'processedCount' => count($itemsPath),
574
                'folderIdMap' => $folderIdMap,
575
            ),
576
            'encode'
577
        );
578
579
        break;
580
581
582
    //Insert into DB the items the user has selected
583
    case 'import_csv_items':
584
        // Check KEY and rights
585
        if ($inputData['key'] !== $session->get('key')) {
586
            echo prepareExchangedData(
587
                array(
588
                    'error' => true,
589
                    'message' => $lang->get('key_is_not_correct'),
590
                ),
591
                'encode'
592
            );
593
            break;
594
        }
595
596
597
        // Decrypt and retreive data in JSON format
598
        $dataReceived = prepareExchangedData(
599
            $inputData['data'],
600
            'decode'
601
        );
602
603
        //Get some info about personal folder
604
        $personalFolder = in_array($dataReceived['folderId'], $session->get('user-personal_folders')) ? 1 : 0;
605
606
        // Prepare some variables
607
        $targetFolderId = $dataReceived['folderId'];
608
        $targetFolderName = DB::queryFirstField(
609
            'SELECT title
610
            FROM '.prefixTable('nested_tree').'
611
            WHERE id = %i',
612
            $targetFolderId
613
        );
614
        $personalFolder = in_array($dataReceived['folderId'], $session->get('user-personal_folders')) ? 1 : 0;
615
616
        // Prepare some variables
617
        $targetFolderId = $dataReceived['folderId'];
618
        $targetFolderName = DB::queryFirstField(
619
            'SELECT title
620
            FROM '.prefixTable('nested_tree').'
621
            WHERE id = %i',
622
            $targetFolderId
623
        );
624
625
        // Get all folders from objects in DB
626
        if ($dataReceived['foldersNumber'] > 0) {
627
            $items = DB::query(
628
                'SELECT ii.label, ii.login, ii.pwd, ii.url, ii.description, ii.folder_id, ii.increment_id, nt.title
629
                FROM '.prefixTable('items_importations').' AS ii
630
                INNER JOIN '.prefixTable('nested_tree').' AS nt ON ii.folder_id = nt.id
631
                WHERE ii.operation_id = %i
632
                LIMIT %i, %i',
633
                $dataReceived['csvOperationId'],
634
                $dataReceived['offset'],
635
                $dataReceived['limit']
636
            );
637
        } else {
638
            $items = DB::query(
639
                'SELECT ii.label, ii.login, ii.pwd, ii.url, ii.description, ii.folder_id, ii.increment_id
640
                FROM '.prefixTable('items_importations').' AS ii
641
                WHERE ii.operation_id = %i
642
                LIMIT %i, %i',
643
                $dataReceived['csvOperationId'],
644
                $dataReceived['offset'],
645
                $dataReceived['limit']
646
            );
647
        }
648
649
        // Init some variables
650
        $insertedItems = $dataReceived['insertedItems'] ?? 0;
651
        $failedItems = [];
652
653
        // Loop on items
654
        foreach ($items as $item) {
655
            try {
656
                // Handle case where password is empty
657
                if (($session->has('user-create_item_without_password') &&
658
                    null !== $session->get('user-create_item_without_password') &&
659
                    (int) $session->get('user-create_item_without_password') !== 1) ||
660
                    !empty($item['pwd'])) {
661
                    // Encrypt password
662
                    $cryptedStuff = doDataEncryption($item['pwd']);
663
                } else {
664
                    $cryptedStuff['encrypted'] = '';
665
                    $cryptedStuff['objectKey'] = '';
666
                }
667
                $itemPassword = $cryptedStuff['encrypted'];
668
669
                // Insert new item in table ITEMS
670
                DB::insert(
671
                    prefixTable('items'),
672
                    array(
673
                        'label' => substr($item['label'], 0, 500),
674
                        'description' => empty($item['description']) === true ? '' : $item['description'],
675
                        'pw' => $itemPassword,
676
                        'pw_iv' => '',
677
                        'url' => empty($item['url']) === true ? '' : substr($item['url'], 0, 500),
678
                        'id_tree' => is_null($item['folder_id']) === true ? $targetFolderId : (int) $item['folder_id'],
679
                        'login' => empty($item['login']) === true ? '' : substr($item['login'], 0, 200),
680
                        'anyone_can_modify' => $dataReceived['editAll'],
681
                        'encryption_type' => 'teampass_aes',
682
                        'item_key' => uniqidReal(50),
683
                        'created_at' => time(),
684
                    )
685
                );
686
                $newId = DB::insertId();
687
688
                error_log('New item created with ID: ' . $newId);
689
690
                // Create new task for the new item
691
                // If it is not a personnal one
692
                if ((int) $personalFolder === 0) {
693
                    if ($dataReceived['keysGenerationWithTasksHandler'] === 'tasksHandler') {
694
                        // Create task for the new item
695
                        storeTask(
696
                            'new_item',
697
                            $session->get('user-id'),
698
                            0,
699
                            (int) $item['folder_id'],
700
                            (int) $newId,
701
                            $cryptedStuff['objectKey'],
702
                        );
703
                    } else {
704
                        // Create sharekeys for current user
705
                        storeUsersShareKey(
706
                            prefixTable('sharekeys_items'),
707
                            (int) $item['folder_id'],
708
                            (int) $newId,
709
                            $cryptedStuff['objectKey'],
710
                            false
711
                        );
712
                    }
713
                } else {
714
                    // Create sharekeys for current user
715
                    storeUsersShareKey(
716
                        prefixTable('sharekeys_items'),
717
                        (int) $personalFolder,
718
                        (int) $newId,
719
                        $cryptedStuff['objectKey'],
720
                        true
721
                    );
722
                }
723
724
                //if asked, anyone in role can modify
725
                if ((int) $dataReceived['editRole'] === 1) {
726
                    foreach ($session->get('system-array_roles') as $role) {
727
                        DB::insert(
728
                            prefixTable('restriction_to_roles'),
729
                            array(
730
                                'role_id' => $role['id'],
731
                                'item_id' => $newId,
732
                            )
733
                        );
734
                    }
735
                }
736
737
                // Insert new item in table LOGS_ITEMS
738
                DB::insert(
739
                    prefixTable('log_items'),
740
                    array(
741
                        'id_item' => $newId,
742
                        'date' => time(),
743
                        'id_user' => $session->get('user-id'),
744
                        'action' => 'at_creation',
745
                    )
746
                );
747
748
                // Add item to cache table
749
                updateCacheTable('add_value', (int) $newId);
750
751
                // Update items_importation table
752
                DB::update(
753
                    prefixTable('items_importations'),
754
                    array(
755
                        'increment_id' => $newId,
756
                        'imported_at'=> time(),
757
                    ),
758
                    "increment_id=%i",
759
                    $item['increment_id']
760
                );
761
762
                $insertedItems++;
763
764
            } catch (Exception $e) {
765
                // Log the error and store the failed item
766
                $failedItems[] = [
767
                    'increment_id' => $item['increment_id'],
768
                    'error' => $e->getMessage(),
769
                ];
770
            }
771
        }
772
773
        echo prepareExchangedData(
774
            array(
775
                'error' => false,
776
                'message' => '',
777
                'insertedItems' => $insertedItems,
778
                'failedItems' => $failedItems,
779
            ),
780
            'encode'
781
        );
782
        break;
783
784
    case 'import_csv_items_finalization':
785
        // Check KEY and rights
786
        if ($inputData['key'] !== $session->get('key')) {
787
            echo prepareExchangedData(
788
                array(
789
                    'error' => true,
790
                    'message' => $lang->get('key_is_not_correct'),
791
                ),
792
                'encode'
793
            );
794
            break;
795
        }
796
797
        // Decrypt and retreive data in JSON format
798
        $receivedParameters = prepareExchangedData(
799
            $inputData['data'],
800
            'decode'
801
        );
802
        $csvOperationId = filter_var($receivedParameters['csvOperationId'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
803
804
        // Delete operation id
805
        DB::delete(
806
            prefixTable('items_importations'),
807
            'operation_id = %i',
808
            $csvOperationId
809
        );
810
811
        echo prepareExchangedData(
812
            array(
813
                'error' => false,
814
                'message' => '',
815
            ),
816
            'encode'
817
        );
818
        break;
819
820
821
    //Check if import KEEPASS file format is what expected
822
    case 'import_file_format_keepass':
823
        // Check KEY and rights
824
        if ($inputData['key'] !== $session->get('key')) {
825
            echo prepareExchangedData(
826
                array(
827
                    'error' => true,
828
                    'message' => $lang->get('key_is_not_correct'),
829
                ),
830
                'encode'
831
            );
832
            break;
833
        }
834
835
        // Decrypt and retreive data in JSON format
836
        $receivedParameters = prepareExchangedData(
837
            $inputData['data'],
838
            'decode'
839
        );
840
        $post_operation_id = filter_var($receivedParameters['file'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
841
        $destinationFolderId = filter_var($receivedParameters['folder_id'], FILTER_SANITIZE_NUMBER_INT);
842
843
        // Get filename from database
844
        $data = DB::queryFirstRow(
845
            'SELECT valeur
846
            FROM '.prefixTable('misc').'
847
            WHERE increment_id = %i AND type = "temp_file"',
848
            $post_operation_id
849
        );
850
851
        // Delete operation id
852
        DB::delete(
853
            prefixTable('misc'),
854
            'increment_id = %i AND type = "temp_file"',
855
            $post_operation_id
856
        );
857
858
        // do some initializations
859
        $file = $data['valeur'];
860
861
        //read xml file
862
        if (file_exists($SETTINGS['path_to_files_folder'].'/'.$file)) {
863
            $xml = simplexml_load_file(
864
                $SETTINGS['path_to_files_folder'].'/'.$file
865
            );
866
        }
867
868
        // Convert XML to associative array
869
        $xmlfile = file_get_contents($SETTINGS['path_to_files_folder'].'/'.$file);
870
        $new = simplexml_load_string($xmlfile);
871
        $con = json_encode($new);
872
        $newArr = json_decode($con, true);
873
874
875
        /**
876
         * Recursive function to process the Keepass XML structure.
877
         *
878
         * @param array $array The current array to process.
879
         * @param string $previousFolder The parent folder ID.
880
         * @param array $newItemsToAdd The new items to add to the database.
881
         * @param int $level The current level of the recursion.
882
         *
883
         * @return array The new items to add to the database.
884
         */
885
        function recursive($array, $previousFolder, $newItemsToAdd, $level) : array
886
        {
887
            // Handle entries (items)
888
            if (isset($array['Entry']) && is_array($array['Entry'])) {
889
                $newItemsToAdd = handleEntries($array['Entry'], $previousFolder, $newItemsToAdd);
890
            }
891
892
            // Handle groups (folders)
893
            if (isset($array['Group']) && is_array($array['Group'])) {
894
                $newItemsToAdd = handleGroups($array['Group'], $previousFolder, $newItemsToAdd, $level);
895
            }
896
897
            return $newItemsToAdd;
898
        }
899
900
        /**
901
         * Handle entries (items) within the structure.
902
         * It processes each entry and adds it to the new items list.
903
         *
904
         * @param array $entries The entries to process.
905
         * @param string $previousFolder The parent folder ID.
906
         * @param array $newItemsToAdd The new items to add to the database.
907
         *
908
         * @return array The new items to add to the database.
909
         */
910
        function handleEntries(array $entries, string $previousFolder, array $newItemsToAdd) : array
911
        {
912
            foreach ($entries as $key => $value) {
913
                // Check if the entry has a 'String' field and process it
914
                if (isset($value['String'])) {
915
                    $newItemsToAdd['items'][] = buildItemDefinition($value['String'], $previousFolder);
916
                }
917
                // If it's a direct 'String' item, build a simple item
918
                elseif ($key === 'String') {
919
                    $newItemsToAdd['items'][] = buildSimpleItem($value, $previousFolder);
920
                }
921
            }
922
923
            return $newItemsToAdd;
924
        }
925
926
        /**
927
         * Build an item definition from the 'String' fields.
928
         * Converts the key-value pairs into a usable item format.
929
         *
930
         * @param array $strings The 'String' fields to process.
931
         * @param string $previousFolder The parent folder ID.
932
         *
933
         * @return array The item definition.
934
         */
935
        function buildItemDefinition(array $strings, string $previousFolder) : array
936
        {
937
            $itemDefinition = [];
938
            // Loop through each 'String' entry and map keys and values
939
            foreach ($strings as $entry) {
940
                $itemDefinition[$entry['Key']] = is_array($entry['Value']) ? '' : $entry['Value'];
941
            }
942
943
            // Set the parent folder and ensure default values for certain fields
944
            $itemDefinition['parentFolderId'] = $previousFolder;
945
            $itemDefinition['Notes'] = $itemDefinition['Notes'] ?? '';
946
            $itemDefinition['URL'] = $itemDefinition['URL'] ?? '';
947
            $itemDefinition['Password'] = $itemDefinition['Password'] ?? '';
948
949
            return $itemDefinition;
950
        }
951
952
        /**
953
         * Build a simple item with predefined fields.
954
         * This is used when there is no associated key, just ordered values.
955
         *
956
         * @param array $value The ordered values to process.
957
         * @param string $previousFolder The parent folder ID.
958
         *
959
         * @return array The simple item definition.
960
         */
961
        function buildSimpleItem(array $value, string $previousFolder) : array
962
        {
963
            return [
964
                'Notes' => is_array($value[0]['Value']) ? '' : $value[0]['Value'],
965
                'Title' => is_array($value[2]['Value']) ? '' : $value[2]['Value'],
966
                'Password' => is_array($value[1]['Value']) ? '' : $value[1]['Value'],
967
                'URL' => is_array($value[3]['Value']) ? '' : $value[3]['Value'],
968
                'UserName' => is_array($value[4]['Value']) ? '' : $value[4]['Value'],
969
                'parentFolderId' => $previousFolder,
970
            ];
971
        }
972
973
        /**
974
         * Handle groups (folders) within the structure.
975
         * It processes each group and recursively goes deeper into subgroups and subentries.
976
         *
977
         * @param array $groups The groups to process.
978
         * @param string $previousFolder The parent folder ID.
979
         * @param array $newItemsToAdd The new items to add to the database.
980
         *
981
         * @return array The new items to add to the database.
982
         */
983
        function handleGroups($groups, string $previousFolder, array $newItemsToAdd, int $level) : array
984
        {
985
            // If a single group is found, wrap it into an array
986
            if (isset($groups['UUID'])) {
987
                $groups = [$groups];
988
            }
989
990
            foreach ($groups as $group) {
991
                // Add the current group (folder) to the list
992
                $newItemsToAdd['folders'][] = [
993
                    'folderName' => $group['Name'],
994
                    'uuid' => $group['UUID'],
995
                    'parentFolderId' => $previousFolder,
996
                    'level' => $level,
997
                ];
998
999
                // Recursively process entries and subgroups inside this group
1000
                $newItemsToAdd = recursive(
1001
                    [
1002
                        'Entry' => $group['Entry'] ?? '',
1003
                        'Group' => $group['Group'] ?? '',
1004
                    ],
1005
                    $group['UUID'],
1006
                    $newItemsToAdd,
1007
                    $level + 1
1008
                );
1009
            }
1010
1011
            return $newItemsToAdd;
1012
        }
1013
1014
        // Start the recursive processing
1015
        $ret = recursive(
1016
            array_merge(
1017
                ['Entry' => $newArr['Root']['Group']['Entry']],
1018
                ['Group' => $newArr['Root']['Group']['Group']],
1019
            ),
1020
            $destinationFolderId,
1021
            [
1022
                'folders' => [],
1023
                'items' => []
1024
            ],
1025
            1,
1026
        );
1027
1028
error_log(print_r($ret, true));
0 ignored issues
show
Bug introduced by
It seems like print_r($ret, true) can also be of type true; however, parameter $message of error_log() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1028
error_log(/** @scrutinizer ignore-type */ print_r($ret, true));
Loading history...
1029
        echo prepareExchangedData(
1030
            array(
1031
                'error' => false,
1032
                'message' => '',
1033
                'data' => $ret,
1034
            ),
1035
            'encode'
1036
        );
1037
1038
        break;
1039
1040
    // KEEPASS - CREATE FOLDERS
1041
    case 'keepass_create_folders':
1042
        // Check KEY and rights
1043
        if ($inputData['key'] !== $session->get('key')) {
1044
            echo prepareExchangedData(
1045
                array(
1046
                    'error' => true,
1047
                    'message' => $lang->get('key_is_not_correct'),
1048
                ),
1049
                'encode'
1050
            );
1051
            break;
1052
        }
1053
1054
        // Decrypt and retreive data in JSON format
1055
        $receivedParameters = prepareExchangedData(
1056
            $inputData['data'],
1057
            'decode'
1058
        );
1059
1060
        $destinationFolderId = filter_var($receivedParameters['folder-id'], FILTER_SANITIZE_NUMBER_INT);
1061
        $inputData['editAll'] = filter_var($receivedParameters['edit-all'], FILTER_SANITIZE_NUMBER_INT);
1062
        $inputData['editRole'] = filter_var($receivedParameters['edit-role'], FILTER_SANITIZE_NUMBER_INT);
1063
        $post_folders = filter_var_array(
1064
            $receivedParameters['folders'],
1065
            FILTER_SANITIZE_FULL_SPECIAL_CHARS
1066
        );
1067
1068
        // get destination folder informations
1069
        $destinationFolderInfos = getFolderComplexity((int) $destinationFolderId, $session->get('user-personal_folders'));
1070
        $arrFolders[$destinationFolderId] = [
1071
            'id' => (int) $destinationFolderId,
1072
            'level' => 1,
1073
            'isPF' => false,
1074
        ];
1075
        $startPathLevel = 1;
1076
1077
        foreach($post_folders as $folder) {
1078
            // get parent id
1079
            if (!isset($arrFolders[$folder['parentFolderId']])) {
1080
                // If parent folder is not in the array, it means it is the destination folder
1081
                $parentId = $destinationFolderId;
1082
            } else {
1083
                $parentId = $arrFolders[$folder['parentFolderId']]['id'];
1084
            }
1085
1086
            // create folder in DB
1087
            $folderId = createFolder(
1088
                $folder['folderName'],
1089
                is_null($parentId) ? 0 : (int) $parentId,
1090
                $folder['level'],
1091
                $startPathLevel,
1092
                $destinationFolderInfos['levelPwComplexity']
1093
            );
1094
1095
            // manage parent
1096
            $arrFolders[$folder['uuid']] = [
1097
                'id' => (int) $folderId,
1098
                'level' => (int) ($folder['level'] + $startPathLevel),
1099
                'isPF' => $destinationFolderInfos['importPF'],
1100
            ];
1101
        }
1102
        //rebuild full tree
1103
        $tree->rebuild();
1104
1105
1106
        echo prepareExchangedData(
1107
            array(
1108
                'error' => false,
1109
                'message' => '',
1110
                'folders' => $arrFolders,
1111
            ),
1112
            'encode'
1113
        );
1114
1115
        break;
1116
1117
    // KEEPASS - CREATE ITEMS
1118
    case 'keepass_create_items':
1119
        // Check KEY and rights
1120
        if ($inputData['key'] !== $session->get('key')) {
1121
            echo prepareExchangedData(
1122
                array(
1123
                    'error' => true,
1124
                    'message' => $lang->get('key_is_not_correct'),
1125
                ),
1126
                'encode'
1127
            );
1128
            break;
1129
        }
1130
1131
        // Decrypt and retreive data in JSON format
1132
        $receivedParameters = prepareExchangedData(
1133
            $inputData['data'],
1134
            'decode'
1135
        );
1136
1137
        $$inputData['editAll'] = filter_var($receivedParameters['edit-all'], FILTER_SANITIZE_NUMBER_INT);
1138
        $$inputData['editRole'] = filter_var($receivedParameters['edit-role'], FILTER_SANITIZE_NUMBER_INT);
1139
        $post_folders = filter_var_array(
1140
            $receivedParameters['folders'],
1141
            FILTER_SANITIZE_FULL_SPECIAL_CHARS
1142
        );
1143
        $post_items = filter_var_array(
1144
            $receivedParameters['items'],
1145
            FILTER_SANITIZE_FULL_SPECIAL_CHARS
1146
        );
1147
        $returnedItems = array();
1148
1149
        // Start transaction for better performance
1150
        DB::startTransaction();
1151
1152
        // Import all items
1153
        foreach($post_items as $item) {
1154
            // get info about this folder
1155
            $destinationFolderMore = DB::queryFirstRow(
1156
                'SELECT title FROM '.prefixTable('nested_tree').' WHERE id = %i',
1157
                (int) $post_folders[$item['parentFolderId']]['id']
1158
            );
1159
1160
            // Handle case where pw is empty
1161
            // if not allowed then warn user
1162
            if (($session->has('user-create_item_without_password') && null !== $session->get('user-create_item_without_password')
1163
                && (int) $session->get('user-create_item_without_password') !== 1
1164
                ) ||
1165
                empty($item['Password']) === false
1166
            ) {
1167
                // NEW ENCRYPTION
1168
                $cryptedStuff = doDataEncryption($item['Password']);
1169
            } else {
1170
                $cryptedStuff['encrypted'] = '';
1171
                $cryptedStuff['objectKey'] = '';
1172
            }
1173
            $post_password = $cryptedStuff['encrypted'];
1174
1175
            //ADD item
1176
            DB::insert(
1177
                prefixTable('items'),
1178
                array(
1179
                    'label' => substr($item['Title'], 0, 500),
1180
                    'description' => $item['Notes'],
1181
                    'pw' => $cryptedStuff['encrypted'],
1182
                    'pw_iv' => '',
1183
                    'url' => substr($item['URL'], 0, 500),
1184
                    'id_tree' => isset($post_folders[$item['parentFolderId']]['id']) ? (int)$post_folders[$item['parentFolderId']]['id'] : 0,
1185
                    'login' => substr($item['UserName'], 0, 500),
1186
                    'anyone_can_modify' => $$inputData['editAll'],
1187
                    'encryption_type' => 'teampass_aes',
1188
                    'inactif' => 0,
1189
                    'restricted_to' => '',
1190
                    'perso' => $post_folders[$item['parentFolderId']]['isPF'] === true ? 1 : 0,
1191
                    'item_key' => uniqidReal(50),
1192
                    'created_at' => time(),
1193
                )
1194
            );
1195
            $newId = DB::insertId();
1196
1197
            // Create sharekeys for users
1198
            storeUsersShareKey(
1199
                prefixTable('sharekeys_items'),
1200
                $post_folders[$item['parentFolderId']]['isPF'] === true ? 1 : 0,
1201
                (int) $newId,
1202
                $cryptedStuff['objectKey'],
1203
            );
1204
1205
            //if asked, anyone in role can modify
1206
            if ($$inputData['editRole'] === 1) {
1207
                foreach ($session->get('system-array_roles') as $role) {
1208
                    DB::insert(
1209
                        prefixTable('restriction_to_roles'),
1210
                        array(
1211
                            'role_id' => $role['id'],
1212
                            'item_id' => $newId,
1213
                        )
1214
                    );
1215
                }
1216
            }
1217
1218
            //Add log
1219
            DB::insert(
1220
                prefixTable('log_items'),
1221
                array(
1222
                    'id_item' => $newId,
1223
                    'date' => time(),
1224
                    'id_user' => $session->get('user-id'),
1225
                    'action' => 'at_creation',
1226
                    'raison' => 'at_import',
1227
                )
1228
            );
1229
1230
            // Add item to cache table
1231
            updateCacheTable('add_value', (int) $newId);
1232
1233
            // prepare return
1234
            $returnedItems[] = array(
1235
                'title' => substr(stripslashes($item['Title']), 0, 500),
1236
                'folder' => $destinationFolderMore['title']
1237
            );
1238
        }
1239
1240
        // Commit transaction.
1241
        DB::commit();
1242
1243
        echo prepareExchangedData(
1244
            array(
1245
                'error' => false,
1246
                'message' => '',
1247
                'items' => $returnedItems,
1248
            ),
1249
            'encode'
1250
        );
1251
1252
        break;
1253
    }
1254
1255
1256
1257
/**
1258
 * Create folders during importation
1259
 *
1260
 * @param string $folderTitle
1261
 * @param integer $parentId
1262
 * @param integer $folderLevel
1263
 * @param integer $startPathLevel
1264
 * @param integer $levelPwComplexity
1265
 * @return integer
1266
 */
1267
function createFolder($folderTitle, $parentId, $folderLevel, $startPathLevel, $levelPwComplexity)
1268
{
1269
    $session = SessionManager::getSession();
1270
1271
    // Is parent folder a personal folder?
1272
    $isPersonalFolder = in_array($parentId, $session->get('user-personal_folders')) ? 1 : 0;
1273
1274
    //create folder - if not exists at the same level
1275
    DB::query(
1276
        'SELECT * FROM '.prefixTable('nested_tree').'
1277
        WHERE nlevel = %i AND title = %s AND parent_id = %i LIMIT 1',
1278
        intval($folderLevel + $startPathLevel),
1279
        $folderTitle,
1280
        $parentId
1281
    );
1282
    if (DB::count() === 0) {
1283
        //do query
1284
        DB::insert(
1285
            prefixTable('nested_tree'),
1286
            array(
1287
                'parent_id' => (int) $parentId,
1288
                'title' => (string) html_entity_decode(stripslashes($folderTitle), ENT_QUOTES, 'UTF-8'),
1289
                'nlevel' => (int) $folderLevel,
1290
                'categories' => '',
1291
            )
1292
        );
1293
        $id = DB::insertId();
1294
        //Add complexity level => level is set to "medium" by default.
1295
        DB::insert(
1296
            prefixTable('misc'),
1297
            array(
1298
                'type' => 'complex',
1299
                'intitule' => (int) $id,
1300
                'valeur' => (int) $levelPwComplexity,
1301
                'created_at' => time(),
1302
            )
1303
        );
1304
1305
        // Indicate that a change has been done to force tree user reload
1306
        DB::update(
1307
            prefixTable('misc'),
1308
            array(
1309
                'valeur' => time(),
1310
                'updated_at' => time(),
1311
            ),
1312
            'type = %s AND intitule = %s',
1313
            'timestamp',
1314
            'last_folder_change'
1315
        );
1316
1317
        //For each role to which the user depends on, add the folder just created.
1318
        // (if not personal, otherwise, add to user-personal_folders)
1319
        if ( $isPersonalFolder ) {
1320
            SessionManager::addRemoveFromSessionArray('user-personal_folders', [$id], 'add');
1321
        } else {
1322
            foreach ($session->get('system-array_roles') as $role) {
1323
                DB::insert(
1324
                    prefixTable('roles_values'),
1325
                    array(
1326
                        'role_id' => $role['id'],
1327
                        'folder_id' => $id,
1328
                        'type' => 'W',
1329
                    )
1330
                );
1331
            }
1332
        }
1333
1334
        //Add this new folder to the list of visible folders for the user.
1335
        $session->set('user-accessible_folders', array_unique(array_merge($session->get('user-accessible_folders'), [$id]), SORT_NUMERIC));
1336
1337
        return $id;
1338
    }
1339
1340
    //get folder actual ID
1341
    $data = DB::queryFirstRow(
1342
        'SELECT id FROM '.prefixTable('nested_tree').'
1343
        WHERE nlevel = %i AND title = %s AND parent_id = %i',
1344
        intval($folderLevel + $startPathLevel),
1345
        $folderTitle,
1346
        $parentId
1347
    );
1348
    return $data['id'];
1349
}
1350
1351
/**
1352
 * getFolderComplexity
1353
 *
1354
 * @param int $folderId
1355
 * @param boolean $isFolderPF
1356
 *
1357
 * @return array
1358
*/
1359
function getFolderComplexity($folderId, $isFolderPF)
1360
{
1361
    // If destination is not ROOT then get the complexity level
1362
    if ($isFolderPF === true) {
1363
        return [
1364
            'levelPwComplexity' => 50,
1365
            'startPathLevel' => 1,
1366
            'importPF' => true
1367
        ];
1368
    } elseif ($folderId > 0) {
1369
        $data = DB::queryFirstRow(
1370
            'SELECT m.valeur as value, t.nlevel as nlevel
1371
            FROM '.prefixTable('misc').' as m
1372
            INNER JOIN '.prefixTable('nested_tree').' as t ON (m.intitule = t.id)
1373
            WHERE m.type = %s AND m.intitule = %s',
1374
            'complex',
1375
            $folderId
1376
        );
1377
        return [
1378
            'levelPwComplexity' => $data['value'],
1379
            'startPathLevel' => $data['nlevel'],
1380
            'importPF' => false
1381
        ];
1382
    }
1383
    return [
1384
        'levelPwComplexity' => 50,
1385
        'startPathLevel' => 0,
1386
        'importPF' => false
1387
    ];
1388
}
1389
1390
spl_autoload_register(function ($class) {
1391
    $prefix = 'League\\Csv\\';
1392
    $base_dir = __DIR__.'/src/';
1393
    $len = strlen($prefix);
1394
    if (strncmp($prefix, $class, $len) !== 0) {
1395
        // no, move to the next registered autoloader
1396
        return;
1397
    }
1398
    $relative_class = substr($class, $len);
1399
    $file = $base_dir.str_replace('\\', '/', $relative_class).'.php';
1400
    if (file_exists($file)) {
1401
        require $file;
1402
    }
1403
});
1404
1405
/**
1406
 * Used to format the string ready for insertion in to the database.
1407
 *
1408
 * @param string $str             String to clean
1409
 * @param string $crLFReplacement Replacement
1410
 *
1411
 * @return string
1412
 */
1413
function sanitiseString($str, $crLFReplacement)
1414
{
1415
    $str = preg_replace('#[\r\n]#', $crLFReplacement, (string) $str);
1416
    $str = str_replace('\\', '&#92;', $str);
1417
    $str = str_replace('"', '&quot;', $str);
1418
    if (!empty($str)) {
1419
        addslashes($str);
1420
    }
1421
1422
    return $str;
1423
}
1424
1425
/**
1426
 * Clean array values.
1427
 *
1428
 * @param string $value String to clean
1429
 *
1430
 * @return string
1431
 */
1432
function cleanOutput(&$value)
1433
{
1434
    return htmlspecialchars_decode($value);
1435
}
1436
1437
/**
1438
 * Clean a string.
1439
 *
1440
 * @param string $value The string to clean.
1441
 *
1442
 * @return string The cleaned string.
1443
 */
1444
function cleanInput($value): string
1445
{
1446
    return stripEmojis(
1447
        cleanString(
1448
            html_entity_decode($value, ENT_QUOTES | ENT_XHTML, 'UTF-8'),
1449
            true
1450
        )
1451
    );
1452
}
1453
1454
/**
1455
 * Strip any emoji icons from the string.
1456
 *
1457
 * @param string $string
1458
 *   The string to remove emojis from.
1459
 *
1460
 * @return string
1461
 *   The string with emojis removed.
1462
 */
1463
function stripEmojis($string): string
1464
{
1465
    // Convert question marks to a special thing so that we can remove
1466
    // question marks later without any problems.
1467
    $string = str_replace("?", "{%}", $string);
1468
    // Convert the text into UTF-8.
1469
    $string = mb_convert_encoding($string, "ISO-8859-1", "UTF-8");
1470
    // Convert the text to ASCII.
1471
    $string = mb_convert_encoding($string, "UTF-8", "ISO-8859-1");
1472
    // Replace anything that is a question mark (left over from the conversion.
1473
    $string = preg_replace('/(\s?\?\s?)/', ' ', $string);
1474
    // Put back the .
1475
    $string = str_replace("{%}", "?", $string);
1476
    // Trim and return.
1477
    return trim($string);
1478
  }
1479