Passed
Push — development ( 7ad83d...584ae1 )
by Nils
03:50
created

cleanOutput()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
 * @package       import.queries.php
4
 * @author        Nils Laumaillé <[email protected]>
5
 * @version       2.1.27
6
 * @copyright     2009-2018 Nils Laumaillé
7
 * @license       GNU GPL-3.0
8
 * @link          https://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
    include_once '../includes/config/tp.config.php';
27
} elseif (file_exists('./includes/config/tp.config.php')) {
28
    include_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
require $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) === false) {
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.'" data-label="'.$account.'" data-login="'.$login.'" data-pwd="'.$pwd.'" data-url="'.$url.'" data-comment="'.$comment.'" data-line="'.$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 = trim(htmlspecialchars($row['Label'], ENT_QUOTES, 'UTF-8'));
199
                    $login = trim(htmlspecialchars($row['Login'], ENT_QUOTES, 'UTF-8'));
200
                    $pwd = trim(str_replace('"', "&quot;", $row['Password']));
201
                    $url = trim($row['url']);
202
                    $to_find = array("\"", "'");
203
                    $to_ins = array("&quot", "&#39;");
204
                    $comment = htmlentities(
205
                        addslashes(str_replace($to_find, $to_ins, $row['Comments'])),
206
                        ENT_QUOTES,
207
                        'UTF-8'
208
                    );
209
210
                    $continue_on_next_line = false;
211
                }
212
213
                //increment number of lines found
214
                $line_number++;
215
            }
216
            // close file
217
            fclose($fp);
218
        } else {
219
            echo '[{"error":"cannot_open"}]';
220
221
            //delete file
222
            unlink($file);
223
            break;
224
        }
225
226
        if ($line_number > 0) {
227
            //add last line
228
            $display .= '<tr><td><input type="checkbox" class="item_checkbox" id="item_to_import-'.$line_number.'" data-label="'.$account.'" data-login="'.$login.'" data-pwd="'.$pwd.'" data-url="'.$url.'" data-comment="'.$comment.'" data-line="'.$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.'" id="item_to_import_values-'.$line_number.'" /></td></tr>';
229
230
            // Add a checkbox for select/unselect all others
231
            $display .= '<tr><td colspan="2"><br><input type="checkbox" id="item_all_selection" />&nbsp;'.$LANG['all'].'</td></tr>';
232
233
            // Prepare a list of all folders that the user can choose
234
            $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%;">';
235
            foreach ($tree as $t) {
236
                if (($_SESSION['user_read_only'] === '0' && in_array($t->id, $_SESSION['groupes_visibles']))
237
                    || ($_SESSION['user_read_only'] === '1' && in_array($t->id, $_SESSION['personal_visible_groups']))
238
                ) {
239
                    $ident = "";
240
                    for ($x = 1; $x < $t->nlevel; $x++) {
241
                        $ident .= "&nbsp;&nbsp;";
242
                    }
243
                    if (null !== filter_input(INPUT_POST, 'folder_id', FILTER_SANITIZE_NUMBER_INT) && filter_input(INPUT_POST, 'folder_id', FILTER_SANITIZE_NUMBER_INT) === $t->id) {
244
                        $selected = " selected";
245
                    } else {
246
                        $selected = "";
247
                    }
248
                    // Check if folder is User id
249
                    if (is_numeric($t->title) === true && $t->title === $_SESSION['user_id']) {
250
                        $t->title = $_SESSION['login'];
251
                    }
252
                    if ($prev_level != null && $prev_level < $t->nlevel) {
253
                        $display .= '<option value="'.$t->id.'"'.$selected.'>'.$ident.str_replace(array("&", '"'), array("&amp;", "&quot;"), $t->title).'</option>';
254
                    } elseif ($prev_level != null && $prev_level == $t->nlevel) {
255
                        $display .= '<option value="'.$t->id.'"'.$selected.'>'.$ident.str_replace(array("&", '"'), array("&amp;", "&quot;"), $t->title).'</option>';
256
                    } else {
257
                        $display .= '<option value="'.$t->id.'"'.$selected.'>'.$ident.str_replace(array("&", '"'), array("&amp;", "&quot;"), $t->title).'</option>';
258
                    }
259
                    $prev_level = $t->nlevel;
260
                }
261
            }
262
            $display .= '</select></div>';
263
264
            // Show results to user.
265
            echo prepareExchangedData(
266
                array(
267
                    "error" => "no",
268
                    "output" => $display
269
                ),
270
                "encode"
271
            );
272
        }
273
274
        //delete file
275
        unlink($file);
276
277
        break;
