xref: /dokuwiki/lib/plugins/authpdo/auth.php (revision 6a1b9bfe5975d7b31163c7b42188cc91ae1d445a)
1f64dbc90SAndreas Gohr<?php
2f64dbc90SAndreas Gohr/**
3f64dbc90SAndreas Gohr * DokuWiki Plugin authpdo (Auth Component)
4f64dbc90SAndreas Gohr *
5f64dbc90SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6f64dbc90SAndreas Gohr * @author  Andreas Gohr <andi@splitbrain.org>
7f64dbc90SAndreas Gohr */
8f64dbc90SAndreas Gohr
9f64dbc90SAndreas Gohr// must be run within Dokuwiki
10f64dbc90SAndreas Gohrif(!defined('DOKU_INC')) die();
11f64dbc90SAndreas Gohr
120d586afdSAndreas Gohr/**
130d586afdSAndreas Gohr * Class auth_plugin_authpdo
140d586afdSAndreas Gohr */
15f64dbc90SAndreas Gohrclass auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
16f64dbc90SAndreas Gohr
17f64dbc90SAndreas Gohr    /** @var PDO */
18f64dbc90SAndreas Gohr    protected $pdo;
19f64dbc90SAndreas Gohr
200cec3e2aSAndreas Gohr    /** @var null|array The list of all groups */
210cec3e2aSAndreas Gohr    protected $groupcache = null;
220cec3e2aSAndreas Gohr
23f64dbc90SAndreas Gohr    /**
24f64dbc90SAndreas Gohr     * Constructor.
25f64dbc90SAndreas Gohr     */
26f64dbc90SAndreas Gohr    public function __construct() {
27f64dbc90SAndreas Gohr        parent::__construct(); // for compatibility
28f64dbc90SAndreas Gohr
29f64dbc90SAndreas Gohr        if(!class_exists('PDO')) {
30f64dbc90SAndreas Gohr            $this->_debug('PDO extension for PHP not found.', -1, __LINE__);
31f64dbc90SAndreas Gohr            $this->success = false;
32f64dbc90SAndreas Gohr            return;
33f64dbc90SAndreas Gohr        }
34f64dbc90SAndreas Gohr
35f64dbc90SAndreas Gohr        if(!$this->getConf('dsn')) {
36f64dbc90SAndreas Gohr            $this->_debug('No DSN specified', -1, __LINE__);
37f64dbc90SAndreas Gohr            $this->success = false;
38f64dbc90SAndreas Gohr            return;
39f64dbc90SAndreas Gohr        }
40f64dbc90SAndreas Gohr
41f64dbc90SAndreas Gohr        try {
42f64dbc90SAndreas Gohr            $this->pdo = new PDO(
43f64dbc90SAndreas Gohr                $this->getConf('dsn'),
44f64dbc90SAndreas Gohr                $this->getConf('user'),
450cc11d97SAndreas Gohr                conf_decodeString($this->getConf('pass')),
46f64dbc90SAndreas Gohr                array(
4770a89417SAndreas Gohr                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // always fetch as array
4870a89417SAndreas Gohr                    PDO::ATTR_EMULATE_PREPARES => true, // emulating prepares allows us to reuse param names
495de3a6a5SAndreas Gohr                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
50f64dbc90SAndreas Gohr                )
51f64dbc90SAndreas Gohr            );
52f64dbc90SAndreas Gohr        } catch(PDOException $e) {
53f64dbc90SAndreas Gohr            $this->_debug($e);
54c27579a6SAndreas Gohr            msg($this->getLang('connectfail'), -1);
55f64dbc90SAndreas Gohr            $this->success = false;
56f64dbc90SAndreas Gohr            return;
57f64dbc90SAndreas Gohr        }
58f64dbc90SAndreas Gohr
590d586afdSAndreas Gohr        // can Users be created?
600d586afdSAndreas Gohr        $this->cando['addUser'] = $this->_chkcnf(
610d586afdSAndreas Gohr            array(
620d586afdSAndreas Gohr                'select-user',
630d586afdSAndreas Gohr                'select-user-groups',
640d586afdSAndreas Gohr                'select-groups',
650d586afdSAndreas Gohr                'insert-user',
660d586afdSAndreas Gohr                'insert-group',
670d586afdSAndreas Gohr                'join-group'
680d586afdSAndreas Gohr            )
690d586afdSAndreas Gohr        );
70f64dbc90SAndreas Gohr
710d586afdSAndreas Gohr        // can Users be deleted?
720d586afdSAndreas Gohr        $this->cando['delUser'] = $this->_chkcnf(
730d586afdSAndreas Gohr            array(
740d586afdSAndreas Gohr                'select-user',
750d586afdSAndreas Gohr                'select-user-groups',
760d586afdSAndreas Gohr                'select-groups',
777f89f089SAndreas Gohr                'leave-group',
787f89f089SAndreas Gohr                'delete-user'
790d586afdSAndreas Gohr            )
800d586afdSAndreas Gohr        );
810d586afdSAndreas Gohr
820d586afdSAndreas Gohr        // can login names be changed?
830d586afdSAndreas Gohr        $this->cando['modLogin'] = $this->_chkcnf(
840d586afdSAndreas Gohr            array(
850d586afdSAndreas Gohr                'select-user',
860d586afdSAndreas Gohr                'select-user-groups',
870d586afdSAndreas Gohr                'update-user-login'
880d586afdSAndreas Gohr            )
890d586afdSAndreas Gohr        );
900d586afdSAndreas Gohr
910d586afdSAndreas Gohr        // can passwords be changed?
920d586afdSAndreas Gohr        $this->cando['modPass'] = $this->_chkcnf(
930d586afdSAndreas Gohr            array(
940d586afdSAndreas Gohr                'select-user',
950d586afdSAndreas Gohr                'select-user-groups',
960d586afdSAndreas Gohr                'update-user-pass'
970d586afdSAndreas Gohr            )
980d586afdSAndreas Gohr        );
990d586afdSAndreas Gohr
100ad4d5631SAndreas Gohr        // can real names be changed?
101ad4d5631SAndreas Gohr        $this->cando['modName'] = $this->_chkcnf(
1020d586afdSAndreas Gohr            array(
1030d586afdSAndreas Gohr                'select-user',
1040d586afdSAndreas Gohr                'select-user-groups',
105ad4d5631SAndreas Gohr                'update-user-info:name'
106ad4d5631SAndreas Gohr            )
107ad4d5631SAndreas Gohr        );
108ad4d5631SAndreas Gohr
109ad4d5631SAndreas Gohr        // can real email be changed?
110ad4d5631SAndreas Gohr        $this->cando['modMail'] = $this->_chkcnf(
111ad4d5631SAndreas Gohr            array(
112ad4d5631SAndreas Gohr                'select-user',
113ad4d5631SAndreas Gohr                'select-user-groups',
114ad4d5631SAndreas Gohr                'update-user-info:mail'
1150d586afdSAndreas Gohr            )
1160d586afdSAndreas Gohr        );
1170d586afdSAndreas Gohr
1180d586afdSAndreas Gohr        // can groups be changed?
1190d586afdSAndreas Gohr        $this->cando['modGroups'] = $this->_chkcnf(
1200d586afdSAndreas Gohr            array(
1210d586afdSAndreas Gohr                'select-user',
1220d586afdSAndreas Gohr                'select-user-groups',
1230d586afdSAndreas Gohr                'select-groups',
1240d586afdSAndreas Gohr                'leave-group',
1250d586afdSAndreas Gohr                'join-group',
1260d586afdSAndreas Gohr                'insert-group'
1270d586afdSAndreas Gohr            )
1280d586afdSAndreas Gohr        );
1290d586afdSAndreas Gohr
1300d586afdSAndreas Gohr        // can a filtered list of users be retrieved?
1310d586afdSAndreas Gohr        $this->cando['getUsers'] = $this->_chkcnf(
1320d586afdSAndreas Gohr            array(
1330d586afdSAndreas Gohr                'list-users'
1340d586afdSAndreas Gohr            )
1350d586afdSAndreas Gohr        );
1360d586afdSAndreas Gohr
1370d586afdSAndreas Gohr        // can the number of users be retrieved?
1380d586afdSAndreas Gohr        $this->cando['getUserCount'] = $this->_chkcnf(
1390d586afdSAndreas Gohr            array(
1400d586afdSAndreas Gohr                'count-users'
1410d586afdSAndreas Gohr            )
1420d586afdSAndreas Gohr        );
1430d586afdSAndreas Gohr
1440d586afdSAndreas Gohr        // can a list of available groups be retrieved?
1450d586afdSAndreas Gohr        $this->cando['getGroups'] = $this->_chkcnf(
1460d586afdSAndreas Gohr            array(
1470d586afdSAndreas Gohr                'select-groups'
1480d586afdSAndreas Gohr            )
1490d586afdSAndreas Gohr        );
1500d586afdSAndreas Gohr
151f64dbc90SAndreas Gohr        $this->success = true;
152f64dbc90SAndreas Gohr    }
153f64dbc90SAndreas Gohr
154f64dbc90SAndreas Gohr    /**
155f64dbc90SAndreas Gohr     * Check user+password
156f64dbc90SAndreas Gohr     *
157f64dbc90SAndreas Gohr     * @param   string $user the user name
158f64dbc90SAndreas Gohr     * @param   string $pass the clear text password
159f64dbc90SAndreas Gohr     * @return  bool
160f64dbc90SAndreas Gohr     */
161f64dbc90SAndreas Gohr    public function checkPass($user, $pass) {
162f64dbc90SAndreas Gohr
163397d62a2SAndreas Gohr        $userdata = $this->_selectUser($user);
164397d62a2SAndreas Gohr        if($userdata == false) return false;
165f64dbc90SAndreas Gohr
166397d62a2SAndreas Gohr        // password checking done in SQL?
167397d62a2SAndreas Gohr        if($this->_chkcnf(array('check-pass'))) {
168397d62a2SAndreas Gohr            $userdata['clear'] = $pass;
169397d62a2SAndreas Gohr            $userdata['hash'] = auth_cryptPassword($pass);
170397d62a2SAndreas Gohr            $result = $this->_query($this->getConf('check-pass'), $userdata);
171397d62a2SAndreas Gohr            if($result === false) return false;
172397d62a2SAndreas Gohr            return (count($result) == 1);
173397d62a2SAndreas Gohr        }
174397d62a2SAndreas Gohr
175397d62a2SAndreas Gohr        // we do password checking on our own
176397d62a2SAndreas Gohr        if(isset($userdata['hash'])) {
177f64dbc90SAndreas Gohr            // hashed password
178f64dbc90SAndreas Gohr            $passhash = new PassHash();
179397d62a2SAndreas Gohr            return $passhash->verify_hash($pass, $userdata['hash']);
180f64dbc90SAndreas Gohr        } else {
181f64dbc90SAndreas Gohr            // clear text password in the database O_o
182d5c0422fSAndreas Gohr            return ($pass === $userdata['clear']);
183f64dbc90SAndreas Gohr        }
184f64dbc90SAndreas Gohr    }
185f64dbc90SAndreas Gohr
186f64dbc90SAndreas Gohr    /**
187f64dbc90SAndreas Gohr     * Return user info
188f64dbc90SAndreas Gohr     *
189f64dbc90SAndreas Gohr     * Returns info about the given user needs to contain
190f64dbc90SAndreas Gohr     * at least these fields:
191f64dbc90SAndreas Gohr     *
192f64dbc90SAndreas Gohr     * name string  full name of the user
193f64dbc90SAndreas Gohr     * mail string  email addres of the user
194f64dbc90SAndreas Gohr     * grps array   list of groups the user is in
195f64dbc90SAndreas Gohr     *
196f64dbc90SAndreas Gohr     * @param   string $user the user name
197f64dbc90SAndreas Gohr     * @param   bool $requireGroups whether or not the returned data must include groups
198358942b5SAndreas Gohr     * @return array|bool containing user data or false
199f64dbc90SAndreas Gohr     */
200f64dbc90SAndreas Gohr    public function getUserData($user, $requireGroups = true) {
201f64dbc90SAndreas Gohr        $data = $this->_selectUser($user);
202f64dbc90SAndreas Gohr        if($data == false) return false;
203f64dbc90SAndreas Gohr
20470a89417SAndreas Gohr        if(isset($data['hash'])) unset($data['hash']);
20570a89417SAndreas Gohr        if(isset($data['clean'])) unset($data['clean']);
206f64dbc90SAndreas Gohr
20770a89417SAndreas Gohr        if($requireGroups) {
20870a89417SAndreas Gohr            $data['grps'] = $this->_selectUserGroups($data);
2095de3a6a5SAndreas Gohr            if($data['grps'] === false) return false;
210f64dbc90SAndreas Gohr        }
211f64dbc90SAndreas Gohr
212f64dbc90SAndreas Gohr        return $data;
213f64dbc90SAndreas Gohr    }
214f64dbc90SAndreas Gohr
215f64dbc90SAndreas Gohr    /**
216f64dbc90SAndreas Gohr     * Create a new User [implement only where required/possible]
217f64dbc90SAndreas Gohr     *
218f64dbc90SAndreas Gohr     * Returns false if the user already exists, null when an error
219f64dbc90SAndreas Gohr     * occurred and true if everything went well.
220f64dbc90SAndreas Gohr     *
221f64dbc90SAndreas Gohr     * The new user HAS TO be added to the default group by this
222f64dbc90SAndreas Gohr     * function!
223f64dbc90SAndreas Gohr     *
224f64dbc90SAndreas Gohr     * Set addUser capability when implemented
225f64dbc90SAndreas Gohr     *
226f64dbc90SAndreas Gohr     * @param  string $user
2275de3a6a5SAndreas Gohr     * @param  string $clear
228f64dbc90SAndreas Gohr     * @param  string $name
229f64dbc90SAndreas Gohr     * @param  string $mail
230f64dbc90SAndreas Gohr     * @param  null|array $grps
231f64dbc90SAndreas Gohr     * @return bool|null
232f64dbc90SAndreas Gohr     */
2335de3a6a5SAndreas Gohr    public function createUser($user, $clear, $name, $mail, $grps = null) {
2345de3a6a5SAndreas Gohr        global $conf;
2355de3a6a5SAndreas Gohr
2365de3a6a5SAndreas Gohr        if(($info = $this->getUserData($user, false)) !== false) {
2375de3a6a5SAndreas Gohr            msg($this->getLang('userexists'), -1);
2385de3a6a5SAndreas Gohr            return false; // user already exists
2395de3a6a5SAndreas Gohr        }
2405de3a6a5SAndreas Gohr
2415de3a6a5SAndreas Gohr        // prepare data
2425de3a6a5SAndreas Gohr        if($grps == null) $grps = array();
24307a11e2aSAndreas Gohr        array_unshift($grps, $conf['defaultgroup']);
2445de3a6a5SAndreas Gohr        $grps = array_unique($grps);
2455de3a6a5SAndreas Gohr        $hash = auth_cryptPassword($clear);
2465de3a6a5SAndreas Gohr        $userdata = compact('user', 'clear', 'hash', 'name', 'mail');
2475de3a6a5SAndreas Gohr
2485de3a6a5SAndreas Gohr        // action protected by transaction
2495de3a6a5SAndreas Gohr        $this->pdo->beginTransaction();
2505de3a6a5SAndreas Gohr        {
2515de3a6a5SAndreas Gohr            // insert the user
2525de3a6a5SAndreas Gohr            $ok = $this->_query($this->getConf('insert-user'), $userdata);
2535de3a6a5SAndreas Gohr            if($ok === false) goto FAIL;
2545de3a6a5SAndreas Gohr            $userdata = $this->getUserData($user, false);
2555de3a6a5SAndreas Gohr            if($userdata === false) goto FAIL;
2565de3a6a5SAndreas Gohr
2575de3a6a5SAndreas Gohr            // create all groups that do not exist, the refetch the groups
2585de3a6a5SAndreas Gohr            $allgroups = $this->_selectGroups();
2595de3a6a5SAndreas Gohr            foreach($grps as $group) {
2605de3a6a5SAndreas Gohr                if(!isset($allgroups[$group])) {
2616459f496SAndreas Gohr                    $ok = $this->addGroup($group);
2625de3a6a5SAndreas Gohr                    if($ok === false) goto FAIL;
2635de3a6a5SAndreas Gohr                }
2645de3a6a5SAndreas Gohr            }
2655de3a6a5SAndreas Gohr            $allgroups = $this->_selectGroups();
2665de3a6a5SAndreas Gohr
2675de3a6a5SAndreas Gohr            // add user to the groups
2685de3a6a5SAndreas Gohr            foreach($grps as $group) {
2695de3a6a5SAndreas Gohr                $ok = $this->_joinGroup($userdata, $allgroups[$group]);
2705de3a6a5SAndreas Gohr                if($ok === false) goto FAIL;
2715de3a6a5SAndreas Gohr            }
2725de3a6a5SAndreas Gohr        }
2735de3a6a5SAndreas Gohr        $this->pdo->commit();
2745de3a6a5SAndreas Gohr        return true;
2755de3a6a5SAndreas Gohr
2765de3a6a5SAndreas Gohr        // something went wrong, rollback
2775de3a6a5SAndreas Gohr        FAIL:
2785de3a6a5SAndreas Gohr        $this->pdo->rollBack();
2795de3a6a5SAndreas Gohr        $this->_debug('Transaction rolled back', 0, __LINE__);
280c27579a6SAndreas Gohr        msg($this->getLang('writefail'), -1);
2815de3a6a5SAndreas Gohr        return null; // return error
2825de3a6a5SAndreas Gohr    }
283f64dbc90SAndreas Gohr
284f64dbc90SAndreas Gohr    /**
2854fb8dfabSAndreas Gohr     * Modify user data
286f64dbc90SAndreas Gohr     *
287f64dbc90SAndreas Gohr     * @param   string $user nick of the user to be changed
288f64dbc90SAndreas Gohr     * @param   array $changes array of field/value pairs to be changed (password will be clear text)
289f64dbc90SAndreas Gohr     * @return  bool
290f64dbc90SAndreas Gohr     */
2914fb8dfabSAndreas Gohr    public function modifyUser($user, $changes) {
2924fb8dfabSAndreas Gohr        // secure everything in transaction
2934fb8dfabSAndreas Gohr        $this->pdo->beginTransaction();
2944fb8dfabSAndreas Gohr        {
2954fb8dfabSAndreas Gohr            $olddata = $this->getUserData($user);
2964fb8dfabSAndreas Gohr            $oldgroups = $olddata['grps'];
2974fb8dfabSAndreas Gohr            unset($olddata['grps']);
2984fb8dfabSAndreas Gohr
2994fb8dfabSAndreas Gohr            // changing the user name?
3004fb8dfabSAndreas Gohr            if(isset($changes['user'])) {
3014fb8dfabSAndreas Gohr                if($this->getUserData($changes['user'], false)) goto FAIL;
3024fb8dfabSAndreas Gohr                $params = $olddata;
3034fb8dfabSAndreas Gohr                $params['newlogin'] = $changes['user'];
3044fb8dfabSAndreas Gohr
3054fb8dfabSAndreas Gohr                $ok = $this->_query($this->getConf('update-user-login'), $params);
3064fb8dfabSAndreas Gohr                if($ok === false) goto FAIL;
3074fb8dfabSAndreas Gohr            }
3084fb8dfabSAndreas Gohr
3094fb8dfabSAndreas Gohr            // changing the password?
3104fb8dfabSAndreas Gohr            if(isset($changes['pass'])) {
3114fb8dfabSAndreas Gohr                $params = $olddata;
3124fb8dfabSAndreas Gohr                $params['clear'] = $changes['pass'];
3134fb8dfabSAndreas Gohr                $params['hash'] = auth_cryptPassword($changes['pass']);
3144fb8dfabSAndreas Gohr
3154fb8dfabSAndreas Gohr                $ok = $this->_query($this->getConf('update-user-pass'), $params);
3164fb8dfabSAndreas Gohr                if($ok === false) goto FAIL;
3174fb8dfabSAndreas Gohr            }
3184fb8dfabSAndreas Gohr
3194fb8dfabSAndreas Gohr            // changing info?
3204fb8dfabSAndreas Gohr            if(isset($changes['mail']) || isset($changes['name'])) {
3214fb8dfabSAndreas Gohr                $params = $olddata;
3224fb8dfabSAndreas Gohr                if(isset($changes['mail'])) $params['mail'] = $changes['mail'];
3234fb8dfabSAndreas Gohr                if(isset($changes['name'])) $params['name'] = $changes['name'];
3244fb8dfabSAndreas Gohr
3254fb8dfabSAndreas Gohr                $ok = $this->_query($this->getConf('update-user-info'), $params);
3264fb8dfabSAndreas Gohr                if($ok === false) goto FAIL;
3274fb8dfabSAndreas Gohr            }
3284fb8dfabSAndreas Gohr
3294fb8dfabSAndreas Gohr            // changing groups?
3304fb8dfabSAndreas Gohr            if(isset($changes['grps'])) {
3314fb8dfabSAndreas Gohr                $allgroups = $this->_selectGroups();
3324fb8dfabSAndreas Gohr
3334fb8dfabSAndreas Gohr                // remove membership for previous groups
3344fb8dfabSAndreas Gohr                foreach($oldgroups as $group) {
335358942b5SAndreas Gohr                    if(!in_array($group, $changes['grps']) && isset($allgroups[$group])) {
3364fb8dfabSAndreas Gohr                        $ok = $this->_leaveGroup($olddata, $allgroups[$group]);
3374fb8dfabSAndreas Gohr                        if($ok === false) goto FAIL;
3384fb8dfabSAndreas Gohr                    }
3394fb8dfabSAndreas Gohr                }
3404fb8dfabSAndreas Gohr
3414fb8dfabSAndreas Gohr                // create all new groups that are missing
3424fb8dfabSAndreas Gohr                $added = 0;
3434fb8dfabSAndreas Gohr                foreach($changes['grps'] as $group) {
3444fb8dfabSAndreas Gohr                    if(!isset($allgroups[$group])) {
3456459f496SAndreas Gohr                        $ok = $this->addGroup($group);
3464fb8dfabSAndreas Gohr                        if($ok === false) goto FAIL;
3474fb8dfabSAndreas Gohr                        $added++;
3484fb8dfabSAndreas Gohr                    }
3494fb8dfabSAndreas Gohr                }
3504fb8dfabSAndreas Gohr                // reload group info
3514fb8dfabSAndreas Gohr                if($added > 0) $allgroups = $this->_selectGroups();
3524fb8dfabSAndreas Gohr
3534fb8dfabSAndreas Gohr                // add membership for new groups
3544fb8dfabSAndreas Gohr                foreach($changes['grps'] as $group) {
3554fb8dfabSAndreas Gohr                    if(!in_array($group, $oldgroups)) {
3564fb8dfabSAndreas Gohr                        $ok = $this->_joinGroup($olddata, $allgroups[$group]);
3574fb8dfabSAndreas Gohr                        if($ok === false) goto FAIL;
3584fb8dfabSAndreas Gohr                    }
3594fb8dfabSAndreas Gohr                }
3604fb8dfabSAndreas Gohr            }
3614fb8dfabSAndreas Gohr
3624fb8dfabSAndreas Gohr        }
3634fb8dfabSAndreas Gohr        $this->pdo->commit();
3644fb8dfabSAndreas Gohr        return true;
3654fb8dfabSAndreas Gohr
3664fb8dfabSAndreas Gohr        // something went wrong, rollback
3674fb8dfabSAndreas Gohr        FAIL:
3684fb8dfabSAndreas Gohr        $this->pdo->rollBack();
3694fb8dfabSAndreas Gohr        $this->_debug('Transaction rolled back', 0, __LINE__);
370c27579a6SAndreas Gohr        msg($this->getLang('writefail'), -1);
3714fb8dfabSAndreas Gohr        return false; // return error
3724fb8dfabSAndreas Gohr    }
373f64dbc90SAndreas Gohr
374f64dbc90SAndreas Gohr    /**
375e19be516SAndreas Gohr     * Delete one or more users
376f64dbc90SAndreas Gohr     *
377f64dbc90SAndreas Gohr     * Set delUser capability when implemented
378f64dbc90SAndreas Gohr     *
379f64dbc90SAndreas Gohr     * @param   array $users
380f64dbc90SAndreas Gohr     * @return  int    number of users deleted
381f64dbc90SAndreas Gohr     */
382e19be516SAndreas Gohr    public function deleteUsers($users) {
383e19be516SAndreas Gohr        $count = 0;
384e19be516SAndreas Gohr        foreach($users as $user) {
385e19be516SAndreas Gohr            if($this->_deleteUser($user)) $count++;
386e19be516SAndreas Gohr        }
387e19be516SAndreas Gohr        return $count;
388e19be516SAndreas Gohr    }
389f64dbc90SAndreas Gohr
390f64dbc90SAndreas Gohr    /**
391f64dbc90SAndreas Gohr     * Bulk retrieval of user data [implement only where required/possible]
392f64dbc90SAndreas Gohr     *
393f64dbc90SAndreas Gohr     * Set getUsers capability when implemented
394f64dbc90SAndreas Gohr     *
395f64dbc90SAndreas Gohr     * @param   int $start index of first user to be returned
396f64dbc90SAndreas Gohr     * @param   int $limit max number of users to be returned
397f64dbc90SAndreas Gohr     * @param   array $filter array of field/pattern pairs, null for no filter
398f64dbc90SAndreas Gohr     * @return  array list of userinfo (refer getUserData for internal userinfo details)
399f64dbc90SAndreas Gohr     */
4006459f496SAndreas Gohr    public function retrieveUsers($start = 0, $limit = -1, $filter = null) {
4016459f496SAndreas Gohr        if($limit < 0) $limit = 10000; // we don't support no limit
4026459f496SAndreas Gohr        if(is_null($filter)) $filter = array();
4036459f496SAndreas Gohr
40412c7f5c3SAndreas Gohr        if(isset($filter['grps'])) $filter['group'] = $filter['grps'];
4056459f496SAndreas Gohr        foreach(array('user', 'name', 'mail', 'group') as $key) {
4066459f496SAndreas Gohr            if(!isset($filter[$key])) {
4076459f496SAndreas Gohr                $filter[$key] = '%';
4086459f496SAndreas Gohr            } else {
4096459f496SAndreas Gohr                $filter[$key] = '%' . $filter[$key] . '%';
4106459f496SAndreas Gohr            }
4116459f496SAndreas Gohr        }
41214119d44SAndreas Gohr        $filter['start'] = (int) $start;
41314119d44SAndreas Gohr        $filter['end'] = (int) $start + $limit;
41414119d44SAndreas Gohr        $filter['limit'] = (int) $limit;
4156459f496SAndreas Gohr
4166459f496SAndreas Gohr        $result = $this->_query($this->getConf('list-users'), $filter);
4176459f496SAndreas Gohr        if(!$result) return array();
4186459f496SAndreas Gohr        $users = array();
4196459f496SAndreas Gohr        foreach($result as $row) {
4206459f496SAndreas Gohr            if(!isset($row['user'])) {
4216459f496SAndreas Gohr                $this->_debug("Statement did not return 'user' attribute", -1, __LINE__);
4226459f496SAndreas Gohr                return array();
4236459f496SAndreas Gohr            }
4243e2a8145SAndreas Gohr            $users[] = $this->getUserData($row['user']);
4256459f496SAndreas Gohr        }
4266459f496SAndreas Gohr        return $users;
4276459f496SAndreas Gohr    }
428f64dbc90SAndreas Gohr
429f64dbc90SAndreas Gohr    /**
430f64dbc90SAndreas Gohr     * Return a count of the number of user which meet $filter criteria
431f64dbc90SAndreas Gohr     *
432f64dbc90SAndreas Gohr     * @param  array $filter array of field/pattern pairs, empty array for no filter
433f64dbc90SAndreas Gohr     * @return int
434f64dbc90SAndreas Gohr     */
4356459f496SAndreas Gohr    public function getUserCount($filter = array()) {
4366459f496SAndreas Gohr        if(is_null($filter)) $filter = array();
4376459f496SAndreas Gohr
43812c7f5c3SAndreas Gohr        if(isset($filter['grps'])) $filter['group'] = $filter['grps'];
4396459f496SAndreas Gohr        foreach(array('user', 'name', 'mail', 'group') as $key) {
4406459f496SAndreas Gohr            if(!isset($filter[$key])) {
4416459f496SAndreas Gohr                $filter[$key] = '%';
4426459f496SAndreas Gohr            } else {
4436459f496SAndreas Gohr                $filter[$key] = '%' . $filter[$key] . '%';
4446459f496SAndreas Gohr            }
4456459f496SAndreas Gohr        }
4466459f496SAndreas Gohr
4476459f496SAndreas Gohr        $result = $this->_query($this->getConf('count-users'), $filter);
4486459f496SAndreas Gohr        if(!$result || !isset($result[0]['count'])) {
4496459f496SAndreas Gohr            $this->_debug("Statement did not return 'count' attribute", -1, __LINE__);
4506459f496SAndreas Gohr        }
451f3c1c207SAndreas Gohr        return (int) $result[0]['count'];
4526459f496SAndreas Gohr    }
453f64dbc90SAndreas Gohr
454f64dbc90SAndreas Gohr    /**
4556459f496SAndreas Gohr     * Create a new group with the given name
456f64dbc90SAndreas Gohr     *
457f64dbc90SAndreas Gohr     * @param string $group
458f64dbc90SAndreas Gohr     * @return bool
459f64dbc90SAndreas Gohr     */
4606459f496SAndreas Gohr    public function addGroup($group) {
4616459f496SAndreas Gohr        $sql = $this->getConf('insert-group');
4626459f496SAndreas Gohr
4636459f496SAndreas Gohr        $result = $this->_query($sql, array(':group' => $group));
4640cec3e2aSAndreas Gohr        $this->_clearGroupCache();
4656459f496SAndreas Gohr        if($result === false) return false;
4666459f496SAndreas Gohr        return true;
4676459f496SAndreas Gohr    }
468f64dbc90SAndreas Gohr
469f64dbc90SAndreas Gohr    /**
4705de3a6a5SAndreas Gohr     * Retrieve groups
471f64dbc90SAndreas Gohr     *
472f64dbc90SAndreas Gohr     * Set getGroups capability when implemented
473f64dbc90SAndreas Gohr     *
474f64dbc90SAndreas Gohr     * @param   int $start
475f64dbc90SAndreas Gohr     * @param   int $limit
476f64dbc90SAndreas Gohr     * @return  array
477f64dbc90SAndreas Gohr     */
4785de3a6a5SAndreas Gohr    public function retrieveGroups($start = 0, $limit = 0) {
4795de3a6a5SAndreas Gohr        $groups = array_keys($this->_selectGroups());
4805de3a6a5SAndreas Gohr        if($groups === false) return array();
481f64dbc90SAndreas Gohr
4825de3a6a5SAndreas Gohr        if(!$limit) {
4835de3a6a5SAndreas Gohr            return array_splice($groups, $start);
4845de3a6a5SAndreas Gohr        } else {
4855de3a6a5SAndreas Gohr            return array_splice($groups, $start, $limit);
486f64dbc90SAndreas Gohr        }
487f64dbc90SAndreas Gohr    }
488f64dbc90SAndreas Gohr
489f64dbc90SAndreas Gohr    /**
490f64dbc90SAndreas Gohr     * Select data of a specified user
491f64dbc90SAndreas Gohr     *
4925de3a6a5SAndreas Gohr     * @param string $user the user name
4935de3a6a5SAndreas Gohr     * @return bool|array user data, false on error
494f64dbc90SAndreas Gohr     */
495f64dbc90SAndreas Gohr    protected function _selectUser($user) {
496f64dbc90SAndreas Gohr        $sql = $this->getConf('select-user');
497f64dbc90SAndreas Gohr
4985de3a6a5SAndreas Gohr        $result = $this->_query($sql, array(':user' => $user));
49970a89417SAndreas Gohr        if(!$result) return false;
500f64dbc90SAndreas Gohr
50170a89417SAndreas Gohr        if(count($result) > 1) {
502f64dbc90SAndreas Gohr            $this->_debug('Found more than one matching user', -1, __LINE__);
503f64dbc90SAndreas Gohr            return false;
504f64dbc90SAndreas Gohr        }
505f64dbc90SAndreas Gohr
506f64dbc90SAndreas Gohr        $data = array_shift($result);
507f64dbc90SAndreas Gohr        $dataok = true;
508f64dbc90SAndreas Gohr
509f64dbc90SAndreas Gohr        if(!isset($data['user'])) {
510f64dbc90SAndreas Gohr            $this->_debug("Statement did not return 'user' attribute", -1, __LINE__);
511f64dbc90SAndreas Gohr            $dataok = false;
512f64dbc90SAndreas Gohr        }
513397d62a2SAndreas Gohr        if(!isset($data['hash']) && !isset($data['clear']) && !$this->_chkcnf(array('check-pass'))) {
514f64dbc90SAndreas Gohr            $this->_debug("Statement did not return 'clear' or 'hash' attribute", -1, __LINE__);
515f64dbc90SAndreas Gohr            $dataok = false;
516f64dbc90SAndreas Gohr        }
517f64dbc90SAndreas Gohr        if(!isset($data['name'])) {
518f64dbc90SAndreas Gohr            $this->_debug("Statement did not return 'name' attribute", -1, __LINE__);
519f64dbc90SAndreas Gohr            $dataok = false;
520f64dbc90SAndreas Gohr        }
521f64dbc90SAndreas Gohr        if(!isset($data['mail'])) {
522f64dbc90SAndreas Gohr            $this->_debug("Statement did not return 'mail' attribute", -1, __LINE__);
523f64dbc90SAndreas Gohr            $dataok = false;
524f64dbc90SAndreas Gohr        }
525f64dbc90SAndreas Gohr
526f64dbc90SAndreas Gohr        if(!$dataok) return false;
527f64dbc90SAndreas Gohr        return $data;
528f64dbc90SAndreas Gohr    }
529f64dbc90SAndreas Gohr
530f64dbc90SAndreas Gohr    /**
531e19be516SAndreas Gohr     * Delete a user after removing all their group memberships
532e19be516SAndreas Gohr     *
533e19be516SAndreas Gohr     * @param string $user
534e19be516SAndreas Gohr     * @return bool true when the user was deleted
535e19be516SAndreas Gohr     */
536e19be516SAndreas Gohr    protected function _deleteUser($user) {
537e19be516SAndreas Gohr        $this->pdo->beginTransaction();
538e19be516SAndreas Gohr        {
539e19be516SAndreas Gohr            $userdata = $this->getUserData($user);
540e19be516SAndreas Gohr            if($userdata === false) goto FAIL;
541e19be516SAndreas Gohr            $allgroups = $this->_selectGroups();
542e19be516SAndreas Gohr
543e19be516SAndreas Gohr            // remove group memberships (ignore errors)
544e19be516SAndreas Gohr            foreach($userdata['grps'] as $group) {
545358942b5SAndreas Gohr                if(isset($allgroups[$group])) {
546e19be516SAndreas Gohr                    $this->_leaveGroup($userdata, $allgroups[$group]);
547e19be516SAndreas Gohr                }
548358942b5SAndreas Gohr            }
549e19be516SAndreas Gohr
550e19be516SAndreas Gohr            $ok = $this->_query($this->getConf('delete-user'), $userdata);
551e19be516SAndreas Gohr            if($ok === false) goto FAIL;
552e19be516SAndreas Gohr        }
553e19be516SAndreas Gohr        $this->pdo->commit();
554e19be516SAndreas Gohr        return true;
555e19be516SAndreas Gohr
556e19be516SAndreas Gohr        FAIL:
557e19be516SAndreas Gohr        $this->pdo->rollBack();
558e19be516SAndreas Gohr        return false;
559e19be516SAndreas Gohr    }
560e19be516SAndreas Gohr
561e19be516SAndreas Gohr    /**
56270a89417SAndreas Gohr     * Select all groups of a user
56370a89417SAndreas Gohr     *
56470a89417SAndreas Gohr     * @param array $userdata The userdata as returned by _selectUser()
5655de3a6a5SAndreas Gohr     * @return array|bool list of group names, false on error
56670a89417SAndreas Gohr     */
56770a89417SAndreas Gohr    protected function _selectUserGroups($userdata) {
56870a89417SAndreas Gohr        global $conf;
56970a89417SAndreas Gohr        $sql = $this->getConf('select-user-groups');
5705de3a6a5SAndreas Gohr        $result = $this->_query($sql, $userdata);
5715de3a6a5SAndreas Gohr        if($result === false) return false;
57270a89417SAndreas Gohr
57370a89417SAndreas Gohr        $groups = array($conf['defaultgroup']); // always add default config
5745de3a6a5SAndreas Gohr        foreach($result as $row) {
5755de3a6a5SAndreas Gohr            if(!isset($row['group'])) {
5765de3a6a5SAndreas Gohr                $this->_debug("No 'group' field returned in select-user-groups statement");
5775de3a6a5SAndreas Gohr                return false;
5785de3a6a5SAndreas Gohr            }
57970a89417SAndreas Gohr            $groups[] = $row['group'];
58070a89417SAndreas Gohr        }
58170a89417SAndreas Gohr
58270a89417SAndreas Gohr        $groups = array_unique($groups);
58370a89417SAndreas Gohr        sort($groups);
58470a89417SAndreas Gohr        return $groups;
58570a89417SAndreas Gohr    }
58670a89417SAndreas Gohr
58770a89417SAndreas Gohr    /**
5885de3a6a5SAndreas Gohr     * Select all available groups
5895de3a6a5SAndreas Gohr     *
5905de3a6a5SAndreas Gohr     * @return array|bool list of all available groups and their properties
5915de3a6a5SAndreas Gohr     */
5925de3a6a5SAndreas Gohr    protected function _selectGroups() {
5930cec3e2aSAndreas Gohr        if($this->groupcache) return $this->groupcache;
5940cec3e2aSAndreas Gohr
5955de3a6a5SAndreas Gohr        $sql = $this->getConf('select-groups');
5965de3a6a5SAndreas Gohr        $result = $this->_query($sql);
5975de3a6a5SAndreas Gohr        if($result === false) return false;
5985de3a6a5SAndreas Gohr
5995de3a6a5SAndreas Gohr        $groups = array();
6005de3a6a5SAndreas Gohr        foreach($result as $row) {
6015de3a6a5SAndreas Gohr            if(!isset($row['group'])) {
6025de3a6a5SAndreas Gohr                $this->_debug("No 'group' field returned from select-groups statement", -1, __LINE__);
6035de3a6a5SAndreas Gohr                return false;
6045de3a6a5SAndreas Gohr            }
6055de3a6a5SAndreas Gohr
6065de3a6a5SAndreas Gohr            // relayout result with group name as key
6075de3a6a5SAndreas Gohr            $group = $row['group'];
6085de3a6a5SAndreas Gohr            $groups[$group] = $row;
6095de3a6a5SAndreas Gohr        }
6105de3a6a5SAndreas Gohr
6115de3a6a5SAndreas Gohr        ksort($groups);
6125de3a6a5SAndreas Gohr        return $groups;
6135de3a6a5SAndreas Gohr    }
6145de3a6a5SAndreas Gohr
6155de3a6a5SAndreas Gohr    /**
6160cec3e2aSAndreas Gohr     * Remove all entries from the group cache
6170cec3e2aSAndreas Gohr     */
6180cec3e2aSAndreas Gohr    protected function _clearGroupCache() {
6190cec3e2aSAndreas Gohr        $this->groupcache = null;
6200cec3e2aSAndreas Gohr    }
6210cec3e2aSAndreas Gohr
6220cec3e2aSAndreas Gohr    /**
6234fb8dfabSAndreas Gohr     * Adds the user to the group
6245de3a6a5SAndreas Gohr     *
6255de3a6a5SAndreas Gohr     * @param array $userdata all the user data
6265de3a6a5SAndreas Gohr     * @param array $groupdata all the group data
6275de3a6a5SAndreas Gohr     * @return bool
6285de3a6a5SAndreas Gohr     */
6295de3a6a5SAndreas Gohr    protected function _joinGroup($userdata, $groupdata) {
6305de3a6a5SAndreas Gohr        $data = array_merge($userdata, $groupdata);
6315de3a6a5SAndreas Gohr        $sql = $this->getConf('join-group');
6325de3a6a5SAndreas Gohr        $result = $this->_query($sql, $data);
6335de3a6a5SAndreas Gohr        if($result === false) return false;
6345de3a6a5SAndreas Gohr        return true;
6355de3a6a5SAndreas Gohr    }
6365de3a6a5SAndreas Gohr
6375de3a6a5SAndreas Gohr    /**
6384fb8dfabSAndreas Gohr     * Removes the user from the group
6394fb8dfabSAndreas Gohr     *
6404fb8dfabSAndreas Gohr     * @param array $userdata all the user data
6414fb8dfabSAndreas Gohr     * @param array $groupdata all the group data
6424fb8dfabSAndreas Gohr     * @return bool
6434fb8dfabSAndreas Gohr     */
6444fb8dfabSAndreas Gohr    protected function _leaveGroup($userdata, $groupdata) {
6454fb8dfabSAndreas Gohr        $data = array_merge($userdata, $groupdata);
6464fb8dfabSAndreas Gohr        $sql = $this->getConf('leave-group');
6474fb8dfabSAndreas Gohr        $result = $this->_query($sql, $data);
6484fb8dfabSAndreas Gohr        if($result === false) return false;
6494fb8dfabSAndreas Gohr        return true;
6504fb8dfabSAndreas Gohr    }
6514fb8dfabSAndreas Gohr
6524fb8dfabSAndreas Gohr    /**
65370a89417SAndreas Gohr     * Executes a query
65470a89417SAndreas Gohr     *
65570a89417SAndreas Gohr     * @param string $sql The SQL statement to execute
65670a89417SAndreas Gohr     * @param array $arguments Named parameters to be used in the statement
657f695c447SAndreas Gohr     * @return array|int|bool The result as associative array for SELECTs, affected rows for others, false on error
65870a89417SAndreas Gohr     */
6595de3a6a5SAndreas Gohr    protected function _query($sql, $arguments = array()) {
660f695c447SAndreas Gohr        $sql = trim($sql);
6615de3a6a5SAndreas Gohr        if(empty($sql)) {
6625de3a6a5SAndreas Gohr            $this->_debug('No SQL query given', -1, __LINE__);
6635de3a6a5SAndreas Gohr            return false;
6645de3a6a5SAndreas Gohr        }
6655de3a6a5SAndreas Gohr
66614119d44SAndreas Gohr        // execute
66770a89417SAndreas Gohr        $params = array();
66814119d44SAndreas Gohr        $sth = $this->pdo->prepare($sql);
66914119d44SAndreas Gohr        try {
67014119d44SAndreas Gohr            // prepare parameters - we only use those that exist in the SQL
67170a89417SAndreas Gohr            foreach($arguments as $key => $value) {
67270a89417SAndreas Gohr                if(is_array($value)) continue;
67370a89417SAndreas Gohr                if(is_object($value)) continue;
67470a89417SAndreas Gohr                if($key[0] != ':') $key = ":$key"; // prefix with colon if needed
67514119d44SAndreas Gohr                if(strpos($sql, $key) === false) continue; // skip if parameter is missing
67614119d44SAndreas Gohr
67714119d44SAndreas Gohr                if(is_int($value)) {
67814119d44SAndreas Gohr                    $sth->bindValue($key, $value, PDO::PARAM_INT);
67914119d44SAndreas Gohr                } else {
68014119d44SAndreas Gohr                    $sth->bindValue($key, $value);
68114119d44SAndreas Gohr                }
682f6cd8a7fSphjanderson                $params[$key] = $value; //remember for debugging
68370a89417SAndreas Gohr            }
68470a89417SAndreas Gohr
68514119d44SAndreas Gohr            $sth->execute();
686*6a1b9bfeSPhy            // only report last line's result
687*6a1b9bfeSPhy            $hasnextrowset = true;
688*6a1b9bfeSPhy            $currentsql = $sql;
689*6a1b9bfeSPhy            while($hasnextrowset){
690*6a1b9bfeSPhy                if(strtolower(substr($currentsql, 0, 6)) == 'select') {
69170a89417SAndreas Gohr                    $result = $sth->fetchAll();
692f695c447SAndreas Gohr                } else {
693f695c447SAndreas Gohr                    $result = $sth->rowCount();
694f695c447SAndreas Gohr                }
695*6a1b9bfeSPhy                $semi_pos = strpos($currentsql, ';');
696*6a1b9bfeSPhy                if($semi_pos){
697*6a1b9bfeSPhy                    $currentsql = trim(substr($currentsql, $semi_pos+1));
698*6a1b9bfeSPhy                }
699*6a1b9bfeSPhy                try{
700*6a1b9bfeSPhy                    $hasnextrowset = $sth->nextRowset(); // run next rowset
701*6a1b9bfeSPhy                }catch(PDOException $rowset_e){
702*6a1b9bfeSPhy                    $hasnextrowset = false; // driver does not support multi-rowset, should be executed in one time
703*6a1b9bfeSPhy                }
704*6a1b9bfeSPhy            }
7055de3a6a5SAndreas Gohr        } catch(Exception $e) {
7064fb8dfabSAndreas Gohr            // report the caller's line
7074fb8dfabSAndreas Gohr            $trace = debug_backtrace();
7084fb8dfabSAndreas Gohr            $line = $trace[0]['line'];
7095de3a6a5SAndreas Gohr            $dsql = $this->_debugSQL($sql, $params, !defined('DOKU_UNITTEST'));
7104fb8dfabSAndreas Gohr            $this->_debug($e, -1, $line);
7114fb8dfabSAndreas Gohr            $this->_debug("SQL: <pre>$dsql</pre>", -1, $line);
71270a89417SAndreas Gohr            $result = false;
7131600c7ccSAndreas Gohr        }
71470a89417SAndreas Gohr        $sth->closeCursor();
71570a89417SAndreas Gohr        $sth = null;
71670a89417SAndreas Gohr
7175de3a6a5SAndreas Gohr        return $result;
7185de3a6a5SAndreas Gohr    }
71970a89417SAndreas Gohr
72070a89417SAndreas Gohr    /**
721f64dbc90SAndreas Gohr     * Wrapper around msg() but outputs only when debug is enabled
722f64dbc90SAndreas Gohr     *
723f64dbc90SAndreas Gohr     * @param string|Exception $message
724f64dbc90SAndreas Gohr     * @param int $err
725f64dbc90SAndreas Gohr     * @param int $line
726f64dbc90SAndreas Gohr     */
727f64dbc90SAndreas Gohr    protected function _debug($message, $err = 0, $line = 0) {
728f64dbc90SAndreas Gohr        if(!$this->getConf('debug')) return;
729f64dbc90SAndreas Gohr        if(is_a($message, 'Exception')) {
730f64dbc90SAndreas Gohr            $err = -1;
731f64dbc90SAndreas Gohr            $msg = $message->getMessage();
7324fb8dfabSAndreas Gohr            if(!$line) $line = $message->getLine();
733f64dbc90SAndreas Gohr        } else {
734f64dbc90SAndreas Gohr            $msg = $message;
735f64dbc90SAndreas Gohr        }
736f64dbc90SAndreas Gohr
737f64dbc90SAndreas Gohr        if(defined('DOKU_UNITTEST')) {
738f64dbc90SAndreas Gohr            printf("\n%s, %s:%d\n", $msg, __FILE__, $line);
739f64dbc90SAndreas Gohr        } else {
740f64dbc90SAndreas Gohr            msg('authpdo: ' . $msg, $err, $line, __FILE__);
741f64dbc90SAndreas Gohr        }
742f64dbc90SAndreas Gohr    }
7435de3a6a5SAndreas Gohr
7445de3a6a5SAndreas Gohr    /**
7455de3a6a5SAndreas Gohr     * Check if the given config strings are set
7465de3a6a5SAndreas Gohr     *
7475de3a6a5SAndreas Gohr     * @author  Matthias Grimm <matthiasgrimm@users.sourceforge.net>
7485de3a6a5SAndreas Gohr     *
7495de3a6a5SAndreas Gohr     * @param   string[] $keys
7505de3a6a5SAndreas Gohr     * @return  bool
7515de3a6a5SAndreas Gohr     */
7525de3a6a5SAndreas Gohr    protected function _chkcnf($keys) {
7535de3a6a5SAndreas Gohr        foreach($keys as $key) {
754ad4d5631SAndreas Gohr            $params = explode(':', $key);
755ad4d5631SAndreas Gohr            $key = array_shift($params);
756ad4d5631SAndreas Gohr            $sql = trim($this->getConf($key));
757ad4d5631SAndreas Gohr
758ad4d5631SAndreas Gohr            // check if sql is set
759ad4d5631SAndreas Gohr            if(!$sql) return false;
760ad4d5631SAndreas Gohr            // check if needed params are there
761ad4d5631SAndreas Gohr            foreach($params as $param) {
762ad4d5631SAndreas Gohr                if(strpos($sql, ":$param") === false) return false;
763ad4d5631SAndreas Gohr            }
7645de3a6a5SAndreas Gohr        }
7655de3a6a5SAndreas Gohr
7665de3a6a5SAndreas Gohr        return true;
7675de3a6a5SAndreas Gohr    }
7685de3a6a5SAndreas Gohr
7695de3a6a5SAndreas Gohr    /**
7705de3a6a5SAndreas Gohr     * create an approximation of the SQL string with parameters replaced
7715de3a6a5SAndreas Gohr     *
7725de3a6a5SAndreas Gohr     * @param string $sql
7735de3a6a5SAndreas Gohr     * @param array $params
7745de3a6a5SAndreas Gohr     * @param bool $htmlescape Should the result be escaped for output in HTML?
7755de3a6a5SAndreas Gohr     * @return string
7765de3a6a5SAndreas Gohr     */
7775de3a6a5SAndreas Gohr    protected function _debugSQL($sql, $params, $htmlescape = true) {
7785de3a6a5SAndreas Gohr        foreach($params as $key => $val) {
7795de3a6a5SAndreas Gohr            if(is_int($val)) {
7805de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val, PDO::PARAM_INT);
7815de3a6a5SAndreas Gohr            } elseif(is_bool($val)) {
7825de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val, PDO::PARAM_BOOL);
7835de3a6a5SAndreas Gohr            } elseif(is_null($val)) {
7845de3a6a5SAndreas Gohr                $val = 'NULL';
7855de3a6a5SAndreas Gohr            } else {
7865de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val);
7875de3a6a5SAndreas Gohr            }
7885de3a6a5SAndreas Gohr            $sql = str_replace($key, $val, $sql);
7895de3a6a5SAndreas Gohr        }
7905de3a6a5SAndreas Gohr        if($htmlescape) $sql = hsc($sql);
7915de3a6a5SAndreas Gohr        return $sql;
7925de3a6a5SAndreas Gohr    }
793f64dbc90SAndreas Gohr}
794f64dbc90SAndreas Gohr
795f64dbc90SAndreas Gohr// vim:ts=4:sw=4:et:
796