Passed
Branch development (e0e718)
by Nils
04:45
created

recursiveKeepassXML()   F

Complexity

Conditions 80
Paths 12826

Size

Total Lines 240
Code Lines 157

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 80
eloc 157
nc 12826
nop 2
dl 0
loc 240
rs 2
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 37 and the first side effect is on line 18.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @file          import.queries.php
4
 * @author        Nils Laumaillé
5
 * @version       2.1.27
6
 * @copyright     (c) 2009-2017 Nils Laumaillé
7
 * @licensing     GNU GPL-3.0
8
 * @link          http://www.teampass.net
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
 */
14
use Goodby\CSV\Import\Standard\Lexer;
15
use Goodby\CSV\Import\Standard\Interpreter;
16
use Goodby\CSV\Import\Standard\LexerConfig;
17
18
require_once 'SecureHandler.php';
19
session_start();
20
if (!isset($_SESSION['CPM']) || $_SESSION['CPM'] != 1 || !isset($_SESSION['key']) || empty($_SESSION['key'])) {
21
    die('Hacking attempt...');
22
}
23
24
// Load config
25
if (file_exists('../includes/config/tp.config.php')) {
26
    require_once '../includes/config/tp.config.php';
27
} elseif (file_exists('./includes/config/tp.config.php')) {
28
    require_once './includes/config/tp.config.php';
29
} else {
30
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
31
}
32
33
// No time limit
34
set_time_limit(0);
35
36
// Set some constants for program readability
37
define('KP_PATH', 0);
38
define('KP_GROUP', 1);
39
define('KP_TITLE', 2);
40
define('KP_PASSWORD', 3);
41
define('KP_USERNAME', 4);
42
define('KP_URL', 5);
43
define('KP_UUID', 6);
44
define('KP_NOTES', 7);
45
46
/*
47
 * sanitiseString
48
 *
49
 * Used to format the string ready for insertion in to the database
50
 */
51
/**
52
 * @param string $crLFReplacement
53
 */