278
279
    //Insert into DB the items the user has selected
280
    case "import_items":
281
        //decrypt and retreive data in JSON format
282
        $dataReceived = (Encryption\Crypt\aesctr::decrypt(
283
            filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES),
284
            $_SESSION['key'],
285
            256
286
        ));
287
288
        $post_folder = filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT);
289
290
        // Get title for this folder
291
        $data_fld = DB::queryFirstRow(
292
            "SELECT title
293
            FROM ".prefix_table("nested_tree")."
294
            WHERE id = %i",
295
            $post_folder
296
        );
297
298
        //Get some info about personal folder
299
        if (in_array($post_folder, $_SESSION['personal_folders']) === true) {
300
            $personalFolder = 1;
301
        } else {
302
            $personalFolder = 0;
303
        }
304
305
        //Prepare variables
306
        $listItems = json_decode($dataReceived, true);
307
308
        /**
309
         * Clean array values
310
         *
311
         * @param [string] $value
0 ignored issues
show
Documentation Bug introduced by
The doc comment [string] at position 0 could not be parsed: Unknown type name '[' at position 0 in [string].
Loading history...
312
         * @return void
313
         */
314
        function cleanOutput(&$value)
315
        {
316
            return htmlspecialchars_decode($value);
0 ignored issues
show
Bug Best Practice introduced by
The expression return htmlspecialchars_decode($value) returns the type string which is incompatible with the documented return type void.
Loading history...
317
        }
318
319
        // Clean each array entry
320
        array_walk_recursive($listItems, "cleanOutput");
321
322
        // Loop on array
323
        foreach ($listItems as $item) {
324
            //For each item, insert into DB
325
            
326
            //Encryption key
327
            if ($personalFolder == 1) {
328
                $encrypt = cryption(
329
                    $item['pwd'],
330
                    $_SESSION['user_settings']['session_psk'],
331
                    "encrypt"
332
                );
333
            } else {
334
                $encrypt = cryption(
335
                    $item['pwd'],
336
                    "",
337
                    "encrypt"
338
                );
339
            }
340
341
            // Insert new item in table ITEMS
342
            DB::insert(
343
                prefix_table("items"),
344
                array(
345
                    'label' => substr($item['label'], 0, 500),
346
                    'description' => empty($item['description']) === true ? '' : $item['description'],
347
                    'pw' => $encrypt['string'],
348
                    'pw_iv' => '',
349
                    'url' => empty($item['url']) === true ? '' : substr($item['url'], 0, 500),
350
                    'id_tree' => filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT),
351
                    'login' => empty($item['login']) === true ? '' : substr($item['login'], 0, 200),
352
                    'anyone_can_modify' => filter_input(INPUT_POST, 'import_csv_anyone_can_modify', FILTER_SANITIZE_STRING) === "true" ? 1 : 0
353
                )
354
            );
355
            $newId = DB::insertId();
356
357
            //if asked, anyone in role can modify
358
            if (null !== filter_input(INPUT_POST, 'import_csv_anyone_can_modify_in_role', FILTER_SANITIZE_STRING)
359
                && filter_input(INPUT_POST, 'import_csv_anyone_can_modify_in_role', FILTER_SANITIZE_STRING) === "true"
360
            ) {
361
                foreach ($_SESSION['arr_roles'] as $role) {
362
                    DB::insert(
363
                        prefix_table("restriction_to_roles"),
364
                        array(
365
                            'role_id' => $role['id'],
366
                            'item_id' => $newId
367
                        )
368
                    );
369
                }
370
            }
371
372
            // Insert new item in table LOGS_ITEMS
373
            DB::insert(
374
                prefix_table("log_items"),
375
                array(
376
                    'id_item' => $newId,
377
                    'date' => time(),
378
                    'id_user' => $_SESSION['user_id'],
379
                    'action' => 'at_creation'
380
                )
381
            );
382
383
            if (empty($list) === true) {
384
                $list = $item['line'];
385
            } else {
386
                $list .= ";".$item['line'];
387
            }
388
389
            //Add entry to cache table
390
            DB::insert(
391
                prefix_table("cache"),
392
                array(
393
                    'id' => $newId,
394
                    'label' => substr($item['label'], 0, 500),
395
                    'description' => empty($item['description']) ? '' : $item['description'],
396
                    'id_tree' => filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT),
397
                    'url' => "0",
398
                    'perso' => $personalFolder == 0 ? 0 : 1,
399
                    'login' => empty($item['login']) ? '' : substr($item['login'], 0, 500),
400
                    'folder' => $data_fld['title'],
401
                    'author' => $_SESSION['user_id'],
402
                    'timestamp' => time(),
403
                    'tags' => '',
404
                    'restricted_to' => '0',
405
                    'renewal_period' => "0",
406
                    'timestamp' => time()
407
                )
