Issues (847)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/plugins/authpdo/auth.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
use dokuwiki\Utf8\Sort;
3
4
/**
5
 * DokuWiki Plugin authpdo (Auth Component)
6
 *
7
 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
8
 * @author  Andreas Gohr <[email protected]>
9
 */
10
11
/**
12
 * Class auth_plugin_authpdo
13
 */
14
class auth_plugin_authpdo extends DokuWiki_Auth_Plugin
15
{
16
17
    /** @var PDO */
18
    protected $pdo;
19
20
    /** @var null|array The list of all groups */
21
    protected $groupcache = null;
22
23
    /**
24
     * Constructor.
25
     */
26
    public function __construct()
27
    {
28
        parent::__construct(); // for compatibility
29
30
        if (!class_exists('PDO')) {
31
            $this->debugMsg('PDO extension for PHP not found.', -1, __LINE__);
32
            $this->success = false;
33
            return;
34
        }
35
36
        if (!$this->getConf('dsn')) {
37
            $this->debugMsg('No DSN specified', -1, __LINE__);
38
            $this->success = false;
39
            return;
40
        }
41
42
        try {
43
            $this->pdo = new PDO(
44
                $this->getConf('dsn'),
45
                $this->getConf('user'),
46
                conf_decodeString($this->getConf('pass')),
47
                array(
48
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // always fetch as array
49
                    PDO::ATTR_EMULATE_PREPARES => true, // emulating prepares allows us to reuse param names
50
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
51
                )
52
            );
53
        } catch (PDOException $e) {
54
            $this->debugMsg($e);
55
            msg($this->getLang('connectfail'), -1);
56
            $this->success = false;
57
            return;
58
        }
59
60
        // can Users be created?
61
        $this->cando['addUser'] = $this->checkConfig(
62
            array(
63
                'select-user',
64
                'select-user-groups',
65
                'select-groups',
66
                'insert-user',
67
                'insert-group',
68
                'join-group'
69
            )
70
        );
71
72
        // can Users be deleted?
73
        $this->cando['delUser'] = $this->checkConfig(
74
            array(
75
                'select-user',
76
                'select-user-groups',
77
                'select-groups',
78
                'leave-group',
79
                'delete-user'
80
            )
81
        );
82
83
        // can login names be changed?
84
        $this->cando['modLogin'] = $this->checkConfig(
85
            array(
86
                'select-user',
87
                'select-user-groups',
88
                'update-user-login'
89
            )
90
        );
91
92
        // can passwords be changed?
93
        $this->cando['modPass'] = $this->checkConfig(
94
            array(
95
                'select-user',
96
                'select-user-groups',
97
                'update-user-pass'
98
            )
99
        );
100
101
        // can real names be changed?
102
        $this->cando['modName'] = $this->checkConfig(
103
            array(
104
                'select-user',
105
                'select-user-groups',
106
                'update-user-info:name'
107
            )
108
        );
109
110
        // can real email be changed?
111
        $this->cando['modMail'] = $this->checkConfig(
112
            array(
113
                'select-user',
114
                'select-user-groups',
115
                'update-user-info:mail'
116
            )
117
        );
118
119
        // can groups be changed?
120
        $this->cando['modGroups'] = $this->checkConfig(
121
            array(
122
                'select-user',
123
                'select-user-groups',
124
                'select-groups',
125
                'leave-group',
126
                'join-group',
127
                'insert-group'
128
            )
129
        );
130
131
        // can a filtered list of users be retrieved?
132
        $this->cando['getUsers'] = $this->checkConfig(
133
            array(
134
                'list-users'
135
            )
136
        );
137
138
        // can the number of users be retrieved?
139
        $this->cando['getUserCount'] = $this->checkConfig(
140
            array(
141
                'count-users'
142
            )
143
        );
144
145
        // can a list of available groups be retrieved?
146
        $this->cando['getGroups'] = $this->checkConfig(
147
            array(
148
                'select-groups'
149
            )
150
        );
151
152
        $this->success = true;
153
    }
154
155
    /**
156
     * Check user+password
157
     *
158
     * @param string $user the user name
159
     * @param string $pass the clear text password
160
     * @return  bool
161
     */
162
    public function checkPass($user, $pass)
163
    {
164
165
        $userdata = $this->selectUser($user);
166
        if ($userdata == false) return false;
167
168
        // password checking done in SQL?
169
        if ($this->checkConfig(array('check-pass'))) {
170
            $userdata['clear'] = $pass;
171
            $userdata['hash'] = auth_cryptPassword($pass);
172
            $result = $this->query($this->getConf('check-pass'), $userdata);
173
            if ($result === false) return false;
174
            return (count($result) == 1);
175
        }
176
177
        // we do password checking on our own
178
        if (isset($userdata['hash'])) {
179
            // hashed password
180
            $passhash = new \dokuwiki\PassHash();
181
            return $passhash->verify_hash($pass, $userdata['hash']);
182
        } else {
183
            // clear text password in the database O_o
184
            return ($pass === $userdata['clear']);
185
        }
186
    }
187
188
    /**
189
     * Return user info
190
     *
191
     * Returns info about the given user needs to contain
192
     * at least these fields:
193
     *
194
     * name string  full name of the user
195
     * mail string  email addres of the user
196
     * grps array   list of groups the user is in
197
     *
198
     * @param string $user the user name
199
     * @param bool $requireGroups whether or not the returned data must include groups
200
     * @return array|bool containing user data or false
201
     */
202
    public function getUserData($user, $requireGroups = true)
203
    {
204
        $data = $this->selectUser($user);
205
        if ($data == false) return false;
206
207
        if (isset($data['hash'])) unset($data['hash']);
208
        if (isset($data['clean'])) unset($data['clean']);
209
210
        if ($requireGroups) {
211
            $data['grps'] = $this->selectUserGroups($data);
212
            if ($data['grps'] === false) return false;
213
        }
214
215
        return $data;
216
    }
217
218
    /**
219
     * Create a new User [implement only where required/possible]
220
     *
221
     * Returns false if the user already exists, null when an error
222
     * occurred and true if everything went well.
223
     *
224
     * The new user HAS TO be added to the default group by this
225
     * function!
226
     *
227
     * Set addUser capability when implemented
228
     *
229
     * @param string $user
230
     * @param string $clear
231
     * @param string $name
232
     * @param string $mail
233
     * @param null|array $grps
234
     * @return bool|null
235
     */
236
    public function createUser($user, $clear, $name, $mail, $grps = null)
237
    {
238
        global $conf;
239
240
        if (($info = $this->getUserData($user, false)) !== false) {
241
            msg($this->getLang('userexists'), -1);
242
            return false; // user already exists
243
        }
244
245
        // prepare data
246
        if ($grps == null) $grps = array();
247
        array_unshift($grps, $conf['defaultgroup']);
248
        $grps = array_unique($grps);
249
        $hash = auth_cryptPassword($clear);
250
        $userdata = compact('user', 'clear', 'hash', 'name', 'mail');
251
252
        // action protected by transaction
253
        $this->pdo->beginTransaction();
254
        {
255
            // insert the user
256
            $ok = $this->query($this->getConf('insert-user'), $userdata);
257
            if ($ok === false) goto FAIL;
258
            $userdata = $this->getUserData($user, false);
259
            if ($userdata === false) goto FAIL;
260
261
            // create all groups that do not exist, the refetch the groups
262
            $allgroups = $this->selectGroups();
263
            foreach ($grps as $group) {
264
                if (!isset($allgroups[$group])) {
265
                    $ok = $this->addGroup($group);
266
                    if ($ok === false) goto FAIL;
267
                }
268
            }
269
            $allgroups = $this->selectGroups();
270
271
            // add user to the groups
272
            foreach ($grps as $group) {
273
                $ok = $this->joinGroup($userdata, $allgroups[$group]);
274
                if ($ok === false) goto FAIL;
275
            }
276
        }
277
        $this->pdo->commit();
278
        return true;
279
280
        // something went wrong, rollback
281
        FAIL:
282
        $this->pdo->rollBack();
283
        $this->debugMsg('Transaction rolled back', 0, __LINE__);
284
        msg($this->getLang('writefail'), -1);
285
        return null; // return error
286
    }
287
288
    /**
289
     * Modify user data
290
     *
291
     * @param string $user nick of the user to be changed
292
     * @param array $changes array of field/value pairs to be changed (password will be clear text)
293
     * @return  bool
294
     */
295
    public function modifyUser($user, $changes)
296
    {
297
        // secure everything in transaction
298
        $this->pdo->beginTransaction();
299
        {
300
            $olddata = $this->getUserData($user);
301
            $oldgroups = $olddata['grps'];
302
            unset($olddata['grps']);
303
304
            // changing the user name?
305
            if (isset($changes['user'])) {
306
                if ($this->getUserData($changes['user'], false)) goto FAIL;
307
                $params = $olddata;
308
                $params['newlogin'] = $changes['user'];
309
310
                $ok = $this->query($this->getConf('update-user-login'), $params);
311
                if ($ok === false) goto FAIL;
312
            }
313
314
            // changing the password?
315
            if (isset($changes['pass'])) {
316
                $params = $olddata;
317
                $params['clear'] = $changes['pass'];
318
                $params['hash'] = auth_cryptPassword($changes['pass']);
319
320
                $ok = $this->query($this->getConf('update-user-pass'), $params);
321
                if ($ok === false) goto FAIL;
322
            }
323
324
            // changing info?
325
            if (isset($changes['mail']) || isset($changes['name'])) {
326
                $params = $olddata;
327
                if (isset($changes['mail'])) $params['mail'] = $changes['mail'];
328
                if (isset($changes['name'])) $params['name'] = $changes['name'];
329
330
                $ok = $this->query($this->getConf('update-user-info'), $params);
331
                if ($ok === false) goto FAIL;
332
            }
333
334
            // changing groups?
335
            if (isset($changes['grps'])) {
336
                $allgroups = $this->selectGroups();
337
338
                // remove membership for previous groups
339
                foreach ($oldgroups as $group) {
340
                    if (!in_array($group, $changes['grps']) && isset($allgroups[$group])) {
341
                        $ok = $this->leaveGroup($olddata, $allgroups[$group]);
342
                        if ($ok === false) goto FAIL;
343
                    }
344
                }
345
346
                // create all new groups that are missing
347
                $added = 0;
348
                foreach ($changes['grps'] as $group) {
349
                    if (!isset($allgroups[$group])) {
350
                        $ok = $this->addGroup($group);
351
                        if ($ok === false) goto FAIL;
352
                        $added++;
353
                    }
354
                }
355
                // reload group info
356
                if ($added > 0) $allgroups = $this->selectGroups();
357
358
                // add membership for new groups
359
                foreach ($changes['grps'] as $group) {
360
                    if (!in_array($group, $oldgroups)) {
361
                        $ok = $this->joinGroup($olddata, $allgroups[$group]);
362
                        if ($ok === false) goto FAIL;
363
                    }
364
                }
365
            }
366
367
        }
368
        $this->pdo->commit();
369
        return true;
370
371
        // something went wrong, rollback
372
        FAIL:
373
        $this->pdo->rollBack();
374
        $this->debugMsg('Transaction rolled back', 0, __LINE__);
375
        msg($this->getLang('writefail'), -1);
376
        return false; // return error
377
    }
378
379
    /**
380
     * Delete one or more users
381
     *
382
     * Set delUser capability when implemented
383
     *
384
     * @param array $users
385
     * @return  int    number of users deleted
386
     */
387
    public function deleteUsers($users)
388
    {
389
        $count = 0;
390
        foreach ($users as $user) {
391
            if ($this->deleteUser($user)) $count++;
392
        }
393
        return $count;
394
    }
395
396
    /**
397
     * Bulk retrieval of user data [implement only where required/possible]
398
     *
399
     * Set getUsers capability when implemented
400
     *
401
     * @param int $start index of first user to be returned
402
     * @param int $limit max number of users to be returned
403
     * @param array $filter array of field/pattern pairs, null for no filter
404
     * @return  array list of userinfo (refer getUserData for internal userinfo details)
405
     */
406
    public function retrieveUsers($start = 0, $limit = -1, $filter = null)
407
    {
408
        if ($limit < 0) $limit = 10000; // we don't support no limit
409
        if (is_null($filter)) $filter = array();
410
411
        if (isset($filter['grps'])) $filter['group'] = $filter['grps'];
412
        foreach (array('user', 'name', 'mail', 'group') as $key) {
413
            if (!isset($filter[$key])) {
414
                $filter[$key] = '%';
415
            } else {
416
                $filter[$key] = '%' . $filter[$key] . '%';
417
            }
418
        }
419
        $filter['start'] = (int)$start;
420
        $filter['end'] = (int)$start + $limit;
421
        $filter['limit'] = (int)$limit;
422
423
        $result = $this->query($this->getConf('list-users'), $filter);
424
        if (!$result) return array();
425
        $users = array();
426
        if (is_array($result)) {
427
            foreach ($result as $row) {
428
                if (!isset($row['user'])) {
429
                    $this->debugMsg("list-users statement did not return 'user' attribute", -1, __LINE__);
430
                    return array();
431
                }
432
                $users[] = $this->getUserData($row['user']);
433
            }
434
        } else {
435
            $this->debugMsg("list-users statement did not return a list of result", -1, __LINE__);
436
        }
437
        return $users;
438
    }
439
440
    /**
441
     * Return a count of the number of user which meet $filter criteria
442
     *
443
     * @param array $filter array of field/pattern pairs, empty array for no filter
444
     * @return int
445
     */
446
    public function getUserCount($filter = array())
447
    {
448
        if (is_null($filter)) $filter = array();
449
450
        if (isset($filter['grps'])) $filter['group'] = $filter['grps'];
451
        foreach (array('user', 'name', 'mail', 'group') as $key) {
452
            if (!isset($filter[$key])) {
453
                $filter[$key] = '%';
454
            } else {
455
                $filter[$key] = '%' . $filter[$key] . '%';
456
            }
457
        }
458
459
        $result = $this->query($this->getConf('count-users'), $filter);
460
        if (!$result || !isset($result[0]['count'])) {
461
            $this->debugMsg("Statement did not return 'count' attribute", -1, __LINE__);
462
        }
463
        return (int)$result[0]['count'];
464
    }
465
466
    /**
467
     * Create a new group with the given name
468
     *
469
     * @param string $group
470
     * @return bool
471
     */
472
    public function addGroup($group)
473
    {
474
        $sql = $this->getConf('insert-group');
475
476
        $result = $this->query($sql, array(':group' => $group));
477
        $this->clearGroupCache();
478
        if ($result === false) return false;
479
        return true;
480
    }
481
482
    /**
483
     * Retrieve groups
484
     *
485
     * Set getGroups capability when implemented
486
     *
487
     * @param int $start
488
     * @param int $limit
489
     * @return  array
490
     */
491
    public function retrieveGroups($start = 0, $limit = 0)
492
    {
493
        $groups = array_keys($this->selectGroups());
494
        if ($groups === false) return array();
495
496
        if (!$limit) {
497
            return array_splice($groups, $start);
498
        } else {
499
            return array_splice($groups, $start, $limit);
500
        }
501
    }
502
503
    /**
504
     * Select data of a specified user
505
     *
506
     * @param string $user the user name
507
     * @return bool|array user data, false on error
508
     */
509
    protected function selectUser($user)
510
    {
511
        $sql = $this->getConf('select-user');
512
513
        $result = $this->query($sql, array(':user' => $user));
514
        if (!$result) return false;
515
516
        if (count($result) > 1) {
517
            $this->debugMsg('Found more than one matching user', -1, __LINE__);
518
            return false;
519
        }
520
521
        $data = array_shift($result);
522
        $dataok = true;
523
524
        if (!isset($data['user'])) {
525
            $this->debugMsg("Statement did not return 'user' attribute", -1, __LINE__);
526
            $dataok = false;
527
        }
528
        if (!isset($data['hash']) && !isset($data['clear']) && !$this->checkConfig(array('check-pass'))) {
529
            $this->debugMsg("Statement did not return 'clear' or 'hash' attribute", -1, __LINE__);
530
            $dataok = false;
531
        }
532
        if (!isset($data['name'])) {
533
            $this->debugMsg("Statement did not return 'name' attribute", -1, __LINE__);
534
            $dataok = false;
535
        }
536
        if (!isset($data['mail'])) {
537
            $this->debugMsg("Statement did not return 'mail' attribute", -1, __LINE__);
538
            $dataok = false;
539
        }
540
541
        if (!$dataok) return false;
542
        return $data;
543
    }
544
545
    /**
546
     * Delete a user after removing all their group memberships
547
     *
548
     * @param string $user
549
     * @return bool true when the user was deleted
550
     */
551
    protected function deleteUser($user)
552
    {
553
        $this->pdo->beginTransaction();
554
        {
555
            $userdata = $this->getUserData($user);
556
            if ($userdata === false) goto FAIL;
557
            $allgroups = $this->selectGroups();
558
559
            // remove group memberships (ignore errors)
560
            foreach ($userdata['grps'] as $group) {
561
                if (isset($allgroups[$group])) {
562
                    $this->leaveGroup($userdata, $allgroups[$group]);
563
                }
564
            }
565
566
            $ok = $this->query($this->getConf('delete-user'), $userdata);
567
            if ($ok === false) goto FAIL;
568
        }
569
        $this->pdo->commit();
570
        return true;
571
572
        FAIL:
573
        $this->pdo->rollBack();
574
        return false;
575
    }
576
577
    /**
578
     * Select all groups of a user
579
     *
580
     * @param array $userdata The userdata as returned by _selectUser()
581
     * @return array|bool list of group names, false on error
582
     */
583
    protected function selectUserGroups($userdata)
584
    {
585
        global $conf;
586
        $sql = $this->getConf('select-user-groups');
587
        $result = $this->query($sql, $userdata);
588
        if ($result === false) return false;
589
590
        $groups = array($conf['defaultgroup']); // always add default config
591
        if (is_array($result)) {
592
            foreach ($result as $row) {
593
                if (!isset($row['group'])) {
594
                    $this->debugMsg("No 'group' field returned in select-user-groups statement", -1, __LINE__);
595
                    return false;
596
                }
597
                $groups[] = $row['group'];
598
            }
599
        } else {
600
            $this->debugMsg("select-user-groups statement did not return a list of result", -1, __LINE__);
601
        }
602
603
        $groups = array_unique($groups);
604
        Sort::sort($groups);
605
        return $groups;
606
    }
607
608
    /**
609
     * Select all available groups
610
     *
611
     * @return array|bool list of all available groups and their properties
612
     */
613
    protected function selectGroups()
614
    {
615
        if ($this->groupcache) return $this->groupcache;
616
617
        $sql = $this->getConf('select-groups');
618
        $result = $this->query($sql);
619
        if ($result === false) return false;
620
621
        $groups = array();
622
        if (is_array($result)) {
623
            foreach ($result as $row) {
624
                if (!isset($row['group'])) {
625
                    $this->debugMsg("No 'group' field returned from select-groups statement", -1, __LINE__);
626
                    return false;
627
                }
628
629
                // relayout result with group name as key
630
                $group = $row['group'];
631
                $groups[$group] = $row;
632
            }
633
        } else {
634
            $this->debugMsg("select-groups statement did not return a list of result", -1, __LINE__);
635
        }
636
637
        Sort::ksort($groups);
638
        return $groups;
639
    }
640
641
    /**
642
     * Remove all entries from the group cache
643
     */
644
    protected function clearGroupCache()
645
    {
646
        $this->groupcache = null;
647
    }
648
649
    /**
650
     * Adds the user to the group
651
     *
652
     * @param array $userdata all the user data
653
     * @param array $groupdata all the group data
654
     * @return bool
655
     */
656
    protected function joinGroup($userdata, $groupdata)
657
    {
658
        $data = array_merge($userdata, $groupdata);
659
        $sql = $this->getConf('join-group');
660
        $result = $this->query($sql, $data);
661
        if ($result === false) return false;
662
        return true;
663
    }
664
665
    /**
666
     * Removes the user from the group
667
     *
668
     * @param array $userdata all the user data
669
     * @param array $groupdata all the group data
670
     * @return bool
671
     */
672
    protected function leaveGroup($userdata, $groupdata)
673
    {
674
        $data = array_merge($userdata, $groupdata);
675
        $sql = $this->getConf('leave-group');
676
        $result = $this->query($sql, $data);
677
        if ($result === false) return false;
678
        return true;
679
    }
680
681
    /**
682
     * Executes a query
683
     *
684
     * @param string $sql The SQL statement to execute
685
     * @param array $arguments Named parameters to be used in the statement
686
     * @return array|int|bool The result as associative array for SELECTs, affected rows for others, false on error
687
     */
688
    protected function query($sql, $arguments = array())
689
    {
690
        $sql = trim($sql);
691
        if (empty($sql)) {
692
            $this->debugMsg('No SQL query given', -1, __LINE__);
693
            return false;
694
        }
695
696
        // execute
697
        $params = array();
698
        $sth = $this->pdo->prepare($sql);
699
        $result = false;
700
        try {
701
            // prepare parameters - we only use those that exist in the SQL
702
            foreach ($arguments as $key => $value) {
703
                if (is_array($value)) continue;
704
                if (is_object($value)) continue;
705
                if ($key[0] != ':') $key = ":$key"; // prefix with colon if needed
706
                if (strpos($sql, $key) === false) continue; // skip if parameter is missing
707
708
                if (is_int($value)) {
709
                    $sth->bindValue($key, $value, PDO::PARAM_INT);
710
                } else {
711
                    $sth->bindValue($key, $value);
712
                }
713
                $params[$key] = $value; //remember for debugging
714
            }
715
716
            $sth->execute();
717
            // only report last line's result
718
            $hasnextrowset = true;
719
            $currentsql = $sql;
720
            while ($hasnextrowset) {
721
                if (strtolower(substr($currentsql, 0, 6)) == 'select') {
722
                    $result = $sth->fetchAll();
723
                } else {
724
                    $result = $sth->rowCount();
725
                }
726
                $semi_pos = strpos($currentsql, ';');
727
                if ($semi_pos) {
728
                    $currentsql = trim(substr($currentsql, $semi_pos + 1));
729
                }
730
                try {
731
                    $hasnextrowset = $sth->nextRowset(); // run next rowset
732
                } catch (PDOException $rowset_e) {
733
                    $hasnextrowset = false; // driver does not support multi-rowset, should be executed in one time
734
                }
735
            }
736
        } catch (Exception $e) {
737
            // report the caller's line
738
            $trace = debug_backtrace();
739
            $line = $trace[0]['line'];
740
            $dsql = $this->debugSQL($sql, $params, !defined('DOKU_UNITTEST'));
741
            $this->debugMsg($e, -1, $line);
742
            $this->debugMsg("SQL: <pre>$dsql</pre>", -1, $line);
743
        }
744
        $sth->closeCursor();
745
        $sth = null;
0 ignored issues
show
$sth is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
746
747
        return $result;
748
    }
749
750
    /**
751
     * Wrapper around msg() but outputs only when debug is enabled
752
     *
753
     * @param string|Exception $message
754
     * @param int $err
755
     * @param int $line
756
     */
757
    protected function debugMsg($message, $err = 0, $line = 0)
758
    {
759
        if (!$this->getConf('debug')) return;
760
        if (is_a($message, 'Exception')) {
761
            $err = -1;
762
            $msg = $message->getMessage();
0 ignored issues
show
It seems like $message is not always an object, but can also be of type string. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
763
            if (!$line) $line = $message->getLine();
764
        } else {
765
            $msg = $message;
766
        }
767
768
        if (defined('DOKU_UNITTEST')) {
769
            printf("\n%s, %s:%d\n", $msg, __FILE__, $line);
770
        } else {
771
            msg('authpdo: ' . $msg, $err, $line, __FILE__);
772
        }
773
    }
774
775
    /**
776
     * Check if the given config strings are set
777
     *
778
     * @param string[] $keys
779
     * @return  bool
780
     * @author  Matthias Grimm <[email protected]>
781
     *
782
     */
783
    protected function checkConfig($keys)
784
    {
785
        foreach ($keys as $key) {
786
            $params = explode(':', $key);
787
            $key = array_shift($params);
788
            $sql = trim($this->getConf($key));
789
790
            // check if sql is set
791
            if (!$sql) return false;
792
            // check if needed params are there
793
            foreach ($params as $param) {
794
                if (strpos($sql, ":$param") === false) return false;
795
            }
796
        }
797
798
        return true;
799
    }
800
801
    /**
802
     * create an approximation of the SQL string with parameters replaced
803
     *
804
     * @param string $sql
805
     * @param array $params
806
     * @param bool $htmlescape Should the result be escaped for output in HTML?
807
     * @return string
808
     */
809
    protected function debugSQL($sql, $params, $htmlescape = true)
810
    {
811
        foreach ($params as $key => $val) {
812
            if (is_int($val)) {
813
                $val = $this->pdo->quote($val, PDO::PARAM_INT);
814
            } elseif (is_bool($val)) {
815
                $val = $this->pdo->quote($val, PDO::PARAM_BOOL);
816
            } elseif (is_null($val)) {
817
                $val = 'NULL';
818
            } else {
819
                $val = $this->pdo->quote($val);
820
            }
821
            $sql = str_replace($key, $val, $sql);
822
        }
823
        if ($htmlescape) $sql = hsc($sql);
824
        return $sql;
825
    }
826
}
827
828
// vim:ts=4:sw=4:et:
829