54
function sanitiseString($str, $crLFReplacement)
55
{
56
    $str = preg_replace('#[\r\n]#', $crLFReplacement, $str);
57
    $str = str_replace('\\', '&#92;', $str);
58
    $str = str_replace('"', "&quot;", $str);
59
    if (!empty($str)) {
60
        addslashes($str);
61
    }
62
    return $str;
63
}
64
65
global $k, $settings;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
66
header("Content-type: text/html; charset=utf-8");
67
error_reporting(E_ERROR);
68
include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
69
70
//Class loader
71
require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
72
73
// call needed functions
74
require_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
75
76
// connect to the server
77
require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
78
$pass = defuse_return_decrypted($pass);
79
DB::$host = $server;
80
DB::$user = $user;
81
DB::$password = $pass;
82
DB::$dbName = $database;
83
DB::$port = $port;
84
DB::$encoding = $encoding;
85
DB::$error_handler = true;
86
$link = mysqli_connect($server, $user, $pass, $database, $port);
87
$link->set_charset($encoding);
88
89
//Load Tree
90
$tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
91
$tree->register();
92
$tree = new Tree\NestedTree\NestedTree($pre.'nested_tree', 'id', 'parent_id', 'title');
93
94
//Load AES
95
$aes = new SplClassLoader('Encryption\Crypt', '../includes/libraries');
96
$aes->register();
97
98
//User's language loading
99
require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$_SESSION['user_language'].'.php';
100
101
// Build query
102
switch (filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING)) {
103
    //Check if import CSV file format is what expected
104
    case "import_file_format_csv":
105
        //load full tree
106
        $tree->rebuild();
107
        $tree = $tree->getDescendants();
108
       // Init post variable
109
        $post_operation_id = filter_input(INPUT_POST, 'file', FILTER_SANITIZE_NUMBER_INT);
110
111
        // Get filename from database
112
        $data = DB::queryFirstRow(
113
            "SELECT valeur
114
            FROM ".$pre."misc
115
            WHERE increment_id = %i AND type = 'temp_file'",
116
            $post_operation_id
117
        );
118
119
        // Delete operation id
120
        DB::delete(
121
            prefix_table('misc'),
122
            "increment_id = %i AND type = 'temp_file'",
123
            $post_operation_id
124
        );
125
126
        // do some initializations
127
        $file = $SETTINGS['path_to_files_folder']."/".$data['valeur'];
128
        $size = 4096;
129
        $separator = ",";
130
        $enclosure = '"';
131
        $fields_expected = array("Label", "Login", "Password", "URL", "Comments"); //requiered fields from CSV
132
        $importation_possible = true;
133
        $display = "<table>";
134
        $line_number = $prev_level = 0;
135
        $account = $text = "";
136
        $continue_on_next_line = false;
137
138
        // Open file
139
        if ($fp = fopen($file, "r")) {
140
            // data from CSV
141
            $valuesToImport = array();
142
            // load libraries
143
            require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Goodby/CSV/Import/Standard/Lexer.php';
144
            require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Goodby/CSV/Import/Standard/Interpreter.php';
145
            require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Goodby/CSV/Import/Standard/LexerConfig.php';
146
147
            // Lexer configuration
148
            $config = new LexerConfig();
149
            $lexer = new Lexer($config);
150
            $config->setIgnoreHeaderLine("true");
151
            // extract data from CSV file
152
            $interpreter = new Interpreter();
153
            $interpreter->addObserver(function (array $row) use (&$valuesToImport) {
154
                $valuesToImport[] = array(
155
                    'Label'     => $row[0],
156
                    'Login'     => $row[1],
157
                    'Password'  => $row[2],
158
                    'url'       => $row[3],
159
                    'Comments'  => $row[4],
160
                );
161
            });
162
            $lexer->parse($file, $interpreter);
163
164
            // extract one line
165
            foreach ($valuesToImport as $key => $row) {
166
                //Check number of fields. MUST be 5. if not stop importation
167
                if (count($row) != 5) {
168
                    $importation_possible = false;
169
                    //Stop if file has not expected structure
170
                    if ($importation_possible === false) {
171
                        echo '[{"error":"bad_structure"}]';
172
                        break;
173
                    }
174
                }
175
176
                //If any comment is on several lines, then replace 'lf' character
177
                $row['Comments'] = str_replace(array("\r\n", "\n", "\r"), "<br />", $row['Comments']);
178
179
                // Check if current line contains a "<br />" character in order to identify an ITEM on several CSV lines
180
                if (substr_count('<br />', $row['Comments']) > 0 || substr_count('<br />', $row['Label']) > 0) {
181
                    $continue_on_next_line = true;
182
                    $comment .= addslashes($row['Label']);
183
                } else {
184
                    // Store in variable values from previous line
185
                    if (!empty($account)) {
186
                        if ($continue_on_next_line === false) {
187
                            // Prepare listing that will be shown to user
188
                            $display .= '<tr><td><input type=\"checkbox\" class=\"item_checkbox\" id=\"item_to_import-'.$line_number.'\" /></td><td><span id=\"item_text-'.$line_number.'\">'.$account.'</span><input type=\"hidden\" value=\"'.$account.'@|@'.$login.'@|@'.$pwd.'@|@'.$url.'@|@'.$comment.'@|@'.$line_number.'\" id=\"item_to_import_values-'.$line_number.'\" /></td></tr>';
189
190
                            // Initialize this variable in order to restart from scratch
191
                            $account = "";
192
                        }
193
                    }
194
                }
195
196
                // Get values of current line
197
                if ($account == "" && $continue_on_next_line === false) {
198
                    $account = htmlspecialchars($row['Label'], ENT_QUOTES, 'UTF-8');
199
                    $login = htmlspecialchars($row['Login'], ENT_QUOTES, 'UTF-8');
200
                    $pwd = str_replace('"', "&quot;", $row['Password']);
201
                    $url = addslashes($row['url']);
202
                    $to_find = array("\"", "'");
203
                    $to_ins = array("&quot", "&#39;");
204
                    $comment = htmlentities(addslashes(str_replace($to_find, $to_ins, $row['Comments'])), ENT_QUOTES, 'UTF-8');
205
206
                    $continue_on_next_line = false;
207
                }
208
209
                //increment number of lines found
210
                $line_number++;
211
            }
212
            // close file
213
            fclose($fp);
214
        } else {
215
            echo '[{"error":"cannot_open"}]';
216
217
            //delete file
218
            unlink($file);
219
            break;
220
        }
221
222
        if ($line_number > 0) {
223
            //add last line
224
            $display .= '<tr><td><input type=\"checkbox\" class=\"item_checkbox\" id=\"item_to_import-'.$line_number.'\" /></td><td><span id=\"item_text-'.$line_number.'\">'.$account.'</span><input type=\"hidden\" value=\"'.$account.'@|@'.$login.'@|@'.str_replace('"', "&quote;", $pwd).'@|@'.$url.'@|@'.$comment.'@|@'.$line_number.'\" id=\"item_to_import_values-'.$line_number.'\" /></td></tr>';
225
226
            // Add a checkbox for select/unselect all others
227
            $display .= '<tr><td colspan=\"2\"><br><input type=\"checkbox\" id=\"item_all_selection\" />&nbsp;'.$LANG['all'].'</td></tr>';
228
229
            // Prepare a list of all folders that the user can choose
230
            $display .= '</table><div style=\"margin:10px 0 10px 0;\"><label><b>'.$LANG['import_to_folder'].'</b></label>&nbsp;<select id=\"import_items_to\" style=\"width:87%;\">';
231
            foreach ($tree as $t) {
232
                if (($_SESSION['user_read_only'] === '0' && in_array($t->id, $_SESSION['groupes_visibles']))
233
                    || ($_SESSION['user_read_only'] === '1' && in_array($t->id, $_SESSION['personal_visible_groups']))
234
                ) {
235
                    $ident = "";
236
                    for ($x = 1; $x < $t->nlevel; $x++) {
237
                        $ident .= "&nbsp;&nbsp;";
238
                    }
239
                    if (null !== filter_input(INPUT_POST, 'folder_id', FILTER_SANITIZE_NUMBER_INT) && filter_input(INPUT_POST, 'folder_id', FILTER_SANITIZE_NUMBER_INT) === $t->id) {
240
                        $selected = " selected";
241
                    } else {
242
                        $selected = "";
243
                    }
244
                    // Check if folder is User id
245
                    if (is_numeric($t->title) === true && $t->title === $_SESSION['user_id']) {
246
                        $t->title = $_SESSION['login'];
247
                    }
248
                    if ($prev_level != null && $prev_level < $t->nlevel) {
249
                        $display .= '<option value=\"'.$t->id.'\"'.$selected.'>'.$ident.str_replace(array("&", '"'), array("&amp;", "&quot;"), $t->title).'</option>';
250
                    } elseif ($prev_level != null && $prev_level == $t->nlevel) {
251
                        $display .= '<option value=\"'.$t->id.'\"'.$selected.'>'.$ident.str_replace(array("&", '"'), array("&amp;", "&quot;"), $t->title).'</option>';
252
                    } else {
253
                        $display .= '<option value=\"'.$t->id.'\"'.$selected.'>'.$ident.str_replace(array("&", '"'), array("&amp;", "&quot;"), $t->title).'</option>';
254
                    }
255
                    $prev_level = $t->nlevel;
256
                }
257
            }
258
            $display .= '</select></div>';
259
260
            // Show results to user.
261
            echo '[{"error":"no" , "output" : "'.$display.'"}]';
262
        }
263
264
        //delete file
265
        unlink($file);
266
267
        break;
268
269
    //Insert into DB the items the user has selected
270
    case "import_items":
271
        //decrypt and retreive data in JSON format
272
        $dataReceived = (Encryption\Crypt\aesctr::decrypt(
273
            filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES),
274
            $_SESSION['key'],
275
            256
276
        ));
