xref: /dokuwiki/lib/plugins/authpdo/auth.php (revision 3213bf4e5dd55220bd7614bf0030e6e680b4c227)
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
90d586afdSAndreas Gohr/**
100d586afdSAndreas Gohr * Class auth_plugin_authpdo
110d586afdSAndreas Gohr */
12*3213bf4eSAndreas Gohrclass auth_plugin_authpdo extends DokuWiki_Auth_Plugin
13*3213bf4eSAndreas Gohr{
14f64dbc90SAndreas Gohr
15f64dbc90SAndreas Gohr    /** @var PDO */
16f64dbc90SAndreas Gohr    protected $pdo;
17f64dbc90SAndreas Gohr
180cec3e2aSAndreas Gohr    /** @var null|array The list of all groups */
190cec3e2aSAndreas Gohr    protected $groupcache = null;
200cec3e2aSAndreas Gohr
21f64dbc90SAndreas Gohr    /**
22f64dbc90SAndreas Gohr     * Constructor.
23f64dbc90SAndreas Gohr     */
24*3213bf4eSAndreas Gohr    public function __construct()
25*3213bf4eSAndreas Gohr    {
26f64dbc90SAndreas Gohr        parent::__construct(); // for compatibility
27f64dbc90SAndreas Gohr
28f64dbc90SAndreas Gohr        if (!class_exists('PDO')) {
29*3213bf4eSAndreas Gohr            $this->debugMsg('PDO extension for PHP not found.', -1, __LINE__);
30f64dbc90SAndreas Gohr            $this->success = false;
31f64dbc90SAndreas Gohr            return;
32f64dbc90SAndreas Gohr        }
33f64dbc90SAndreas Gohr
34f64dbc90SAndreas Gohr        if (!$this->getConf('dsn')) {
35*3213bf4eSAndreas Gohr            $this->debugMsg('No DSN specified', -1, __LINE__);
36f64dbc90SAndreas Gohr            $this->success = false;
37f64dbc90SAndreas Gohr            return;
38f64dbc90SAndreas Gohr        }
39f64dbc90SAndreas Gohr
40f64dbc90SAndreas Gohr        try {
41f64dbc90SAndreas Gohr            $this->pdo = new PDO(
42f64dbc90SAndreas Gohr                $this->getConf('dsn'),
43f64dbc90SAndreas Gohr                $this->getConf('user'),
440cc11d97SAndreas Gohr                conf_decodeString($this->getConf('pass')),
45f64dbc90SAndreas Gohr                array(
4670a89417SAndreas Gohr                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // always fetch as array
4770a89417SAndreas Gohr                    PDO::ATTR_EMULATE_PREPARES => true, // emulating prepares allows us to reuse param names
485de3a6a5SAndreas Gohr                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
49f64dbc90SAndreas Gohr                )
50f64dbc90SAndreas Gohr            );
51f64dbc90SAndreas Gohr        } catch (PDOException $e) {
52*3213bf4eSAndreas Gohr            $this->debugMsg($e);
53c27579a6SAndreas Gohr            msg($this->getLang('connectfail'), -1);
54f64dbc90SAndreas Gohr            $this->success = false;
55f64dbc90SAndreas Gohr            return;
56f64dbc90SAndreas Gohr        }
57f64dbc90SAndreas Gohr
580d586afdSAndreas Gohr        // can Users be created?
59*3213bf4eSAndreas Gohr        $this->cando['addUser'] = $this->checkConfig(
600d586afdSAndreas Gohr            array(
610d586afdSAndreas Gohr                'select-user',
620d586afdSAndreas Gohr                'select-user-groups',
630d586afdSAndreas Gohr                'select-groups',
640d586afdSAndreas Gohr                'insert-user',
650d586afdSAndreas Gohr                'insert-group',
660d586afdSAndreas Gohr                'join-group'
670d586afdSAndreas Gohr            )
680d586afdSAndreas Gohr        );
69f64dbc90SAndreas Gohr
700d586afdSAndreas Gohr        // can Users be deleted?
71*3213bf4eSAndreas Gohr        $this->cando['delUser'] = $this->checkConfig(
720d586afdSAndreas Gohr            array(
730d586afdSAndreas Gohr                'select-user',
740d586afdSAndreas Gohr                'select-user-groups',
750d586afdSAndreas Gohr                'select-groups',
767f89f089SAndreas Gohr                'leave-group',
777f89f089SAndreas Gohr                'delete-user'
780d586afdSAndreas Gohr            )
790d586afdSAndreas Gohr        );
800d586afdSAndreas Gohr
810d586afdSAndreas Gohr        // can login names be changed?
82*3213bf4eSAndreas Gohr        $this->cando['modLogin'] = $this->checkConfig(
830d586afdSAndreas Gohr            array(
840d586afdSAndreas Gohr                'select-user',
850d586afdSAndreas Gohr                'select-user-groups',
860d586afdSAndreas Gohr                'update-user-login'
870d586afdSAndreas Gohr            )
880d586afdSAndreas Gohr        );
890d586afdSAndreas Gohr
900d586afdSAndreas Gohr        // can passwords be changed?
91*3213bf4eSAndreas Gohr        $this->cando['modPass'] = $this->checkConfig(
920d586afdSAndreas Gohr            array(
930d586afdSAndreas Gohr                'select-user',
940d586afdSAndreas Gohr                'select-user-groups',
950d586afdSAndreas Gohr                'update-user-pass'
960d586afdSAndreas Gohr            )
970d586afdSAndreas Gohr        );
980d586afdSAndreas Gohr
99ad4d5631SAndreas Gohr        // can real names be changed?
100*3213bf4eSAndreas Gohr        $this->cando['modName'] = $this->checkConfig(
1010d586afdSAndreas Gohr            array(
1020d586afdSAndreas Gohr                'select-user',
1030d586afdSAndreas Gohr                'select-user-groups',
104ad4d5631SAndreas Gohr                'update-user-info:name'
105ad4d5631SAndreas Gohr            )
106ad4d5631SAndreas Gohr        );
107ad4d5631SAndreas Gohr
108ad4d5631SAndreas Gohr        // can real email be changed?
109*3213bf4eSAndreas Gohr        $this->cando['modMail'] = $this->checkConfig(
110ad4d5631SAndreas Gohr            array(
111ad4d5631SAndreas Gohr                'select-user',
112ad4d5631SAndreas Gohr                'select-user-groups',
113ad4d5631SAndreas Gohr                'update-user-info:mail'
1140d586afdSAndreas Gohr            )
1150d586afdSAndreas Gohr        );
1160d586afdSAndreas Gohr
1170d586afdSAndreas Gohr        // can groups be changed?
118*3213bf4eSAndreas Gohr        $this->cando['modGroups'] = $this->checkConfig(
1190d586afdSAndreas Gohr            array(
1200d586afdSAndreas Gohr                'select-user',
1210d586afdSAndreas Gohr                'select-user-groups',
1220d586afdSAndreas Gohr                'select-groups',
1230d586afdSAndreas Gohr                'leave-group',
1240d586afdSAndreas Gohr                'join-group',
1250d586afdSAndreas Gohr                'insert-group'
1260d586afdSAndreas Gohr            )
1270d586afdSAndreas Gohr        );
1280d586afdSAndreas Gohr
1290d586afdSAndreas Gohr        // can a filtered list of users be retrieved?
130*3213bf4eSAndreas Gohr        $this->cando['getUsers'] = $this->checkConfig(
1310d586afdSAndreas Gohr            array(
1320d586afdSAndreas Gohr                'list-users'
1330d586afdSAndreas Gohr            )
1340d586afdSAndreas Gohr        );
1350d586afdSAndreas Gohr
1360d586afdSAndreas Gohr        // can the number of users be retrieved?
137*3213bf4eSAndreas Gohr        $this->cando['getUserCount'] = $this->checkConfig(
1380d586afdSAndreas Gohr            array(
1390d586afdSAndreas Gohr                'count-users'
1400d586afdSAndreas Gohr            )
1410d586afdSAndreas Gohr        );
1420d586afdSAndreas Gohr
1430d586afdSAndreas Gohr        // can a list of available groups be retrieved?
144*3213bf4eSAndreas Gohr        $this->cando['getGroups'] = $this->checkConfig(
1450d586afdSAndreas Gohr            array(
1460d586afdSAndreas Gohr                'select-groups'
1470d586afdSAndreas Gohr            )
1480d586afdSAndreas Gohr        );
1490d586afdSAndreas Gohr
150f64dbc90SAndreas Gohr        $this->success = true;
151f64dbc90SAndreas Gohr    }
152f64dbc90SAndreas Gohr
153f64dbc90SAndreas Gohr    /**
154f64dbc90SAndreas Gohr     * Check user+password
155f64dbc90SAndreas Gohr     *
156f64dbc90SAndreas Gohr     * @param   string $user the user name
157f64dbc90SAndreas Gohr     * @param   string $pass the clear text password
158f64dbc90SAndreas Gohr     * @return  bool
159f64dbc90SAndreas Gohr     */
160*3213bf4eSAndreas Gohr    public function checkPass($user, $pass)
161*3213bf4eSAndreas Gohr    {
162f64dbc90SAndreas Gohr
163*3213bf4eSAndreas Gohr        $userdata = $this->selectUser($user);
164397d62a2SAndreas Gohr        if ($userdata == false) return false;
165f64dbc90SAndreas Gohr
166397d62a2SAndreas Gohr        // password checking done in SQL?
167*3213bf4eSAndreas Gohr        if ($this->checkConfig(array('check-pass'))) {
168397d62a2SAndreas Gohr            $userdata['clear'] = $pass;
169397d62a2SAndreas Gohr            $userdata['hash'] = auth_cryptPassword($pass);
170*3213bf4eSAndreas 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     */
200*3213bf4eSAndreas Gohr    public function getUserData($user, $requireGroups = true)
201*3213bf4eSAndreas Gohr    {
202*3213bf4eSAndreas Gohr        $data = $this->selectUser($user);
203f64dbc90SAndreas Gohr        if ($data == false) return false;
204f64dbc90SAndreas Gohr
20570a89417SAndreas Gohr        if (isset($data['hash'])) unset($data['hash']);
20670a89417SAndreas Gohr        if (isset($data['clean'])) unset($data['clean']);
207f64dbc90SAndreas Gohr
20870a89417SAndreas Gohr        if ($requireGroups) {
209*3213bf4eSAndreas Gohr            $data['grps'] = $this->selectUserGroups($data);
2105de3a6a5SAndreas Gohr            if ($data['grps'] === false) return false;
211f64dbc90SAndreas Gohr        }
212f64dbc90SAndreas Gohr
213f64dbc90SAndreas Gohr        return $data;
214f64dbc90SAndreas Gohr    }
215f64dbc90SAndreas Gohr
216f64dbc90SAndreas Gohr    /**
217f64dbc90SAndreas Gohr     * Create a new User [implement only where required/possible]
218f64dbc90SAndreas Gohr     *
219f64dbc90SAndreas Gohr     * Returns false if the user already exists, null when an error
220f64dbc90SAndreas Gohr     * occurred and true if everything went well.
221f64dbc90SAndreas Gohr     *
222f64dbc90SAndreas Gohr     * The new user HAS TO be added to the default group by this
223f64dbc90SAndreas Gohr     * function!
224f64dbc90SAndreas Gohr     *
225f64dbc90SAndreas Gohr     * Set addUser capability when implemented
226f64dbc90SAndreas Gohr     *
227f64dbc90SAndreas Gohr     * @param  string $user
2285de3a6a5SAndreas Gohr     * @param  string $clear
229f64dbc90SAndreas Gohr     * @param  string $name
230f64dbc90SAndreas Gohr     * @param  string $mail
231f64dbc90SAndreas Gohr     * @param  null|array $grps
232f64dbc90SAndreas Gohr     * @return bool|null
233f64dbc90SAndreas Gohr     */
234*3213bf4eSAndreas Gohr    public function createUser($user, $clear, $name, $mail, $grps = null)
235*3213bf4eSAndreas Gohr    {
2365de3a6a5SAndreas Gohr        global $conf;
2375de3a6a5SAndreas Gohr
2385de3a6a5SAndreas Gohr        if (($info = $this->getUserData($user, false)) !== false) {
2395de3a6a5SAndreas Gohr            msg($this->getLang('userexists'), -1);
2405de3a6a5SAndreas Gohr            return false; // user already exists
2415de3a6a5SAndreas Gohr        }
2425de3a6a5SAndreas Gohr
2435de3a6a5SAndreas Gohr        // prepare data
2445de3a6a5SAndreas Gohr        if ($grps == null) $grps = array();
24507a11e2aSAndreas Gohr        array_unshift($grps, $conf['defaultgroup']);
2465de3a6a5SAndreas Gohr        $grps = array_unique($grps);
2475de3a6a5SAndreas Gohr        $hash = auth_cryptPassword($clear);
2485de3a6a5SAndreas Gohr        $userdata = compact('user', 'clear', 'hash', 'name', 'mail');
2495de3a6a5SAndreas Gohr
2505de3a6a5SAndreas Gohr        // action protected by transaction
2515de3a6a5SAndreas Gohr        $this->pdo->beginTransaction();
2525de3a6a5SAndreas Gohr        {
2535de3a6a5SAndreas Gohr            // insert the user
254*3213bf4eSAndreas Gohr            $ok = $this->query($this->getConf('insert-user'), $userdata);
2555de3a6a5SAndreas Gohr            if ($ok === false) goto FAIL;
2565de3a6a5SAndreas Gohr            $userdata = $this->getUserData($user, false);
2575de3a6a5SAndreas Gohr            if ($userdata === false) goto FAIL;
2585de3a6a5SAndreas Gohr
2595de3a6a5SAndreas Gohr            // create all groups that do not exist, the refetch the groups
260*3213bf4eSAndreas Gohr            $allgroups = $this->selectGroups();
2615de3a6a5SAndreas Gohr        foreach ($grps as $group) {
2625de3a6a5SAndreas Gohr            if (!isset($allgroups[$group])) {
2636459f496SAndreas Gohr                $ok = $this->addGroup($group);
2645de3a6a5SAndreas Gohr                if ($ok === false) goto FAIL;
2655de3a6a5SAndreas Gohr            }
2665de3a6a5SAndreas Gohr        }
267*3213bf4eSAndreas Gohr            $allgroups = $this->selectGroups();
2685de3a6a5SAndreas Gohr
2695de3a6a5SAndreas Gohr            // add user to the groups
2705de3a6a5SAndreas Gohr        foreach ($grps as $group) {
271*3213bf4eSAndreas Gohr            $ok = $this->joinGroup($userdata, $allgroups[$group]);
2725de3a6a5SAndreas Gohr            if ($ok === false) goto FAIL;
2735de3a6a5SAndreas Gohr        }
2745de3a6a5SAndreas Gohr        }
2755de3a6a5SAndreas Gohr        $this->pdo->commit();
2765de3a6a5SAndreas Gohr        return true;
2775de3a6a5SAndreas Gohr
2785de3a6a5SAndreas Gohr        // something went wrong, rollback
2795de3a6a5SAndreas Gohr        FAIL:
2805de3a6a5SAndreas Gohr        $this->pdo->rollBack();
281*3213bf4eSAndreas Gohr        $this->debugMsg('Transaction rolled back', 0, __LINE__);
282c27579a6SAndreas Gohr        msg($this->getLang('writefail'), -1);
2835de3a6a5SAndreas Gohr        return null; // return error
2845de3a6a5SAndreas Gohr    }
285f64dbc90SAndreas Gohr
286f64dbc90SAndreas Gohr    /**
2874fb8dfabSAndreas Gohr     * Modify user data
288f64dbc90SAndreas Gohr     *
289f64dbc90SAndreas Gohr     * @param   string $user nick of the user to be changed
290f64dbc90SAndreas Gohr     * @param   array $changes array of field/value pairs to be changed (password will be clear text)
291f64dbc90SAndreas Gohr     * @return  bool
292f64dbc90SAndreas Gohr     */
293*3213bf4eSAndreas Gohr    public function modifyUser($user, $changes)
294*3213bf4eSAndreas Gohr    {
2954fb8dfabSAndreas Gohr        // secure everything in transaction
2964fb8dfabSAndreas Gohr        $this->pdo->beginTransaction();
2974fb8dfabSAndreas Gohr        {
2984fb8dfabSAndreas Gohr            $olddata = $this->getUserData($user);
2994fb8dfabSAndreas Gohr            $oldgroups = $olddata['grps'];
3004fb8dfabSAndreas Gohr            unset($olddata['grps']);
3014fb8dfabSAndreas Gohr
3024fb8dfabSAndreas Gohr            // changing the user name?
3034fb8dfabSAndreas Gohr        if (isset($changes['user'])) {
3044fb8dfabSAndreas Gohr            if ($this->getUserData($changes['user'], false)) goto FAIL;
3054fb8dfabSAndreas Gohr            $params = $olddata;
3064fb8dfabSAndreas Gohr            $params['newlogin'] = $changes['user'];
3074fb8dfabSAndreas Gohr
308*3213bf4eSAndreas Gohr            $ok = $this->query($this->getConf('update-user-login'), $params);
3094fb8dfabSAndreas Gohr            if ($ok === false) goto FAIL;
3104fb8dfabSAndreas Gohr        }
3114fb8dfabSAndreas Gohr
3124fb8dfabSAndreas Gohr            // changing the password?
3134fb8dfabSAndreas Gohr        if (isset($changes['pass'])) {
3144fb8dfabSAndreas Gohr            $params = $olddata;
3154fb8dfabSAndreas Gohr            $params['clear'] = $changes['pass'];
3164fb8dfabSAndreas Gohr            $params['hash'] = auth_cryptPassword($changes['pass']);
3174fb8dfabSAndreas Gohr
318*3213bf4eSAndreas Gohr            $ok = $this->query($this->getConf('update-user-pass'), $params);
3194fb8dfabSAndreas Gohr            if ($ok === false) goto FAIL;
3204fb8dfabSAndreas Gohr        }
3214fb8dfabSAndreas Gohr
3224fb8dfabSAndreas Gohr            // changing info?
3234fb8dfabSAndreas Gohr        if (isset($changes['mail']) || isset($changes['name'])) {
3244fb8dfabSAndreas Gohr            $params = $olddata;
3254fb8dfabSAndreas Gohr            if (isset($changes['mail'])) $params['mail'] = $changes['mail'];
3264fb8dfabSAndreas Gohr            if (isset($changes['name'])) $params['name'] = $changes['name'];
3274fb8dfabSAndreas Gohr
328*3213bf4eSAndreas Gohr            $ok = $this->query($this->getConf('update-user-info'), $params);
3294fb8dfabSAndreas Gohr            if ($ok === false) goto FAIL;
3304fb8dfabSAndreas Gohr        }
3314fb8dfabSAndreas Gohr
3324fb8dfabSAndreas Gohr            // changing groups?
3334fb8dfabSAndreas Gohr        if (isset($changes['grps'])) {
334*3213bf4eSAndreas Gohr            $allgroups = $this->selectGroups();
3354fb8dfabSAndreas Gohr
3364fb8dfabSAndreas Gohr            // remove membership for previous groups
3374fb8dfabSAndreas Gohr            foreach ($oldgroups as $group) {
338358942b5SAndreas Gohr                if (!in_array($group, $changes['grps']) && isset($allgroups[$group])) {
339*3213bf4eSAndreas Gohr                    $ok = $this->leaveGroup($olddata, $allgroups[$group]);
3404fb8dfabSAndreas Gohr                    if ($ok === false) goto FAIL;
3414fb8dfabSAndreas Gohr                }
3424fb8dfabSAndreas Gohr            }
3434fb8dfabSAndreas Gohr
3444fb8dfabSAndreas Gohr            // create all new groups that are missing
3454fb8dfabSAndreas Gohr            $added = 0;
3464fb8dfabSAndreas Gohr            foreach ($changes['grps'] as $group) {
3474fb8dfabSAndreas Gohr                if (!isset($allgroups[$group])) {
3486459f496SAndreas Gohr                    $ok = $this->addGroup($group);
3494fb8dfabSAndreas Gohr                    if ($ok === false) goto FAIL;
3504fb8dfabSAndreas Gohr                    $added++;
3514fb8dfabSAndreas Gohr                }
3524fb8dfabSAndreas Gohr            }
3534fb8dfabSAndreas Gohr            // reload group info
354*3213bf4eSAndreas Gohr            if ($added > 0) $allgroups = $this->selectGroups();
3554fb8dfabSAndreas Gohr
3564fb8dfabSAndreas Gohr            // add membership for new groups
3574fb8dfabSAndreas Gohr            foreach ($changes['grps'] as $group) {
3584fb8dfabSAndreas Gohr                if (!in_array($group, $oldgroups)) {
359*3213bf4eSAndreas Gohr                    $ok = $this->joinGroup($olddata, $allgroups[$group]);
3604fb8dfabSAndreas Gohr                    if ($ok === false) goto FAIL;
3614fb8dfabSAndreas Gohr                }
3624fb8dfabSAndreas Gohr            }
3634fb8dfabSAndreas Gohr        }
3644fb8dfabSAndreas Gohr
3654fb8dfabSAndreas Gohr        }
3664fb8dfabSAndreas Gohr        $this->pdo->commit();
3674fb8dfabSAndreas Gohr        return true;
3684fb8dfabSAndreas Gohr
3694fb8dfabSAndreas Gohr        // something went wrong, rollback
3704fb8dfabSAndreas Gohr        FAIL:
3714fb8dfabSAndreas Gohr        $this->pdo->rollBack();
372*3213bf4eSAndreas Gohr        $this->debugMsg('Transaction rolled back', 0, __LINE__);
373c27579a6SAndreas Gohr        msg($this->getLang('writefail'), -1);
3744fb8dfabSAndreas Gohr        return false; // return error
3754fb8dfabSAndreas Gohr    }
376f64dbc90SAndreas Gohr
377f64dbc90SAndreas Gohr    /**
378e19be516SAndreas Gohr     * Delete one or more users
379f64dbc90SAndreas Gohr     *
380f64dbc90SAndreas Gohr     * Set delUser capability when implemented
381f64dbc90SAndreas Gohr     *
382f64dbc90SAndreas Gohr     * @param   array $users
383f64dbc90SAndreas Gohr     * @return  int    number of users deleted
384f64dbc90SAndreas Gohr     */
385*3213bf4eSAndreas Gohr    public function deleteUsers($users)
386*3213bf4eSAndreas Gohr    {
387e19be516SAndreas Gohr        $count = 0;
388e19be516SAndreas Gohr        foreach ($users as $user) {
389*3213bf4eSAndreas Gohr            if ($this->deleteUser($user)) $count++;
390e19be516SAndreas Gohr        }
391e19be516SAndreas Gohr        return $count;
392e19be516SAndreas Gohr    }
393f64dbc90SAndreas Gohr
394f64dbc90SAndreas Gohr    /**
395f64dbc90SAndreas Gohr     * Bulk retrieval of user data [implement only where required/possible]
396f64dbc90SAndreas Gohr     *
397f64dbc90SAndreas Gohr     * Set getUsers capability when implemented
398f64dbc90SAndreas Gohr     *
399f64dbc90SAndreas Gohr     * @param   int $start index of first user to be returned
400f64dbc90SAndreas Gohr     * @param   int $limit max number of users to be returned
401f64dbc90SAndreas Gohr     * @param   array $filter array of field/pattern pairs, null for no filter
402f64dbc90SAndreas Gohr     * @return  array list of userinfo (refer getUserData for internal userinfo details)
403f64dbc90SAndreas Gohr     */
404*3213bf4eSAndreas Gohr    public function retrieveUsers($start = 0, $limit = -1, $filter = null)
405*3213bf4eSAndreas Gohr    {
4066459f496SAndreas Gohr        if ($limit < 0) $limit = 10000; // we don't support no limit
4076459f496SAndreas Gohr        if (is_null($filter)) $filter = array();
4086459f496SAndreas Gohr
40912c7f5c3SAndreas Gohr        if (isset($filter['grps'])) $filter['group'] = $filter['grps'];
4106459f496SAndreas Gohr        foreach (array('user', 'name', 'mail', 'group') as $key) {
4116459f496SAndreas Gohr            if (!isset($filter[$key])) {
4126459f496SAndreas Gohr                $filter[$key] = '%';
4136459f496SAndreas Gohr            } else {
4146459f496SAndreas Gohr                $filter[$key] = '%' . $filter[$key] . '%';
4156459f496SAndreas Gohr            }
4166459f496SAndreas Gohr        }
41714119d44SAndreas Gohr        $filter['start'] = (int) $start;
41814119d44SAndreas Gohr        $filter['end'] = (int) $start + $limit;
41914119d44SAndreas Gohr        $filter['limit'] = (int) $limit;
4206459f496SAndreas Gohr
421*3213bf4eSAndreas Gohr        $result = $this->query($this->getConf('list-users'), $filter);
4226459f496SAndreas Gohr        if (!$result) return array();
4236459f496SAndreas Gohr        $users = array();
4246459f496SAndreas Gohr        foreach ($result as $row) {
4256459f496SAndreas Gohr            if (!isset($row['user'])) {
426*3213bf4eSAndreas Gohr                $this->debugMsg("Statement did not return 'user' attribute", -1, __LINE__);
4276459f496SAndreas Gohr                return array();
4286459f496SAndreas Gohr            }
4293e2a8145SAndreas Gohr            $users[] = $this->getUserData($row['user']);
4306459f496SAndreas Gohr        }
4316459f496SAndreas Gohr        return $users;
4326459f496SAndreas Gohr    }
433f64dbc90SAndreas Gohr
434f64dbc90SAndreas Gohr    /**
435f64dbc90SAndreas Gohr     * Return a count of the number of user which meet $filter criteria
436f64dbc90SAndreas Gohr     *
437f64dbc90SAndreas Gohr     * @param  array $filter array of field/pattern pairs, empty array for no filter
438f64dbc90SAndreas Gohr     * @return int
439f64dbc90SAndreas Gohr     */
440*3213bf4eSAndreas Gohr    public function getUserCount($filter = array())
441*3213bf4eSAndreas Gohr    {
4426459f496SAndreas Gohr        if (is_null($filter)) $filter = array();
4436459f496SAndreas Gohr
44412c7f5c3SAndreas Gohr        if (isset($filter['grps'])) $filter['group'] = $filter['grps'];
4456459f496SAndreas Gohr        foreach (array('user', 'name', 'mail', 'group') as $key) {
4466459f496SAndreas Gohr            if (!isset($filter[$key])) {
4476459f496SAndreas Gohr                $filter[$key] = '%';
4486459f496SAndreas Gohr            } else {
4496459f496SAndreas Gohr                $filter[$key] = '%' . $filter[$key] . '%';
4506459f496SAndreas Gohr            }
4516459f496SAndreas Gohr        }
4526459f496SAndreas Gohr
453*3213bf4eSAndreas Gohr        $result = $this->query($this->getConf('count-users'), $filter);
4546459f496SAndreas Gohr        if (!$result || !isset($result[0]['count'])) {
455*3213bf4eSAndreas Gohr            $this->debugMsg("Statement did not return 'count' attribute", -1, __LINE__);
4566459f496SAndreas Gohr        }
457f3c1c207SAndreas Gohr        return (int) $result[0]['count'];
4586459f496SAndreas Gohr    }
459f64dbc90SAndreas Gohr
460f64dbc90SAndreas Gohr    /**
4616459f496SAndreas Gohr     * Create a new group with the given name
462f64dbc90SAndreas Gohr     *
463f64dbc90SAndreas Gohr     * @param string $group
464f64dbc90SAndreas Gohr     * @return bool
465f64dbc90SAndreas Gohr     */
466*3213bf4eSAndreas Gohr    public function addGroup($group)
467*3213bf4eSAndreas Gohr    {
4686459f496SAndreas Gohr        $sql = $this->getConf('insert-group');
4696459f496SAndreas Gohr
470*3213bf4eSAndreas Gohr        $result = $this->query($sql, array(':group' => $group));
471*3213bf4eSAndreas Gohr        $this->clearGroupCache();
4726459f496SAndreas Gohr        if ($result === false) return false;
4736459f496SAndreas Gohr        return true;
4746459f496SAndreas Gohr    }
475f64dbc90SAndreas Gohr
476f64dbc90SAndreas Gohr    /**
4775de3a6a5SAndreas Gohr     * Retrieve groups
478f64dbc90SAndreas Gohr     *
479f64dbc90SAndreas Gohr     * Set getGroups capability when implemented
480f64dbc90SAndreas Gohr     *
481f64dbc90SAndreas Gohr     * @param   int $start
482f64dbc90SAndreas Gohr     * @param   int $limit
483f64dbc90SAndreas Gohr     * @return  array
484f64dbc90SAndreas Gohr     */
485*3213bf4eSAndreas Gohr    public function retrieveGroups($start = 0, $limit = 0)
486*3213bf4eSAndreas Gohr    {
487*3213bf4eSAndreas Gohr        $groups = array_keys($this->selectGroups());
4885de3a6a5SAndreas Gohr        if ($groups === false) return array();
489f64dbc90SAndreas Gohr
4905de3a6a5SAndreas Gohr        if (!$limit) {
4915de3a6a5SAndreas Gohr            return array_splice($groups, $start);
4925de3a6a5SAndreas Gohr        } else {
4935de3a6a5SAndreas Gohr            return array_splice($groups, $start, $limit);
494f64dbc90SAndreas Gohr        }
495f64dbc90SAndreas Gohr    }
496f64dbc90SAndreas Gohr
497f64dbc90SAndreas Gohr    /**
498f64dbc90SAndreas Gohr     * Select data of a specified user
499f64dbc90SAndreas Gohr     *
5005de3a6a5SAndreas Gohr     * @param string $user the user name
5015de3a6a5SAndreas Gohr     * @return bool|array user data, false on error
502f64dbc90SAndreas Gohr     */
503*3213bf4eSAndreas Gohr    protected function selectUser($user)
504*3213bf4eSAndreas Gohr    {
505f64dbc90SAndreas Gohr        $sql = $this->getConf('select-user');
506f64dbc90SAndreas Gohr
507*3213bf4eSAndreas Gohr        $result = $this->query($sql, array(':user' => $user));
50870a89417SAndreas Gohr        if (!$result) return false;
509f64dbc90SAndreas Gohr
51070a89417SAndreas Gohr        if (count($result) > 1) {
511*3213bf4eSAndreas Gohr            $this->debugMsg('Found more than one matching user', -1, __LINE__);
512f64dbc90SAndreas Gohr            return false;
513f64dbc90SAndreas Gohr        }
514f64dbc90SAndreas Gohr
515f64dbc90SAndreas Gohr        $data = array_shift($result);
516f64dbc90SAndreas Gohr        $dataok = true;
517f64dbc90SAndreas Gohr
518f64dbc90SAndreas Gohr        if (!isset($data['user'])) {
519*3213bf4eSAndreas Gohr            $this->debugMsg("Statement did not return 'user' attribute", -1, __LINE__);
520f64dbc90SAndreas Gohr            $dataok = false;
521f64dbc90SAndreas Gohr        }
522*3213bf4eSAndreas Gohr        if (!isset($data['hash']) && !isset($data['clear']) && !$this->checkConfig(array('check-pass'))) {
523*3213bf4eSAndreas Gohr            $this->debugMsg("Statement did not return 'clear' or 'hash' attribute", -1, __LINE__);
524f64dbc90SAndreas Gohr            $dataok = false;
525f64dbc90SAndreas Gohr        }
526f64dbc90SAndreas Gohr        if (!isset($data['name'])) {
527*3213bf4eSAndreas Gohr            $this->debugMsg("Statement did not return 'name' attribute", -1, __LINE__);
528f64dbc90SAndreas Gohr            $dataok = false;
529f64dbc90SAndreas Gohr        }
530f64dbc90SAndreas Gohr        if (!isset($data['mail'])) {
531*3213bf4eSAndreas Gohr            $this->debugMsg("Statement did not return 'mail' attribute", -1, __LINE__);
532f64dbc90SAndreas Gohr            $dataok = false;
533f64dbc90SAndreas Gohr        }
534f64dbc90SAndreas Gohr
535f64dbc90SAndreas Gohr        if (!$dataok) return false;
536f64dbc90SAndreas Gohr        return $data;
537f64dbc90SAndreas Gohr    }
538f64dbc90SAndreas Gohr
539f64dbc90SAndreas Gohr    /**
540e19be516SAndreas Gohr     * Delete a user after removing all their group memberships
541e19be516SAndreas Gohr     *
542e19be516SAndreas Gohr     * @param string $user
543e19be516SAndreas Gohr     * @return bool true when the user was deleted
544e19be516SAndreas Gohr     */
545*3213bf4eSAndreas Gohr    protected function deleteUser($user)
546*3213bf4eSAndreas Gohr    {
547e19be516SAndreas Gohr        $this->pdo->beginTransaction();
548e19be516SAndreas Gohr        {
549e19be516SAndreas Gohr            $userdata = $this->getUserData($user);
550e19be516SAndreas Gohr            if ($userdata === false) goto FAIL;
551*3213bf4eSAndreas Gohr            $allgroups = $this->selectGroups();
552e19be516SAndreas Gohr
553e19be516SAndreas Gohr            // remove group memberships (ignore errors)
554e19be516SAndreas Gohr        foreach ($userdata['grps'] as $group) {
555358942b5SAndreas Gohr            if (isset($allgroups[$group])) {
556*3213bf4eSAndreas Gohr                $this->leaveGroup($userdata, $allgroups[$group]);
557e19be516SAndreas Gohr            }
558358942b5SAndreas Gohr        }
559e19be516SAndreas Gohr
560*3213bf4eSAndreas Gohr            $ok = $this->query($this->getConf('delete-user'), $userdata);
561e19be516SAndreas Gohr            if ($ok === false) goto FAIL;
562e19be516SAndreas Gohr        }
563e19be516SAndreas Gohr        $this->pdo->commit();
564e19be516SAndreas Gohr        return true;
565e19be516SAndreas Gohr
566e19be516SAndreas Gohr        FAIL:
567e19be516SAndreas Gohr        $this->pdo->rollBack();
568e19be516SAndreas Gohr        return false;
569e19be516SAndreas Gohr    }
570e19be516SAndreas Gohr
571e19be516SAndreas Gohr    /**
57270a89417SAndreas Gohr     * Select all groups of a user
57370a89417SAndreas Gohr     *
57470a89417SAndreas Gohr     * @param array $userdata The userdata as returned by _selectUser()
5755de3a6a5SAndreas Gohr     * @return array|bool list of group names, false on error
57670a89417SAndreas Gohr     */
577*3213bf4eSAndreas Gohr    protected function selectUserGroups($userdata)
578*3213bf4eSAndreas Gohr    {
57970a89417SAndreas Gohr        global $conf;
58070a89417SAndreas Gohr        $sql = $this->getConf('select-user-groups');
581*3213bf4eSAndreas Gohr        $result = $this->query($sql, $userdata);
5825de3a6a5SAndreas Gohr        if ($result === false) return false;
58370a89417SAndreas Gohr
58470a89417SAndreas Gohr        $groups = array($conf['defaultgroup']); // always add default config
5855de3a6a5SAndreas Gohr        foreach ($result as $row) {
5865de3a6a5SAndreas Gohr            if (!isset($row['group'])) {
587*3213bf4eSAndreas Gohr                $this->debugMsg("No 'group' field returned in select-user-groups statement");
5885de3a6a5SAndreas Gohr                return false;
5895de3a6a5SAndreas Gohr            }
59070a89417SAndreas Gohr            $groups[] = $row['group'];
59170a89417SAndreas Gohr        }
59270a89417SAndreas Gohr
59370a89417SAndreas Gohr        $groups = array_unique($groups);
59470a89417SAndreas Gohr        sort($groups);
59570a89417SAndreas Gohr        return $groups;
59670a89417SAndreas Gohr    }
59770a89417SAndreas Gohr
59870a89417SAndreas Gohr    /**
5995de3a6a5SAndreas Gohr     * Select all available groups
6005de3a6a5SAndreas Gohr     *
6015de3a6a5SAndreas Gohr     * @return array|bool list of all available groups and their properties
6025de3a6a5SAndreas Gohr     */
603*3213bf4eSAndreas Gohr    protected function selectGroups()
604*3213bf4eSAndreas Gohr    {
6050cec3e2aSAndreas Gohr        if ($this->groupcache) return $this->groupcache;
6060cec3e2aSAndreas Gohr
6075de3a6a5SAndreas Gohr        $sql = $this->getConf('select-groups');
608*3213bf4eSAndreas Gohr        $result = $this->query($sql);
6095de3a6a5SAndreas Gohr        if ($result === false) return false;
6105de3a6a5SAndreas Gohr
6115de3a6a5SAndreas Gohr        $groups = array();
6125de3a6a5SAndreas Gohr        foreach ($result as $row) {
6135de3a6a5SAndreas Gohr            if (!isset($row['group'])) {
614*3213bf4eSAndreas Gohr                $this->debugMsg("No 'group' field returned from select-groups statement", -1, __LINE__);
6155de3a6a5SAndreas Gohr                return false;
6165de3a6a5SAndreas Gohr            }
6175de3a6a5SAndreas Gohr
6185de3a6a5SAndreas Gohr            // relayout result with group name as key
6195de3a6a5SAndreas Gohr            $group = $row['group'];
6205de3a6a5SAndreas Gohr            $groups[$group] = $row;
6215de3a6a5SAndreas Gohr        }
6225de3a6a5SAndreas Gohr
6235de3a6a5SAndreas Gohr        ksort($groups);
6245de3a6a5SAndreas Gohr        return $groups;
6255de3a6a5SAndreas Gohr    }
6265de3a6a5SAndreas Gohr
6275de3a6a5SAndreas Gohr    /**
6280cec3e2aSAndreas Gohr     * Remove all entries from the group cache
6290cec3e2aSAndreas Gohr     */
630*3213bf4eSAndreas Gohr    protected function clearGroupCache()
631*3213bf4eSAndreas Gohr    {
6320cec3e2aSAndreas Gohr        $this->groupcache = null;
6330cec3e2aSAndreas Gohr    }
6340cec3e2aSAndreas Gohr
6350cec3e2aSAndreas Gohr    /**
6364fb8dfabSAndreas Gohr     * Adds the user to the group
6375de3a6a5SAndreas Gohr     *
6385de3a6a5SAndreas Gohr     * @param array $userdata all the user data
6395de3a6a5SAndreas Gohr     * @param array $groupdata all the group data
6405de3a6a5SAndreas Gohr     * @return bool
6415de3a6a5SAndreas Gohr     */
642*3213bf4eSAndreas Gohr    protected function joinGroup($userdata, $groupdata)
643*3213bf4eSAndreas Gohr    {
6445de3a6a5SAndreas Gohr        $data = array_merge($userdata, $groupdata);
6455de3a6a5SAndreas Gohr        $sql = $this->getConf('join-group');
646*3213bf4eSAndreas Gohr        $result = $this->query($sql, $data);
6475de3a6a5SAndreas Gohr        if ($result === false) return false;
6485de3a6a5SAndreas Gohr        return true;
6495de3a6a5SAndreas Gohr    }
6505de3a6a5SAndreas Gohr
6515de3a6a5SAndreas Gohr    /**
6524fb8dfabSAndreas Gohr     * Removes the user from the group
6534fb8dfabSAndreas Gohr     *
6544fb8dfabSAndreas Gohr     * @param array $userdata all the user data
6554fb8dfabSAndreas Gohr     * @param array $groupdata all the group data
6564fb8dfabSAndreas Gohr     * @return bool
6574fb8dfabSAndreas Gohr     */
658*3213bf4eSAndreas Gohr    protected function leaveGroup($userdata, $groupdata)
659*3213bf4eSAndreas Gohr    {
6604fb8dfabSAndreas Gohr        $data = array_merge($userdata, $groupdata);
6614fb8dfabSAndreas Gohr        $sql = $this->getConf('leave-group');
662*3213bf4eSAndreas Gohr        $result = $this->query($sql, $data);
6634fb8dfabSAndreas Gohr        if ($result === false) return false;
6644fb8dfabSAndreas Gohr        return true;
6654fb8dfabSAndreas Gohr    }
6664fb8dfabSAndreas Gohr
6674fb8dfabSAndreas Gohr    /**
66870a89417SAndreas Gohr     * Executes a query
66970a89417SAndreas Gohr     *
67070a89417SAndreas Gohr     * @param string $sql The SQL statement to execute
67170a89417SAndreas Gohr     * @param array $arguments Named parameters to be used in the statement
672f695c447SAndreas Gohr     * @return array|int|bool The result as associative array for SELECTs, affected rows for others, false on error
67370a89417SAndreas Gohr     */
674*3213bf4eSAndreas Gohr    protected function query($sql, $arguments = array())
675*3213bf4eSAndreas Gohr    {
676f695c447SAndreas Gohr        $sql = trim($sql);
6775de3a6a5SAndreas Gohr        if (empty($sql)) {
678*3213bf4eSAndreas Gohr            $this->debugMsg('No SQL query given', -1, __LINE__);
6795de3a6a5SAndreas Gohr            return false;
6805de3a6a5SAndreas Gohr        }
6815de3a6a5SAndreas Gohr
68214119d44SAndreas Gohr        // execute
68370a89417SAndreas Gohr        $params = array();
68414119d44SAndreas Gohr        $sth = $this->pdo->prepare($sql);
68514119d44SAndreas Gohr        try {
68614119d44SAndreas Gohr            // prepare parameters - we only use those that exist in the SQL
68770a89417SAndreas Gohr            foreach ($arguments as $key => $value) {
68870a89417SAndreas Gohr                if (is_array($value)) continue;
68970a89417SAndreas Gohr                if (is_object($value)) continue;
69070a89417SAndreas Gohr                if ($key[0] != ':') $key = ":$key"; // prefix with colon if needed
69114119d44SAndreas Gohr                if (strpos($sql, $key) === false) continue; // skip if parameter is missing
69214119d44SAndreas Gohr
69314119d44SAndreas Gohr                if (is_int($value)) {
69414119d44SAndreas Gohr                    $sth->bindValue($key, $value, PDO::PARAM_INT);
69514119d44SAndreas Gohr                } else {
69614119d44SAndreas Gohr                    $sth->bindValue($key, $value);
69714119d44SAndreas Gohr                }
698f6cd8a7fSphjanderson                $params[$key] = $value; //remember for debugging
69970a89417SAndreas Gohr            }
70070a89417SAndreas Gohr
70114119d44SAndreas Gohr            $sth->execute();
702f695c447SAndreas Gohr            if (strtolower(substr($sql, 0, 6)) == 'select') {
70370a89417SAndreas Gohr                $result = $sth->fetchAll();
704f695c447SAndreas Gohr            } else {
705f695c447SAndreas Gohr                $result = $sth->rowCount();
706f695c447SAndreas Gohr            }
7075de3a6a5SAndreas Gohr        } catch (Exception $e) {
7084fb8dfabSAndreas Gohr            // report the caller's line
7094fb8dfabSAndreas Gohr            $trace = debug_backtrace();
7104fb8dfabSAndreas Gohr            $line = $trace[0]['line'];
711*3213bf4eSAndreas Gohr            $dsql = $this->debugSQL($sql, $params, !defined('DOKU_UNITTEST'));
712*3213bf4eSAndreas Gohr            $this->debugMsg($e, -1, $line);
713*3213bf4eSAndreas Gohr            $this->debugMsg("SQL: <pre>$dsql</pre>", -1, $line);
71470a89417SAndreas Gohr            $result = false;
7151600c7ccSAndreas Gohr        }
71670a89417SAndreas Gohr        $sth->closeCursor();
71770a89417SAndreas Gohr        $sth = null;
71870a89417SAndreas Gohr
7195de3a6a5SAndreas Gohr        return $result;
7205de3a6a5SAndreas Gohr    }
72170a89417SAndreas Gohr
72270a89417SAndreas Gohr    /**
723f64dbc90SAndreas Gohr     * Wrapper around msg() but outputs only when debug is enabled
724f64dbc90SAndreas Gohr     *
725f64dbc90SAndreas Gohr     * @param string|Exception $message
726f64dbc90SAndreas Gohr     * @param int $err
727f64dbc90SAndreas Gohr     * @param int $line
728f64dbc90SAndreas Gohr     */
729*3213bf4eSAndreas Gohr    protected function debugMsg($message, $err = 0, $line = 0)
730*3213bf4eSAndreas Gohr    {
731f64dbc90SAndreas Gohr        if (!$this->getConf('debug')) return;
732f64dbc90SAndreas Gohr        if (is_a($message, 'Exception')) {
733f64dbc90SAndreas Gohr            $err = -1;
734f64dbc90SAndreas Gohr            $msg = $message->getMessage();
7354fb8dfabSAndreas Gohr            if (!$line) $line = $message->getLine();
736f64dbc90SAndreas Gohr        } else {
737f64dbc90SAndreas Gohr            $msg = $message;
738f64dbc90SAndreas Gohr        }
739f64dbc90SAndreas Gohr
740f64dbc90SAndreas Gohr        if (defined('DOKU_UNITTEST')) {
741f64dbc90SAndreas Gohr            printf("\n%s, %s:%d\n", $msg, __FILE__, $line);
742f64dbc90SAndreas Gohr        } else {
743f64dbc90SAndreas Gohr            msg('authpdo: ' . $msg, $err, $line, __FILE__);
744f64dbc90SAndreas Gohr        }
745f64dbc90SAndreas Gohr    }
7465de3a6a5SAndreas Gohr
7475de3a6a5SAndreas Gohr    /**
7485de3a6a5SAndreas Gohr     * Check if the given config strings are set
7495de3a6a5SAndreas Gohr     *
7505de3a6a5SAndreas Gohr     * @author  Matthias Grimm <matthiasgrimm@users.sourceforge.net>
7515de3a6a5SAndreas Gohr     *
7525de3a6a5SAndreas Gohr     * @param   string[] $keys
7535de3a6a5SAndreas Gohr     * @return  bool
7545de3a6a5SAndreas Gohr     */
755*3213bf4eSAndreas Gohr    protected function checkConfig($keys)
756*3213bf4eSAndreas Gohr    {
7575de3a6a5SAndreas Gohr        foreach ($keys as $key) {
758ad4d5631SAndreas Gohr            $params = explode(':', $key);
759ad4d5631SAndreas Gohr            $key = array_shift($params);
760ad4d5631SAndreas Gohr            $sql = trim($this->getConf($key));
761ad4d5631SAndreas Gohr
762ad4d5631SAndreas Gohr            // check if sql is set
763ad4d5631SAndreas Gohr            if (!$sql) return false;
764ad4d5631SAndreas Gohr            // check if needed params are there
765ad4d5631SAndreas Gohr            foreach ($params as $param) {
766ad4d5631SAndreas Gohr                if (strpos($sql, ":$param") === false) return false;
767ad4d5631SAndreas Gohr            }
7685de3a6a5SAndreas Gohr        }
7695de3a6a5SAndreas Gohr
7705de3a6a5SAndreas Gohr        return true;
7715de3a6a5SAndreas Gohr    }
7725de3a6a5SAndreas Gohr
7735de3a6a5SAndreas Gohr    /**
7745de3a6a5SAndreas Gohr     * create an approximation of the SQL string with parameters replaced
7755de3a6a5SAndreas Gohr     *
7765de3a6a5SAndreas Gohr     * @param string $sql
7775de3a6a5SAndreas Gohr     * @param array $params
7785de3a6a5SAndreas Gohr     * @param bool $htmlescape Should the result be escaped for output in HTML?
7795de3a6a5SAndreas Gohr     * @return string
7805de3a6a5SAndreas Gohr     */
781*3213bf4eSAndreas Gohr    protected function debugSQL($sql, $params, $htmlescape = true)
782*3213bf4eSAndreas Gohr    {
7835de3a6a5SAndreas Gohr        foreach ($params as $key => $val) {
7845de3a6a5SAndreas Gohr            if (is_int($val)) {
7855de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val, PDO::PARAM_INT);
7865de3a6a5SAndreas Gohr            } elseif (is_bool($val)) {
7875de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val, PDO::PARAM_BOOL);
7885de3a6a5SAndreas Gohr            } elseif (is_null($val)) {
7895de3a6a5SAndreas Gohr                $val = 'NULL';
7905de3a6a5SAndreas Gohr            } else {
7915de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val);
7925de3a6a5SAndreas Gohr            }
7935de3a6a5SAndreas Gohr            $sql = str_replace($key, $val, $sql);
7945de3a6a5SAndreas Gohr        }
7955de3a6a5SAndreas Gohr        if ($htmlescape) $sql = hsc($sql);
7965de3a6a5SAndreas Gohr        return $sql;
7975de3a6a5SAndreas Gohr    }
798f64dbc90SAndreas Gohr}
799f64dbc90SAndreas Gohr
800f64dbc90SAndreas Gohr// vim:ts=4:sw=4:et:
801