408
            );
409
        }
410
        echo '[{"items":"'.$list.'"}]';
411
        break;
412
413
    //Check if import KEEPASS file format is what expected
414
    case "import_file_format_keepass":
415
        //Initialization
416
        $root = $meta = $group = $entry = $key = $title = $notes = $pwd = $username = $url = $notKeepassFile = $newItem = $history = $generatorFound = false;
417
        $name = $levelInProgress = $previousLevel = $fullPath = $historyLevel = $path = $display = $keepassVersion = "";
418
        $numGroups = $numItems = 0;
419
        $temparray = $arrFolders = array();
420
        $levelMin = 2;
421
        $foldersSeparator = '@&##&@';
422
        $itemsSeparator = '<=|#|=>';
423
        $lineEndSeparator = '@*1|#9*|@';
424
425
        //prepare CACHE files
426
        $cacheFileName = $SETTINGS['path_to_files_folder']."/cpassman_cache_".md5(time().mt_rand());
427
        $cacheFileNameFolder = $cacheFileName."_folders";
428
        $cacheFile = fopen($cacheFileName, "w");
429
        $cacheFileF = fopen($cacheFileNameFolder, "w");
430
        $logFileName = "/keepassImport_".date('YmdHis').".log";
431
        $cacheLogFile = fopen($SETTINGS['path_to_files_folder'].$logFileName, 'w');
432
433
        // Init post variable
434
        $post_operation_id = filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING);
435
436
        // Get filename from database
437
        $data = DB::queryFirstRow(
438
            "SELECT valeur
439
            FROM ".$pre."misc
440
            WHERE increment_id = %i AND type = 'temp_file'",
441
            $post_operation_id
442
        );
443
444
        // Delete operation id
445
        DB::delete(
446
            prefix_table('misc'),
447
            "increment_id = %i AND type = 'temp_file'",
448
            $post_operation_id
449
        );
450
451
        // do some initializations
452
        $file = $data['valeur'];
453
454
        //read xml file
455
        if (file_exists($SETTINGS['path_to_files_folder']."/".$file)) {
456
            $xml = simplexml_load_file(
457
                $SETTINGS['path_to_files_folder']."/".$file
458
            );
459
        }
460
461
        /**
462
         ** Recursive function that will permit to read each level of XML nodes
463
         */
464
        function recursiveKeepassXML($xmlRoot, $xmlLevel = 0)