277
278
        $post_folder = filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT);
279
280
        // Get title for this folder
281
        $data_fld = DB::queryFirstRow(
282
            "SELECT title
283
            FROM ".prefix_table("nested_tree")."
284
            WHERE id = %i",
285
            $post_folder
286
        );
287
288
        //Get some info about personal folder
289
        if (in_array($post_folder, $_SESSION['personal_folders']) === true) {
290
            $personalFolder = 1;
291
        } else {
292
            $personalFolder = 0;
293
        }
294
295
        //Prepare variables
296
        $listItems = htmlspecialchars_decode($dataReceived);
297
        $list = "";
298
299
        foreach (explode('@_#sep#_@', stripslashes($listItems)) as $item) {
300
            //For each item, insert into DB
301
            $item = explode('@|@', $item); //explode item to get all fields
302
303
            //Encryption key
304
            if ($personalFolder == 1) {
305
                $encrypt = cryption(
306
                    $item[2],
307
                    $_SESSION['user_settings']['session_psk'],
308
                    "encrypt"
309
                );
310
            } else {
311
                $encrypt = cryption(
312
                    $item[2],
313
                    "",
314
                    "encrypt"
315
                );
316
            }
317
318
            // Insert new item in table ITEMS
319
            DB::insert(
320
                prefix_table("items"),
321
                array(
322
                    'label' => substr($item[0], 0, 500),
323
                    'description' => empty($item[4]) ? '' : $item[4],
324
                    'pw' => $encrypt['string'],
325
                    'pw_iv' => $encrypt['iv'],
326
                    'url' => empty($item[3]) ? '' : substr($item[3], 0, 500),
327
                    'id_tree' => filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT),
328
                    'login' => empty($item[1]) ? '' : substr($item[1], 0, 200),
329
                    'anyone_can_modify' => filter_input(INPUT_POST, 'import_csv_anyone_can_modify', FILTER_SANITIZE_STRING) === "true" ? 1 : 0
330
                )
331
            );
332
            $newId = DB::insertId();
333
334
            //if asked, anyone in role can modify
335
            if (null !== filter_input(INPUT_POST, 'import_csv_anyone_can_modify_in_role', FILTER_SANITIZE_STRING)
336
                && filter_input(INPUT_POST, 'import_csv_anyone_can_modify_in_role', FILTER_SANITIZE_STRING) === "true"
337
            ) {
338
                foreach ($_SESSION['arr_roles'] as $role) {
339
                    DB::insert(
340
                        prefix_table("restriction_to_roles"),
341
                        array(
342
                            'role_id' => $role['id'],
343
                            'item_id' => $newId
344
                        )
345
                    );
346
                }
347
            }
348
349
            // Insert new item in table LOGS_ITEMS
350
            DB::insert(
351
                prefix_table("log_items"),
352
                array(
353
                    'id_item' => $newId,
354
                    'date' => time(),
355
                    'id_user' => $_SESSION['user_id'],
356
                    'action' => 'at_creation'
357
                )
358
            );
359
360
            if (empty($list)) {
361
                $list = $item[5];
362
            } else {
363
                $list .= ";".$item[5];
364
            }
365
366
            //Add entry to cache table
367
            DB::insert(
368
                prefix_table("cache"),
369
                array(
370
                    'id' => $newId,
371
                    'label' => substr($item[0], 0, 500),
372
                    'description' => empty($item[4]) ? '' : $item[4],
373
                    'id_tree' => filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT),
374
                    'url' => "0",
375
                    'perso' => $personalFolder == 0 ? 0 : 1,
376
                    'login' => empty($item[1]) ? '' : substr($item[1], 0, 500),
377
                    'folder' => $data_fld['title'],
378
                    'author' => $_SESSION['user_id'],
379
                    'timestamp' => time(),
380
                    'tags' => '',
381
                    'restricted_to' => '0',
382
                    'renewal_period' => "0",
383
                    'timestamp' => time()
384
                )
385
            );
386
        }
387
        echo '[{"items":"'.$list.'"}]';
388
        break;
389
390
    //Check if import KEEPASS file format is what expected
391
    case "import_file_format_keepass":
392
        //Initialization
393
        $root = $meta = $group = $entry = $key = $title = $notes = $pwd = $username = $url = $notKeepassFile = $newItem = $history = $generatorFound = false;
394
        $name = $levelInProgress = $previousLevel = $fullPath = $historyLevel = $path = $display = $keepassVersion = "";
395
        $numGroups = $numItems = 0;
396
        $temparray = $arrFolders = array();
397
        $levelMin = 2;
398
        $foldersSeparator = '@&##&@';
399
        $itemsSeparator = '<=|#|=>';
400
        $lineEndSeparator = '@*1|#9*|@';
401
402
        //prepare CACHE files
403
        $cacheFileName = $SETTINGS['path_to_files_folder']."/cpassman_cache_".md5(time().mt_rand());
404
        $cacheFileNameFolder = $cacheFileName."_folders";
405
        $cacheFile = fopen($cacheFileName, "w");
406
        $cacheFileF = fopen($cacheFileNameFolder, "w");
407
        $logFileName = "/keepassImport_".date('YmdHis').".log";
408
        $cacheLogFile = fopen($SETTINGS['path_to_files_folder'].$logFileName, 'w');
409
410
        // Init post variable
411
        $post_operation_id = filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING);
412
413
        // Get filename from database
414
        $data = DB::queryFirstRow(
415
            "SELECT valeur
416
            FROM ".$pre."misc
417
            WHERE increment_id = %i AND type = 'temp_file'",
418
            $post_operation_id
419
        );
420
421
        // Delete operation id
422
        DB::delete(
423
            prefix_table('misc'),
424
            "increment_id = %i AND type = 'temp_file'",
425
            $post_operation_id
426
        );
427
428
        // do some initializations
429
        $file = $data['valeur'];
430
431
        //read xml file
432
        if (file_exists($SETTINGS['path_to_files_folder']."/".$file)) {
433
            $xml = simplexml_load_file(
434
                $SETTINGS['path_to_files_folder']."/".$file
435
            );
436
        }
437
438
        /**
439
        ** Recursive function that will permit to read each level of XML nodes
440
         */
441
        function recursiveKeepassXML($xmlRoot, $xmlLevel = 0)
442
        {
443
            global $meta, $root, $group, $name, $entry, $levelMin, $title, $notes, $pwd, $username, $url,
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
444
                $newItem, $temparray, $history, $levelInProgress, $historyLevel,
445
                $path, $previousLevel, $generatorFound, $cacheFile, $cacheFileF, $numGroups,
446
                $numItems, $foldersSeparator, $itemsSeparator, $keepassVersion, $arrFolders;
447
448
            $groupsArray = array();
449
450
            // For each node, get the name and SimpleXML balise
451
            foreach ($xmlRoot as $nom => $elem) {
452
                /*
453
                * check if file is generated by keepass 1
454
                * key "pwentry" is only used in KP1.xx XML files
455
                */
456
                if ($nom == "pwentry") {
457
                    if (empty($keepassVersion)) {
458
                        $keepassVersion = 1;
459
                        $generatorFound = true;
460
                        $entry = true;
461
                    } else {
462
                        $entry = true;
463
                    }
464
465
                    //get children
466
                    $xmlChildren = $elem->children();
467
468
                    //recursive call
469
                    recursiveKeepassXML($xmlChildren, $xmlLevel + 1);
470
                }
471
                //IMPORTING KEEPASS 1 XML FILE
472
                if ($keepassVersion == 1) {
473
                    if ($entry === true && $nom == "expiretime") {
474
                        //save previous keepass entry
475
                        $tree = preg_replace('/\\\\/', $foldersSeparator, $temparray['tree']);
476
                        fputs(
477
                            $cacheFile,
478
                            $tree.$itemsSeparator.$temparray[KP_GROUP].$itemsSeparator.$temparray[KP_TITLE].
479
                            $itemsSeparator.$temparray[KP_PW].$itemsSeparator.$temparray[KP_USERNAME].
0 ignored issues
show
Bug introduced by
The constant KP_PW was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
480
                            $itemsSeparator.$temparray[KP_URL].$itemsSeparator.$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
481
                        );
482
483
                        if (!in_array($temparray['tree'], $arrFolders)) {
484
                            fwrite($cacheFileF, $tree."\n");
485
                            array_push($arrFolders, $temparray['tree']);
486
                        }
487
488
                        $temparray = array();
489
                        $newItem++;
490
                    }
491
492
                    if ($entry === true && $nom == "group") {
493
                        $temparray[KP_GROUP] = addslashes(preg_replace('#[\r\n]#', '', $elem));
494
                        foreach ($elem->attributes() as $attributeskey0 => $attributesvalue1) {
495
                            if ($attributeskey0 == "tree") {
496
                                $path = explode('\\', $attributesvalue1);
497
                                if (count($path) > 1) {
498
                                    unset($path[0]);
499
                                    $temparray['tree'] = implode('\\', $path).'\\'.$temparray[KP_GROUP];
500
                                } else {
501
                                    $temparray['tree'] = $temparray[KP_GROUP];
502
                                }
503
                            }
504
                        }
505
                        $numGroups++;
506
                    } elseif ($entry === true && $nom == "title") {
507
                        $temparray[KP_TITLE] = sanitiseString($elem, '');
508
                    } elseif ($entry === true && $nom == "username") {
509
                        $temparray[KP_USERNAME] = sanitiseString($elem, '');
510
                    } elseif ($entry === true && $nom == "url") {
511
                        $temparray[KP_URL] = sanitiseString($elem, '');
512
                    } elseif ($entry === true && $nom == "uuid") {
513
                        $temparray[KP_UUID] = addslashes(preg_replace('#[\r\n]#', '', $elem));
514
                    } elseif ($entry === true && $nom == "password") {
515
                        $temparray[KP_PW] = sanitiseString($elem, '');
516
                    } elseif ($entry === true && $nom == "notes") {
517
                        $temparray[KP_NOTES] = sanitiseString($elem, '');
518
                    }
519
                }
520
521
                /*
522
                   * check if file is generated by keepass 2
523
                */
524
                if (trim($elem) == "" && $keepassVersion != 1) {
525
                    //check if file is generated by keepass 2
526
                    if ($nom == "Meta") {
527
                        $meta = true;
528
                    }
529
                    if ($nom == "Root") {
530
                        $root = true;
531
                    }
532
533
                    if ($nom == "Group") {
534
                        $group = true;
535
                        $entry = false;
536
                        $name = "";
537
538
                        // recap previous info
539
                        if (!empty($temparray[KP_TITLE])) {
540
                            //store data
541
                            fputs(
542
                                $cacheFile,
543
                                $temparray[KP_PATH].$itemsSeparator.$temparray[KP_GROUP].
544
                                $itemsSeparator.$temparray[KP_TITLE].$itemsSeparator.$temparray[KP_PW].
545
                                $itemsSeparator.$temparray[KP_USERNAME].$itemsSeparator.
546
                                $temparray[KP_URL].$itemsSeparator.$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
547
                            );
548
549
                            //Clean temp array
550
                            $temparray[KP_TITLE] = $temparray[KP_NOTES] = $temparray[KP_PW] = $temparray[KP_USERNAME] = $temparray[KP_URL] = "";
551
552
                            //increment number
553
                            $numItems++;
554
                        }
555
                        $historyLevel = 0;
556
                    }
557
558
                    //History node needs to be managed in order to not polluate final list
559
                    if ($nom == "History") {
560
                        $history = true;
561
                        $entry = false;
562
                        $historyLevel = $xmlLevel;
563
                    }
564
565
                    if ($nom == "Entry" && ($xmlLevel < $historyLevel || empty($historyLevel))) {
566
                        $entry = true;
567
                        $group = false;
568
                        $history = false;
569
570
                        // recap previous info
571
                        if (!empty($temparray[KP_TITLE])) {
572
                            //store data
573
                            fputs($cacheFile, $temparray[KP_PATH].$itemsSeparator.$temparray[KP_GROUP].$itemsSeparator.$temparray[KP_TITLE].$itemsSeparator.$temparray[KP_PW].$itemsSeparator.$temparray[KP_USERNAME].$itemsSeparator.$temparray[KP_URL].$itemsSeparator.$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n");
574
575
                            //Clean temp array
576
                            $temparray[KP_TITLE] = $temparray[KP_NOTES] = $temparray[KP_PW] = $temparray[KP_USERNAME] = $temparray[KP_URL] = $temparray[KP_UUID] = "";
577
578
                            //increment number
579
                            $numItems++;
580
                        }
581
                        $historyLevel = 0;
582
                    }
583
584
                    //get children
585
                    $xmlChildren = $elem->children();
586
587
                    //recursive call
588
                    if ($history !== true) {
589
                      recursiveKeepassXML($xmlChildren, $xmlLevel + 1);
590
                    }
591
592
                    // Force History to false
593
                    $history = false;
594
595
                    //IMPORTING KEEPASS 2 XML FILE
596
                } elseif ($keepassVersion != 1) {
597
                    // exit if XML file not generated by KeePass
598
                    if ($meta === true && $nom == "Generator" && $elem == "KeePass") {
599
                        $generatorFound = true;
600
                        $keepassVersion = 2;
601
                        break;
602
                    } elseif ($root === true && $xmlLevel > $levelMin) {
603
                        //Check each node name and get data from some of them
604
                        if ($entry === true && $nom == "Key" && $elem == "Title") {
605
                            $title = true;
606
                            $notes = $pwd = $url = $username = false;
607
                        } elseif ($entry === true && $nom == "Key" && $elem == "Notes") {
608
                            $notes = true;
609
                            $title = $pwd = $url = $username = false;
610
                        } elseif ($entry === true && $nom == "UUID") {
611
                            $temparray[KP_UUID] = $elem;
612
                        } elseif ($entry === true && $nom == "Key" && $elem == "Password") {
613
                            $pwd = true;
614
                            $notes = $title = $url = $username = false;
615
                        } elseif ($entry === true && $nom == "Key" && $elem == "URL") {
616
                            $url = true;
617
                            $notes = $pwd = $title = $username = false;
618
                        } elseif ($entry === true && $nom == "Key" && $elem == "UserName") {
619
                            $username = true;
620
                            $notes = $pwd = $url = $title = false;
621
                        } elseif ($group === true && $nom == "Name") {
622
                            $temparray[KP_GROUP] = addslashes(preg_replace('#[\r\n]#', '', $elem));
623
                            $temparray['level'] = $xmlLevel;
624
                            //build current path
625
                            if ($xmlLevel > $levelInProgress) {
626
                                if (!empty($temparray[KP_PATH])) {
627
                                    $temparray[KP_PATH] .= $foldersSeparator.$temparray[KP_GROUP];
628
                                } else {
629
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
630
                                }
631
                            } elseif ($xmlLevel == $levelInProgress) {
632
                                if ($levelInProgress == 3) {
633
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
634
                                } else {
635
                                    $temparray[KP_PATH] = substr($temparray[KP_PATH], 0, strrpos($temparray[KP_PATH], $foldersSeparator) + strlen($foldersSeparator)).$temparray[KP_GROUP];
636
                                }
637
                            } else {
638
                                $diff = abs($xmlLevel - $levelInProgress) + 1;
639
                                $tmp = explode($foldersSeparator, $temparray[KP_PATH]);
640
                                $temparray[KP_PATH] = "";
641
                                for ($x = 0; $x < (count($tmp) - $diff); $x++) {
642
                                    if (!empty($temparray[KP_PATH])) {
643
                                        $temparray[KP_PATH] = $temparray[KP_PATH].$foldersSeparator.$tmp[$x];
644
                                    } else {
645
                                        $temparray[KP_PATH] = $tmp[$x];
646
                                    }
647
                                }
648
                                if (!empty($temparray[KP_PATH])) {
649
                                    $temparray[KP_PATH] .= $foldersSeparator.$temparray[KP_GROUP];
650
                                } else {
651
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
652
                                }
653
                            }
654
655
                            //store folders
656
                            if (!in_array($temparray[KP_PATH], $groupsArray)) {
657
                                fwrite($cacheFileF, $temparray[KP_PATH]."\n");
658
                                array_push($groupsArray, $temparray[KP_PATH]);
659
                                //increment number
660
                                $numGroups++;
661
                            }
662
663
                            //Store actual level
664
                            $levelInProgress = $xmlLevel;
665
                            $previousLevel = $temparray[KP_GROUP];
666
                        } elseif ($title === true && $nom == "Value") {
667
                            $title = false;
668
                            $temparray[KP_TITLE] = sanitiseString($elem, '');
669
                        } elseif ($notes === true && $nom == "Value") {
670
                            $notes = false;
671
                            $temparray[KP_NOTES] = sanitiseString($elem, '');
672
                        } elseif ($pwd === true && $nom == "Value") {
673
                            $pwd = false;
674
                            $temparray[KP_PW] = sanitiseString($elem, '');
675
                        } elseif ($url === true && $nom == "Value") {
676
                            $url = false;
677
                            $temparray[KP_URL] = sanitiseString($elem, '');
678
                        } elseif ($username === true && $nom == "Value") {
679
                            $username = false;
680
                            $temparray[KP_USERNAME] = sanitiseString($elem, '');
681
                        }
682
                    }
683
                }
684
            }
685
        }
686
687
        fputs($cacheLogFile, date('H:i:s ')."Writing XML File ".filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING)."\n");