465
        {
466
            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...
467
                $newItem, $temparray, $history, $levelInProgress, $historyLevel,
468
                $path, $previousLevel, $generatorFound, $cacheFile, $cacheFileF, $numGroups,
469
                $numItems, $foldersSeparator, $itemsSeparator, $keepassVersion, $arrFolders;
470
471
            $groupsArray = array();
472
473
            // For each node, get the name and SimpleXML balise
474
            foreach ($xmlRoot as $nom => $elem) {
475
                /*
476
                * check if file is generated by keepass 1
477
                * key "pwentry" is only used in KP1.xx XML files
478
                */
479
                if ($nom == "pwentry") {
480
                    if (empty($keepassVersion)) {
481
                        $keepassVersion = 1;
482
                        $generatorFound = true;
483
                        $entry = true;
484
                    } else {
485
                        $entry = true;
486
                    }
487
488
                    //get children
489
                    $xmlChildren = $elem->children();
490
491
                    //recursive call
492
                    recursiveKeepassXML($xmlChildren, $xmlLevel + 1);
493
                }
494
                //IMPORTING KEEPASS 1 XML FILE
495
                if ($keepassVersion == 1) {
496
                    if ($entry === true && $nom == "expiretime") {
497
                        //save previous keepass entry
498
                        $tree = preg_replace('/\\\\/', $foldersSeparator, $temparray['tree']);
499
                        fputs(
500
                            $cacheFile,
501
                            $tree.$itemsSeparator.$temparray[KP_GROUP].$itemsSeparator.$temparray[KP_TITLE].
502
                            $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...
503
                            $itemsSeparator.$temparray[KP_URL].$itemsSeparator.$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
504
                        );
505
506
                        if (!in_array($temparray['tree'], $arrFolders)) {
507
                            fwrite($cacheFileF, $tree."\n");
508
                            array_push($arrFolders, $temparray['tree']);
509
                        }
510
511
                        $temparray = array();
512
                        $newItem++;
513
                    }
514
515
                    if ($entry === true && $nom == "group") {
516
                        $temparray[KP_GROUP] = addslashes(preg_replace('#[\r\n]#', '', $elem));
517
                        foreach ($elem->attributes() as $attributeskey0 => $attributesvalue1) {
518
                            if ($attributeskey0 == "tree") {
519
                                $path = explode('\\', $attributesvalue1);
520
                                if (count($path) > 1) {
521
                                    unset($path[0]);
522
                                    $temparray['tree'] = implode('\\', $path).'\\'.$temparray[KP_GROUP];
523
                                } else {
524
                                    $temparray['tree'] = $temparray[KP_GROUP];
525
                                }
526
                            }
527
                        }
528
                        $numGroups++;
529
                    } elseif ($entry === true && $nom == "title") {
530
                        $temparray[KP_TITLE] = sanitiseString($elem, '');
531
                    } elseif ($entry === true && $nom == "username") {
532
                        $temparray[KP_USERNAME] = sanitiseString($elem, '');
533
                    } elseif ($entry === true && $nom == "url") {
534
                        $temparray[KP_URL] = sanitiseString($elem, '');
535
                    } elseif ($entry === true && $nom == "uuid") {
536
                        $temparray[KP_UUID] = addslashes(preg_replace('#[\r\n]#', '', $elem));
537
                    } elseif ($entry === true && $nom == "password") {
538
                        $temparray[KP_PW] = sanitiseString($elem, '');
539
                    } elseif ($entry === true && $nom == "notes") {
540
                        $temparray[KP_NOTES] = sanitiseString($elem, '');
541
                    }
542
                }
543
544
                /*
545
                   * check if file is generated by keepass 2
546
                */
547
                if (trim($elem) == "" && $keepassVersion != 1) {
548
                    //check if file is generated by keepass 2
549
                    if ($nom == "Meta") {
550
                        $meta = true;
551
                    }
552
                    if ($nom == "Root") {
553
                        $root = true;
554
                    }
555
556
                    if ($nom == "Group") {
557
                        $group = true;
558
                        $entry = false;
559
                        $name = "";
560
561
                        // recap previous info
562
                        if (!empty($temparray[KP_TITLE])) {
563
                            //store data
564
                            fputs(
565
                                $cacheFile,
566
                                $temparray[KP_PATH].$itemsSeparator.$temparray[KP_GROUP].
567
                                $itemsSeparator.$temparray[KP_TITLE].$itemsSeparator.$temparray[KP_PW].
568
                                $itemsSeparator.$temparray[KP_USERNAME].$itemsSeparator.
569
                                $temparray[KP_URL].$itemsSeparator.$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
570
                            );
571
572
                            //Clean temp array
573
                            $temparray[KP_TITLE] = $temparray[KP_NOTES] = $temparray[KP_PW] = $temparray[KP_USERNAME] = $temparray[KP_URL] = "";
574
575
                            //increment number
576
                            $numItems++;
577
                        }
578
                        $historyLevel = 0;
579
                    }
580
581
                    //History node needs to be managed in order to not polluate final list
582
                    if ($nom == "History") {
583
                        $history = true;
584
                        $entry = false;
585
                        $historyLevel = $xmlLevel;
586
                    }
587
588
                    if ($nom == "Entry" && ($xmlLevel < $historyLevel || empty($historyLevel))) {
589
                        $entry = true;
590
                        $group = false;
591
                        $history = false;
592
593
                        // recap previous info
594
                        if (!empty($temparray[KP_TITLE])) {
595
                            //store data
596
                            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");
597
598
                            //Clean temp array
599
                            $temparray[KP_TITLE] = $temparray[KP_NOTES] = $temparray[KP_PW] = $temparray[KP_USERNAME] = $temparray[KP_URL] = $temparray[KP_UUID] = "";
600
601
                            //increment number
602
                            $numItems++;
603
                        }
604
                        $historyLevel = 0;
605
                    }
606
607
                    //get children
608
                    $xmlChildren = $elem->children();
609
610
                    //recursive call
611
                    if ($history !== true) {
612
                        recursiveKeepassXML($xmlChildren, $xmlLevel + 1);
613
                    }
614
615
                    // Force History to false
616
                    $history = false;
617
618
                    //IMPORTING KEEPASS 2 XML FILE
619
                } elseif ($keepassVersion != 1) {
620
                    // exit if XML file not generated by KeePass
621
                    if ($meta === true && $nom == "Generator" && $elem == "KeePass") {
622
                        $generatorFound = true;
623
                        $keepassVersion = 2;
624
                        break;
625
                    } elseif ($root === true && $xmlLevel > $levelMin) {
626
                        //Check each node name and get data from some of them
627
                        if ($entry === true && $nom == "Key" && $elem == "Title") {
628
                            $title = true;
629
                            $notes = $pwd = $url = $username = false;
630
                        } elseif ($entry === true && $nom == "Key" && $elem == "Notes") {
631
                            $notes = true;
632
                            $title = $pwd = $url = $username = false;
633
                        } elseif ($entry === true && $nom == "UUID") {
634
                            $temparray[KP_UUID] = $elem;
635
                        } elseif ($entry === true && $nom == "Key" && $elem == "Password") {
636
                            $pwd = true;
637
                            $notes = $title = $url = $username = false;
638
                        } elseif ($entry === true && $nom == "Key" && $elem == "URL") {
639
                            $url = true;
640
                            $notes = $pwd = $title = $username = false;
641
                        } elseif ($entry === true && $nom == "Key" && $elem == "UserName") {
642
                            $username = true;
643
                            $notes = $pwd = $url = $title = false;
644
                        } elseif ($group === true && $nom == "Name") {
645
                            $temparray[KP_GROUP] = addslashes(preg_replace('#[\r\n]#', '', $elem));
646
                            $temparray['level'] = $xmlLevel;
647
                            //build current path
648
                            if ($xmlLevel > $levelInProgress) {
649
                                if (!empty($temparray[KP_PATH])) {
650
                                    $temparray[KP_PATH] .= $foldersSeparator.$temparray[KP_GROUP];
651
                                } else {
652
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
653
                                }
654
                            } elseif ($xmlLevel == $levelInProgress) {
655
                                if ($levelInProgress == 3) {
656
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
657
                                } else {
658
                                    $temparray[KP_PATH] = substr($temparray[KP_PATH], 0, strrpos($temparray[KP_PATH], $foldersSeparator) + strlen($foldersSeparator)).$temparray[KP_GROUP];
659
                                }
660
                            } else {
661
                                $diff = abs($xmlLevel - $levelInProgress) + 1;
662
                                $tmp = explode($foldersSeparator, $temparray[KP_PATH]);
663
                                $temparray[KP_PATH] = "";
664
                                for ($x = 0; $x < (count($tmp) - $diff); $x++) {
665
                                    if (!empty($temparray[KP_PATH])) {
666
                                        $temparray[KP_PATH] = $temparray[KP_PATH].$foldersSeparator.$tmp[$x];
667
                                    } else {
668
                                        $temparray[KP_PATH] = $tmp[$x];
669
                                    }
670
                                }
671
                                if (!empty($temparray[KP_PATH])) {
672
                                    $temparray[KP_PATH] .= $foldersSeparator.$temparray[KP_GROUP];
673
                                } else {
674
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
675
                                }
676
                            }
677
678
                            //store folders
679
                            if (!in_array($temparray[KP_PATH], $groupsArray)) {
680
                                fwrite($cacheFileF, $temparray[KP_PATH]."\n");
681
                                array_push($groupsArray, $temparray[KP_PATH]);
682
                                //increment number
683
                                $numGroups++;
684
                            }
685
686
                            //Store actual level
687
                            $levelInProgress = $xmlLevel;
688
                            $previousLevel = $temparray[KP_GROUP];
689
                        } elseif ($title === true && $nom == "Value") {
690
                            $title = false;
691
                            $temparray[KP_TITLE] = sanitiseString($elem, '');
692
                        } elseif ($notes === true && $nom == "Value") {
693
                            $notes = false;
694
                            $temparray[KP_NOTES] = sanitiseString($elem, '');
695
                        } elseif ($pwd === true && $nom == "Value") {
696
                            $pwd = false;
697
                            $temparray[KP_PW] = sanitiseString($elem, '');
698
                        } elseif ($url === true && $nom == "Value") {
699
                            $url = false;
700
                            $temparray[KP_URL] = sanitiseString($elem, '');
701
                        } elseif ($username === true && $nom == "Value") {
702
                            $username = false;
703
                            $temparray[KP_USERNAME] = sanitiseString($elem, '');
704
                        }
705
                    }
706
                }
707
            }
708
        }
709
710
        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

710
        fputs(/** @scrutinizer ignore-type */ $cacheLogFile, date('H:i:s ')."Writing XML File ".filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING)."\n");
Loading history...
711
712
        // Go through each node of XML file
713
        recursiveKeepassXML($xml);
714
715
        //Stop if not a keepass file
716
        if ($generatorFound === false) {
0 ignored issues
show
introduced by
The condition $generatorFound === false is always true.
Loading history...
717
            //Close file & delete it
718
            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

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