0 ignored issues
show
Bug introduced by
It seems like $cacheLogFile can also be of type false; however, parameter $handle of fputs() does only seem to accept resource, 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

687
        fputs(/** @scrutinizer ignore-type */ $cacheLogFile, date('H:i:s ')."Writing XML File ".filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING)."\n");
Loading history...
688
689
        // Go through each node of XML file
690
        recursiveKeepassXML($xml);
691
692
        //Stop if not a keepass file
693
        if ($generatorFound === false) {
0 ignored issues
show
introduced by
The condition $generatorFound === false is always true.
Loading history...
694
            //Close file & delete it
695
            fclose($cacheFileF);
0 ignored issues
show
Bug introduced by
It seems like $cacheFileF can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, 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

695
            fclose(/** @scrutinizer ignore-type */ $cacheFileF);
Loading history...
696
            fclose($cacheFile);
697
            unlink($cacheFileName);
698
            unlink($cacheFileNameFolder);
699
            unlink($SETTINGS['url_to_files_folder']."/".filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING));
700
701
            fputs($cacheLogFile, date('H:i').$LANG['import_error_no_read_possible_kp']."\n");
702
703
            echo '[{"error":"not_kp_file" , "message":"'.$LANG['import_error_no_read_possible_kp'].'"}]';
704
            break;
705
        }
706
707
        //save last item
708
        if (!empty($temparray[KP_TITLE])) {
709
            //store data
710
            fputs(
711
                $cacheFile,
712
                $temparray[KP_PATH].$itemsSeparator.$temparray[KP_GROUP].$itemsSeparator.
713
                $temparray[KP_TITLE].$itemsSeparator.$temparray[KP_PW].$itemsSeparator.$temparray[KP_USERNAME].
0 ignored issues
show
Bug introduced by
The constant KP_PW was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
714
                $itemsSeparator.$temparray[KP_URL].$itemsSeparator.$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
715
            );
716
717
            //increment number
718
            $numItems++;
719
        }
720
721
        ##################
722
        ## STARTING IMPORTING IF NO ERRORS OR NOT EMPTY
723
        ##################
724
        if ($numItems > 0 || $numGroups > 0) {
725
            // Write in file
726
            fputs($cacheLogFile, date('H:i:s ').$LANG['nb_folders'].' '.$numGroups."\n");
727
            fputs($cacheLogFile, date('H:i:s ').$LANG['nb_items'].' '.$numItems."\n");
728
729
            $import_perso = false;
730
            $itemsArray = array();
731
            $text = '<span class="fa fa-folder-open"></span>&nbsp;'.$LANG['nb_folders'].': '.
732
                $numGroups.'<br /><span class="fa fa-tag"></span>>&nbsp;'.$LANG['nb_items'].': '.
733
                $numItems.'<br /><br />';
734
            $post_destination = filter_input(INPUT_POST, 'destination', FILTER_SANITIZE_STRING);
735
736
            // If personal folder, then remove the suffix in ID
737
            if (substr_count($post_destination, '-perso') > 0) {
738
                $post_destination = str_replace('-perso', '', $post_destination);
739
            }
740
741
            // If destination is not ROOT then get the complexity level
742
            if (strpos($post_destination, "perso") !== 0) {
743
                $levelPwComplexity = 50;
744
                $startPathLevel = 1;
745
                $import_perso = true;
746
            } elseif ($post_destination > 0) {
747
                $data = DB::queryFirstRow(
748
                    "SELECT m.valeur as value, t.nlevel as nlevel
749
                    FROM ".prefix_table("misc")." as m
750
                    INNER JOIN ".prefix_table("nested_tree")." as t ON (m.intitule = t.id)
751
                    WHERE m.type = %s AND m.intitule = %s",
752
                    "complex",
753
                    mysqli_escape_string($link, $post_destination)
754
                );
755
                $levelPwComplexity = $data['value'];
756
                $startPathLevel = $data['nlevel'];
757
            } else {
758
                $levelPwComplexity = 50;
759
                $startPathLevel = 0;
760
            }
761
762
            //Get all folders from file
763
            fclose($cacheFileF);
764
            $cacheFileF = fopen($cacheFileNameFolder, "r");
765
766
            //Create folders
767
            $i = 1;
768
            $level = 0;
769
            $foldersArray = array();
770
            $nbFoldersImported = 0;
771
772
            fputs($cacheLogFile, date('H:i:s ')."Creating Folders\n");
773
            $results = "Folders\n\n";
774
775
            while (!feof($cacheFileF)) {
776
                $folder = fgets($cacheFileF, 4096);
777
                if (!empty($folder)) {
778
                    $folder = str_replace(array("\r\n", "\n", "\r"), '', $folder);
779
                    //get number of levels in path
780
                    $path = explode($foldersSeparator, $folder);
781
                    $folderLevel = count($path);
782
783
                    //get folder name
784
                    if (strrpos($folder, $foldersSeparator) > 0) {
785
                        $fold = substr($folder, strrpos($folder, $foldersSeparator) + strlen($foldersSeparator));
786
                        $parent = implode($foldersSeparator, array_slice($path, 0, -1));
787
                        $parent_id = $foldersArray[$parent]['id'];
788
                    } else {
789
                        $fold = $folder;
790
                        $parent_id = $post_destination; //permits to select the folder destination
791
                    }
792
793
                    $fold = stripslashes($fold);
794
                    //create folder - if not exists at the same level
795
                    DB::query(
796
                        "SELECT * FROM ".prefix_table("nested_tree")."
797
                        WHERE nlevel = %i AND title = %s AND parent_id = %i LIMIT 1",
798
                        intval($folderLevel + $startPathLevel),
799
                        $fold,
800
                        $parent_id
801
                    );
802
                    $results .= str_replace($foldersSeparator, '\\', $folder);
803
                    $counter = DB::count();
804
                    if ($counter == 0) {
805
                        $results .= " - Inserting\n";
806
                        //do query
807
                        DB::insert(
808
                            prefix_table("nested_tree"),
809
                            array(
810
                                'parent_id' => $parent_id,
811
                                'title' => stripslashes($fold),
812
                                'nlevel' => $folderLevel
813
                            )
814
                        );
815
                        $id = DB::insertId();
816
                        //Add complexity level => level is set to "medium" by default.
817
                        DB::insert(
818
                            prefix_table("misc"),
819
                            array(
820
                                'type' => 'complex',
821
                                'intitule' => $id,
822
                                'valeur' => $levelPwComplexity
823
                            )
824
                        );
825
826
                        //For each role to which the user depends on, add the folder just created.
827
                        foreach ($_SESSION['arr_roles'] as $role) {
828
                            DB::insert(
829
                                prefix_table("roles_values"),
830
                                array(
831
                                    'role_id' => $role['id'],
832
                                    'folder_id' => $id,
833
                                    'type' => "W"
834
                                )
835
                            );
836
                        }
837
838
                        //Add this new folder to the list of visible folders for the user.
839
                        array_push($_SESSION['groupes_visibles'], $id);
840
841
                        //increment number of imported folders
842
                        $nbFoldersImported++;
843
                    } else {
844
                        $results .= " - Skipped\n";
845
                        //get folder actual ID
846
                        $data = DB::queryFirstRow(
847
                            "SELECT id FROM ".prefix_table("nested_tree")."
848
                            WHERE nlevel = %i AND title = %s AND parent_id = %i",
849
                            intval($folderLevel + $startPathLevel),
850
                            $fold,
851
                            $parent_id
852
                        );
853
                        $id = $data['id'];
854
                    }
855
856
                    //store in array
857
                    $foldersArray[$folder] = array(
858
                        'folder' => $fold,
859
                        'nlevel' => $folderLevel,
860
                        'id' => $id
861
                    );
862
863
                    $_SESSION['nb_folders']++;
864
                    $i++;
865
                }
866
            }
867
868
            $results .= "\n\nItems\n\n";
869
            //if no new folders them inform
870
            if ($nbFoldersImported > 0) {
871
                fputs($cacheLogFile, date('H:i:s ')."Setting User Rights\n");
872
                //Refresh the rights of actual user
873
                identifyUserRights(
874
                    implode(';', $_SESSION['groupes_visibles']).';'.$newId,
875
                    $_SESSION['groupes_interdits'],
876
                    $_SESSION['is_admin'],
877
                    $_SESSION['fonction_id']
878
                );
879
880
                fputs($cacheLogFile, date('H:i:s ')."Rebuilding Tree\n");
881
                //rebuild full tree
882
                $tree->rebuild();
883
            }
884
885
            fputs($cacheLogFile, date('H:i:s ')."Importing Items\n");
886
887
            // Now import ITEMS
888
            $nbItemsImported = 0;
889
            $count = 0;
890
891
            //Get some info about personal folder
892
            if ($post_destination == $_SESSION['user_id']) {
893
                $personalFolder = 1;
894
            } else {
895
                $personalFolder = 0;
896
            }
897
898
            //prepare file to be read
899
            fclose($cacheFile);
900
            $cacheFile = fopen($cacheFileName, "r");
901
902
            while (!feof($cacheFile)) {
903
                //prepare an array with item to import
904
                $full_item = fgets($cacheFile, 8192);
905
                $full_item = str_replace(array("\r\n", "\n", "\r"), '', $full_item);
906
                $item = explode($itemsSeparator, $full_item);
907
908
                $count++;
909
                if (!($count % 10)) {
910
                    fputs($cacheLogFile, date('H:i:s ')."  Imported $count items (".number_format(($count / $numItems) * 100, 1).")\n");
911
                }
912
913
                if (!empty($item[KP_TITLE])) {
914
                    //$count++;
915
                    //check if not exists
916
                    $results .= str_replace($foldersSeparator, "\\", $item[KP_PATH]).'\\'.$item[KP_TITLE];
917
918
                    $pwd = $item[KP_PASSWORD];
919
920
                    //Get folder label
921
                    if (count($foldersArray) == 0 || empty($item[KP_PATH])) {
922
                        $folderId = $post_destination;
923
                    } else {
924
                        $folderId = $foldersArray[$item[KP_PATH]]['id'];
925
                    }
926
                    $data = DB::queryFirstRow(
927
                        "SELECT title FROM ".prefix_table("nested_tree")." WHERE id = %i",
928
                        intval($folderId)
929
                    );
930
931
                    // escape if folderId is empty
932
                    if (!empty($folderId)) {
933
                        $results .= " - Inserting\n";
934
935
                        // prepare PW
936
                        if ($import_perso === true) {
937
                            $encrypt = cryption(
938
                                $pwd,
939
                                $_SESSION['user_settings']['session_psk'],
940
                                "encrypt"
941
                            );
942
                        } else {
943
                            $encrypt = cryption(
944
                                $pwd,
945
                                "",
946
                                "encrypt"
947
                            );
948
                        }
949
950
                        //ADD item
951
                        DB::insert(
952
                            prefix_table("items"),
953
                            array(
954
                                'label' => substr(stripslashes($item[KP_TITLE]), 0, 500),
955
                                'description' => stripslashes(str_replace($lineEndSeparator, '<br />', $item[KP_NOTES])),
956
                                'pw' => $encrypt['string'],
957
                                'pw_iv' => $encrypt['iv'],
958
                                'url' => substr(stripslashes($item[KP_URL]), 0, 500),
959
                                'id_tree' => $folderId,
960
                                'login' => substr(stripslashes($item[KP_USERNAME]), 0, 500),
961
                                'anyone_can_modify' => filter_input(INPUT_POST, 'import_kps_anyone_can_modify', FILTER_SANITIZE_STRING) === "true" ? 1 : 0
962
                            )
963
                        );
964
                        $newId = DB::insertId();
965
966
                        //if asked, anyone in role can modify
967
                        if (null !== filter_input(INPUT_POST, 'import_kps_anyone_can_modify_in_role', FILTER_SANITIZE_STRING) && filter_input(INPUT_POST, 'import_kps_anyone_can_modify_in_role', FILTER_SANITIZE_STRING) === "true") {
968
                            foreach ($_SESSION['arr_roles'] as $role) {
969
                                DB::insert(
970
                                    prefix_table("restriction_to_roles"),
971
                                    array(
972
                                        'role_id' => $role['id'],
973
                                        'item_id' => $newId
974
                                    )
975
                                );
976
                            }
977
                        }
978
979
                        //Add log
980
                        DB::insert(
981
                            prefix_table("log_items"),
982
                            array(
983
                                'id_item' => $newId,
984
                                'date' => time(),
985
                                'id_user' => $_SESSION['user_id'],
986
                                'action' => 'at_creation',
987
                                'raison' => 'at_import'
988
                            )
989
                        );
990
991
                        //Add entry to cache table
992
                        DB::insert(
993
                            prefix_table("cache"),
994
                            array(
995
                                'id' => $newId,
996
                                'label' => substr(stripslashes($item[KP_TITLE]), 0, 500),
997
                                'description' => stripslashes(str_replace($lineEndSeparator, '<br />', $item[KP_NOTES])),
998
                                'url' => substr(stripslashes($item[KP_URL]), 0, 500),
999
                                'tags' => "",
1000
                                'id_tree' => $folderId,
1001
                                'perso' => $personalFolder == 0 ? 0 : 1,
1002
                                'login' => substr(stripslashes($item[KP_USERNAME]), 0, 500),
1003
                                'restricted_to' => "0",
1004
                                'folder' => $data['title'],
1005
                                'author' => $_SESSION['user_id'],
1006
                                'renewal_period' => "0",
1007
                                'timestamp' => time()
1008
                            )
1009
                        );
1010
1011
                        //increment number of imported items
1012
                        $nbItemsImported++;
1013
                    } else {
1014
                        $results .= " - ".$item[KP_TITLE]." was not imported\n";
1015
                    }
1016
                    fputs($cacheLogFile, date('H:i:s ')." ".$results."\n");
1017
                }
1018
            }
1019
1020
            //SHow finished
1021
            $text .= "Folders imported: $nbFoldersImported<br />";
1022
            $text .= "Items imported: $nbItemsImported<br />";
1023
            $text .= '</div><br /><br /><b>'.$LANG['import_kp_finished'].'</b>';
1024
            $text .= '<a href=\''.$SETTINGS['url_to_files_folder'].'/'.$logFileName.'\' target=\'_blank\'>'.$LANG['pdf_download'].'</a>';
1025
1026
            fputs($cacheLogFile, date('H:i:s ')."Import finished\n");
1027
            fputs($cacheLogFile, date('H:i:s ')."Statistics\n");
1028
            fputs($cacheLogFile, date('H:i:s ')."Folders imported: $nbFoldersImported\n");
1029
            fputs($cacheLogFile, date('H:i:s ')."Items imported: $nbItemsImported\n\n".$results);
1030
1031
            //Delete cache file
1032
            fclose($cacheFileF);
1033
            fclose($cacheFile);
1034
            fclose($cacheLogFile);
1035
            unlink($cacheFileName);
1036
            unlink($cacheFileNameFolder);
1037
            unlink($SETTINGS['path_to_files_folder']."/".$file);
1038
1039
            //Display all messages to user
1040
            echo '[{"error":"" , "message":"'.str_replace('"', "&quote;", strip_tags($text, '<br /><a><div><b><br>')).'"}]';
1041
        } else {
1042
            echo '[{"error":"yes" , "message":"Error - No item found!"}]';
1043
        }
1044
        break;
1045
}
1046
1047
spl_autoload_register(function ($class) {
1048
    $prefix = 'League\\Csv\\';
1049
    $base_dir = __DIR__.'/src/';
1050
    $len = strlen($prefix);
1051
    if (strncmp($prefix, $class, $len) !== 0) {
1052
        // no, move to the next registered autoloader
1053
        return;
1054
    }
1055
    $relative_class = substr($class, $len);
1056
    $file = $base_dir.str_replace('\\', '/', $relative_class).'.php';
1057
    if (file_exists($file)) {
1058
        require $file;
1059
    }
1060
});
1061