xref: /dokuwiki/lib/plugins/authpdo/auth.php (revision 5de3a6a5ad40cfd5f62c9a028f248d53e3f9da6d)
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
12f64dbc90SAndreas Gohrclass auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
13f64dbc90SAndreas Gohr
14f64dbc90SAndreas Gohr    /** @var PDO */
15f64dbc90SAndreas Gohr    protected $pdo;
16f64dbc90SAndreas Gohr
17f64dbc90SAndreas Gohr    /**
18f64dbc90SAndreas Gohr     * Constructor.
19f64dbc90SAndreas Gohr     */
20f64dbc90SAndreas Gohr    public function __construct() {
21f64dbc90SAndreas Gohr        parent::__construct(); // for compatibility
22f64dbc90SAndreas Gohr
23f64dbc90SAndreas Gohr        if(!class_exists('PDO')) {
24f64dbc90SAndreas Gohr            $this->_debug('PDO extension for PHP not found.', -1, __LINE__);
25f64dbc90SAndreas Gohr            $this->success = false;
26f64dbc90SAndreas Gohr            return;
27f64dbc90SAndreas Gohr        }
28f64dbc90SAndreas Gohr
29f64dbc90SAndreas Gohr        if(!$this->getConf('dsn')) {
30f64dbc90SAndreas Gohr            $this->_debug('No DSN specified', -1, __LINE__);
31f64dbc90SAndreas Gohr            $this->success = false;
32f64dbc90SAndreas Gohr            return;
33f64dbc90SAndreas Gohr        }
34f64dbc90SAndreas Gohr
35f64dbc90SAndreas Gohr        try {
36f64dbc90SAndreas Gohr            $this->pdo = new PDO(
37f64dbc90SAndreas Gohr                $this->getConf('dsn'),
38f64dbc90SAndreas Gohr                $this->getConf('user'),
39f64dbc90SAndreas Gohr                $this->getConf('pass'),
40f64dbc90SAndreas Gohr                array(
4170a89417SAndreas Gohr                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // always fetch as array
4270a89417SAndreas Gohr                    PDO::ATTR_EMULATE_PREPARES => true, // emulating prepares allows us to reuse param names
43*5de3a6a5SAndreas Gohr                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
44f64dbc90SAndreas Gohr                )
45f64dbc90SAndreas Gohr            );
46f64dbc90SAndreas Gohr        } catch(PDOException $e) {
47f64dbc90SAndreas Gohr            $this->_debug($e);
48f64dbc90SAndreas Gohr            $this->success = false;
49f64dbc90SAndreas Gohr            return;
50f64dbc90SAndreas Gohr        }
51f64dbc90SAndreas Gohr
52f64dbc90SAndreas Gohr        // FIXME set capabilities accordingly
53f64dbc90SAndreas Gohr        //$this->cando['addUser']     = false; // can Users be created?
54f64dbc90SAndreas Gohr        //$this->cando['delUser']     = false; // can Users be deleted?
55f64dbc90SAndreas Gohr        //$this->cando['modLogin']    = false; // can login names be changed?
56f64dbc90SAndreas Gohr        //$this->cando['modPass']     = false; // can passwords be changed?
57f64dbc90SAndreas Gohr        //$this->cando['modName']     = false; // can real names be changed?
58f64dbc90SAndreas Gohr        //$this->cando['modMail']     = false; // can emails be changed?
59f64dbc90SAndreas Gohr        //$this->cando['modGroups']   = false; // can groups be changed?
60f64dbc90SAndreas Gohr        //$this->cando['getUsers']    = false; // can a (filtered) list of users be retrieved?
61f64dbc90SAndreas Gohr        //$this->cando['getUserCount']= false; // can the number of users be retrieved?
62f64dbc90SAndreas Gohr        //$this->cando['getGroups']   = false; // can a list of available groups be retrieved?
63f64dbc90SAndreas Gohr        //$this->cando['external']    = false; // does the module do external auth checking?
64f64dbc90SAndreas Gohr        //$this->cando['logout']      = true; // can the user logout again? (eg. not possible with HTTP auth)
65f64dbc90SAndreas Gohr
66f64dbc90SAndreas Gohr        // FIXME intialize your auth system and set success to true, if successful
67f64dbc90SAndreas Gohr        $this->success = true;
68f64dbc90SAndreas Gohr    }
69f64dbc90SAndreas Gohr
70f64dbc90SAndreas Gohr    /**
71f64dbc90SAndreas Gohr     * Check user+password
72f64dbc90SAndreas Gohr     *
73f64dbc90SAndreas Gohr     * May be ommited if trustExternal is used.
74f64dbc90SAndreas Gohr     *
75f64dbc90SAndreas Gohr     * @param   string $user the user name
76f64dbc90SAndreas Gohr     * @param   string $pass the clear text password
77f64dbc90SAndreas Gohr     * @return  bool
78f64dbc90SAndreas Gohr     */
79f64dbc90SAndreas Gohr    public function checkPass($user, $pass) {
80f64dbc90SAndreas Gohr
81f64dbc90SAndreas Gohr        $data = $this->_selectUser($user);
82f64dbc90SAndreas Gohr        if($data == false) return false;
83f64dbc90SAndreas Gohr
84f64dbc90SAndreas Gohr        if(isset($data['hash'])) {
85f64dbc90SAndreas Gohr            // hashed password
86f64dbc90SAndreas Gohr            $passhash = new PassHash();
87f64dbc90SAndreas Gohr            return $passhash->verify_hash($pass, $data['hash']);
88f64dbc90SAndreas Gohr        } else {
89f64dbc90SAndreas Gohr            // clear text password in the database O_o
90f64dbc90SAndreas Gohr            return ($pass == $data['clear']);
91f64dbc90SAndreas Gohr        }
92f64dbc90SAndreas Gohr    }
93f64dbc90SAndreas Gohr
94f64dbc90SAndreas Gohr    /**
95f64dbc90SAndreas Gohr     * Return user info
96f64dbc90SAndreas Gohr     *
97f64dbc90SAndreas Gohr     * Returns info about the given user needs to contain
98f64dbc90SAndreas Gohr     * at least these fields:
99f64dbc90SAndreas Gohr     *
100f64dbc90SAndreas Gohr     * name string  full name of the user
101f64dbc90SAndreas Gohr     * mail string  email addres of the user
102f64dbc90SAndreas Gohr     * grps array   list of groups the user is in
103f64dbc90SAndreas Gohr     *
104f64dbc90SAndreas Gohr     * @param   string $user the user name
105f64dbc90SAndreas Gohr     * @param   bool $requireGroups whether or not the returned data must include groups
106f64dbc90SAndreas Gohr     * @return array containing user data or false
107f64dbc90SAndreas Gohr     */
108f64dbc90SAndreas Gohr    public function getUserData($user, $requireGroups = true) {
109f64dbc90SAndreas Gohr        $data = $this->_selectUser($user);
110f64dbc90SAndreas Gohr        if($data == false) return false;
111f64dbc90SAndreas Gohr
11270a89417SAndreas Gohr        if(isset($data['hash'])) unset($data['hash']);
11370a89417SAndreas Gohr        if(isset($data['clean'])) unset($data['clean']);
114f64dbc90SAndreas Gohr
11570a89417SAndreas Gohr        if($requireGroups) {
11670a89417SAndreas Gohr            $data['grps'] = $this->_selectUserGroups($data);
117*5de3a6a5SAndreas Gohr            if($data['grps'] === false) return false;
118f64dbc90SAndreas Gohr        }
119f64dbc90SAndreas Gohr
120f64dbc90SAndreas Gohr        return $data;
121f64dbc90SAndreas Gohr    }
122f64dbc90SAndreas Gohr
123f64dbc90SAndreas Gohr    /**
124f64dbc90SAndreas Gohr     * Create a new User [implement only where required/possible]
125f64dbc90SAndreas Gohr     *
126f64dbc90SAndreas Gohr     * Returns false if the user already exists, null when an error
127f64dbc90SAndreas Gohr     * occurred and true if everything went well.
128f64dbc90SAndreas Gohr     *
129f64dbc90SAndreas Gohr     * The new user HAS TO be added to the default group by this
130f64dbc90SAndreas Gohr     * function!
131f64dbc90SAndreas Gohr     *
132f64dbc90SAndreas Gohr     * Set addUser capability when implemented
133f64dbc90SAndreas Gohr     *
134f64dbc90SAndreas Gohr     * @param  string $user
135*5de3a6a5SAndreas Gohr     * @param  string $clear
136f64dbc90SAndreas Gohr     * @param  string $name
137f64dbc90SAndreas Gohr     * @param  string $mail
138f64dbc90SAndreas Gohr     * @param  null|array $grps
139f64dbc90SAndreas Gohr     * @return bool|null
140f64dbc90SAndreas Gohr     */
141*5de3a6a5SAndreas Gohr    public function createUser($user, $clear, $name, $mail, $grps = null) {
142*5de3a6a5SAndreas Gohr        global $conf;
143*5de3a6a5SAndreas Gohr
144*5de3a6a5SAndreas Gohr        if(($info = $this->getUserData($user, false)) !== false) {
145*5de3a6a5SAndreas Gohr            msg($this->getLang('userexists'), -1);
146*5de3a6a5SAndreas Gohr            return false; // user already exists
147*5de3a6a5SAndreas Gohr        }
148*5de3a6a5SAndreas Gohr
149*5de3a6a5SAndreas Gohr        // prepare data
150*5de3a6a5SAndreas Gohr        if($grps == null) $grps = array();
151*5de3a6a5SAndreas Gohr        $grps[] = $conf['defaultgroup'];
152*5de3a6a5SAndreas Gohr        $grps = array_unique($grps);
153*5de3a6a5SAndreas Gohr        $hash = auth_cryptPassword($clear);
154*5de3a6a5SAndreas Gohr        $userdata = compact('user', 'clear', 'hash', 'name', 'mail');
155*5de3a6a5SAndreas Gohr
156*5de3a6a5SAndreas Gohr        // action protected by transaction
157*5de3a6a5SAndreas Gohr        $this->pdo->beginTransaction();
158*5de3a6a5SAndreas Gohr        {
159*5de3a6a5SAndreas Gohr            // insert the user
160*5de3a6a5SAndreas Gohr            $ok = $this->_query($this->getConf('insert-user'), $userdata);
161*5de3a6a5SAndreas Gohr            if($ok === false) goto FAIL;
162*5de3a6a5SAndreas Gohr            $userdata = $this->getUserData($user, false);
163*5de3a6a5SAndreas Gohr            if($userdata === false) goto FAIL;
164*5de3a6a5SAndreas Gohr
165*5de3a6a5SAndreas Gohr            // create all groups that do not exist, the refetch the groups
166*5de3a6a5SAndreas Gohr            $allgroups = $this->_selectGroups();
167*5de3a6a5SAndreas Gohr            foreach($grps as $group) {
168*5de3a6a5SAndreas Gohr                if(!isset($allgroups[$group])) {
169*5de3a6a5SAndreas Gohr                    $ok = $this->_insertGroup($group);
170*5de3a6a5SAndreas Gohr                    if($ok === false) goto FAIL;
171*5de3a6a5SAndreas Gohr                }
172*5de3a6a5SAndreas Gohr            }
173*5de3a6a5SAndreas Gohr            $allgroups = $this->_selectGroups();
174*5de3a6a5SAndreas Gohr
175*5de3a6a5SAndreas Gohr            // add user to the groups
176*5de3a6a5SAndreas Gohr            foreach($grps as $group) {
177*5de3a6a5SAndreas Gohr                $ok = $this->_joinGroup($userdata, $allgroups[$group]);
178*5de3a6a5SAndreas Gohr                if($ok === false) goto FAIL;
179*5de3a6a5SAndreas Gohr            }
180*5de3a6a5SAndreas Gohr        }
181*5de3a6a5SAndreas Gohr        $this->pdo->commit();
182*5de3a6a5SAndreas Gohr        return true;
183*5de3a6a5SAndreas Gohr
184*5de3a6a5SAndreas Gohr        // something went wrong, rollback
185*5de3a6a5SAndreas Gohr        FAIL:
186*5de3a6a5SAndreas Gohr        $this->pdo->rollBack();
187*5de3a6a5SAndreas Gohr        $this->_debug('Transaction rolled back', 0, __LINE__);
188*5de3a6a5SAndreas Gohr        return null; // return error
189*5de3a6a5SAndreas Gohr    }
190f64dbc90SAndreas Gohr
191f64dbc90SAndreas Gohr    /**
192f64dbc90SAndreas Gohr     * Modify user data [implement only where required/possible]
193f64dbc90SAndreas Gohr     *
194f64dbc90SAndreas Gohr     * Set the mod* capabilities according to the implemented features
195f64dbc90SAndreas Gohr     *
196f64dbc90SAndreas Gohr     * @param   string $user nick of the user to be changed
197f64dbc90SAndreas Gohr     * @param   array $changes array of field/value pairs to be changed (password will be clear text)
198f64dbc90SAndreas Gohr     * @return  bool
199f64dbc90SAndreas Gohr     */
200f64dbc90SAndreas Gohr    //public function modifyUser($user, $changes) {
201f64dbc90SAndreas Gohr    // FIXME implement
202f64dbc90SAndreas Gohr    //    return false;
203f64dbc90SAndreas Gohr    //}
204f64dbc90SAndreas Gohr
205f64dbc90SAndreas Gohr    /**
206f64dbc90SAndreas Gohr     * Delete one or more users [implement only where required/possible]
207f64dbc90SAndreas Gohr     *
208f64dbc90SAndreas Gohr     * Set delUser capability when implemented
209f64dbc90SAndreas Gohr     *
210f64dbc90SAndreas Gohr     * @param   array $users
211f64dbc90SAndreas Gohr     * @return  int    number of users deleted
212f64dbc90SAndreas Gohr     */
213f64dbc90SAndreas Gohr    //public function deleteUsers($users) {
214f64dbc90SAndreas Gohr    // FIXME implement
215f64dbc90SAndreas Gohr    //    return false;
216f64dbc90SAndreas Gohr    //}
217f64dbc90SAndreas Gohr
218f64dbc90SAndreas Gohr    /**
219f64dbc90SAndreas Gohr     * Bulk retrieval of user data [implement only where required/possible]
220f64dbc90SAndreas Gohr     *
221f64dbc90SAndreas Gohr     * Set getUsers capability when implemented
222f64dbc90SAndreas Gohr     *
223f64dbc90SAndreas Gohr     * @param   int $start index of first user to be returned
224f64dbc90SAndreas Gohr     * @param   int $limit max number of users to be returned
225f64dbc90SAndreas Gohr     * @param   array $filter array of field/pattern pairs, null for no filter
226f64dbc90SAndreas Gohr     * @return  array list of userinfo (refer getUserData for internal userinfo details)
227f64dbc90SAndreas Gohr     */
228f64dbc90SAndreas Gohr    //public function retrieveUsers($start = 0, $limit = -1, $filter = null) {
229f64dbc90SAndreas Gohr    // FIXME implement
230f64dbc90SAndreas Gohr    //    return array();
231f64dbc90SAndreas Gohr    //}
232f64dbc90SAndreas Gohr
233f64dbc90SAndreas Gohr    /**
234f64dbc90SAndreas Gohr     * Return a count of the number of user which meet $filter criteria
235f64dbc90SAndreas Gohr     * [should be implemented whenever retrieveUsers is implemented]
236f64dbc90SAndreas Gohr     *
237f64dbc90SAndreas Gohr     * Set getUserCount capability when implemented
238f64dbc90SAndreas Gohr     *
239f64dbc90SAndreas Gohr     * @param  array $filter array of field/pattern pairs, empty array for no filter
240f64dbc90SAndreas Gohr     * @return int
241f64dbc90SAndreas Gohr     */
242f64dbc90SAndreas Gohr    //public function getUserCount($filter = array()) {
243f64dbc90SAndreas Gohr    // FIXME implement
244f64dbc90SAndreas Gohr    //    return 0;
245f64dbc90SAndreas Gohr    //}
246f64dbc90SAndreas Gohr
247f64dbc90SAndreas Gohr    /**
248f64dbc90SAndreas Gohr     * Define a group [implement only where required/possible]
249f64dbc90SAndreas Gohr     *
250f64dbc90SAndreas Gohr     * Set addGroup capability when implemented
251f64dbc90SAndreas Gohr     *
252f64dbc90SAndreas Gohr     * @param   string $group
253f64dbc90SAndreas Gohr     * @return  bool
254f64dbc90SAndreas Gohr     */
255f64dbc90SAndreas Gohr    //public function addGroup($group) {
256f64dbc90SAndreas Gohr    // FIXME implement
257f64dbc90SAndreas Gohr    //    return false;
258f64dbc90SAndreas Gohr    //}
259f64dbc90SAndreas Gohr
260f64dbc90SAndreas Gohr    /**
261*5de3a6a5SAndreas Gohr     * Retrieve groups
262f64dbc90SAndreas Gohr     *
263f64dbc90SAndreas Gohr     * Set getGroups capability when implemented
264f64dbc90SAndreas Gohr     *
265f64dbc90SAndreas Gohr     * @param   int $start
266f64dbc90SAndreas Gohr     * @param   int $limit
267f64dbc90SAndreas Gohr     * @return  array
268f64dbc90SAndreas Gohr     */
269*5de3a6a5SAndreas Gohr    public function retrieveGroups($start = 0, $limit = 0) {
270*5de3a6a5SAndreas Gohr        $groups = array_keys($this->_selectGroups());
271*5de3a6a5SAndreas Gohr        if($groups === false) return array();
272f64dbc90SAndreas Gohr
273*5de3a6a5SAndreas Gohr        if(!$limit) {
274*5de3a6a5SAndreas Gohr            return array_splice($groups, $start);
275*5de3a6a5SAndreas Gohr        } else {
276*5de3a6a5SAndreas Gohr            return array_splice($groups, $start, $limit);
277f64dbc90SAndreas Gohr        }
278f64dbc90SAndreas Gohr    }
279f64dbc90SAndreas Gohr
280f64dbc90SAndreas Gohr    /**
281f64dbc90SAndreas Gohr     * Select data of a specified user
282f64dbc90SAndreas Gohr     *
283*5de3a6a5SAndreas Gohr     * @param string $user the user name
284*5de3a6a5SAndreas Gohr     * @return bool|array user data, false on error
285f64dbc90SAndreas Gohr     */
286f64dbc90SAndreas Gohr    protected function _selectUser($user) {
287f64dbc90SAndreas Gohr        $sql = $this->getConf('select-user');
288f64dbc90SAndreas Gohr
289*5de3a6a5SAndreas Gohr        $result = $this->_query($sql, array(':user' => $user));
29070a89417SAndreas Gohr        if(!$result) return false;
291f64dbc90SAndreas Gohr
29270a89417SAndreas Gohr        if(count($result) > 1) {
293f64dbc90SAndreas Gohr            $this->_debug('Found more than one matching user', -1, __LINE__);
294f64dbc90SAndreas Gohr            return false;
295f64dbc90SAndreas Gohr        }
296f64dbc90SAndreas Gohr
297f64dbc90SAndreas Gohr        $data = array_shift($result);
298f64dbc90SAndreas Gohr        $dataok = true;
299f64dbc90SAndreas Gohr
300f64dbc90SAndreas Gohr        if(!isset($data['user'])) {
301f64dbc90SAndreas Gohr            $this->_debug("Statement did not return 'user' attribute", -1, __LINE__);
302f64dbc90SAndreas Gohr            $dataok = false;
303f64dbc90SAndreas Gohr        }
304f64dbc90SAndreas Gohr        if(!isset($data['hash']) && !isset($data['clear'])) {
305f64dbc90SAndreas Gohr            $this->_debug("Statement did not return 'clear' or 'hash' attribute", -1, __LINE__);
306f64dbc90SAndreas Gohr            $dataok = false;
307f64dbc90SAndreas Gohr        }
308f64dbc90SAndreas Gohr        if(!isset($data['name'])) {
309f64dbc90SAndreas Gohr            $this->_debug("Statement did not return 'name' attribute", -1, __LINE__);
310f64dbc90SAndreas Gohr            $dataok = false;
311f64dbc90SAndreas Gohr        }
312f64dbc90SAndreas Gohr        if(!isset($data['mail'])) {
313f64dbc90SAndreas Gohr            $this->_debug("Statement did not return 'mail' attribute", -1, __LINE__);
314f64dbc90SAndreas Gohr            $dataok = false;
315f64dbc90SAndreas Gohr        }
316f64dbc90SAndreas Gohr
317f64dbc90SAndreas Gohr        if(!$dataok) return false;
318f64dbc90SAndreas Gohr        return $data;
319f64dbc90SAndreas Gohr    }
320f64dbc90SAndreas Gohr
321f64dbc90SAndreas Gohr    /**
32270a89417SAndreas Gohr     * Select all groups of a user
32370a89417SAndreas Gohr     *
32470a89417SAndreas Gohr     * @param array $userdata The userdata as returned by _selectUser()
325*5de3a6a5SAndreas Gohr     * @return array|bool list of group names, false on error
32670a89417SAndreas Gohr     */
32770a89417SAndreas Gohr    protected function _selectUserGroups($userdata) {
32870a89417SAndreas Gohr        global $conf;
32970a89417SAndreas Gohr        $sql = $this->getConf('select-user-groups');
330*5de3a6a5SAndreas Gohr        $result = $this->_query($sql, $userdata);
331*5de3a6a5SAndreas Gohr        if($result === false) return false;
33270a89417SAndreas Gohr
33370a89417SAndreas Gohr        $groups = array($conf['defaultgroup']); // always add default config
334*5de3a6a5SAndreas Gohr        foreach($result as $row) {
335*5de3a6a5SAndreas Gohr            if(!isset($row['group'])) {
336*5de3a6a5SAndreas Gohr                $this->_debug("No 'group' field returned in select-user-groups statement");
337*5de3a6a5SAndreas Gohr                return false;
338*5de3a6a5SAndreas Gohr            }
33970a89417SAndreas Gohr            $groups[] = $row['group'];
34070a89417SAndreas Gohr        }
34170a89417SAndreas Gohr
34270a89417SAndreas Gohr        $groups = array_unique($groups);
34370a89417SAndreas Gohr        sort($groups);
34470a89417SAndreas Gohr        return $groups;
34570a89417SAndreas Gohr    }
34670a89417SAndreas Gohr
34770a89417SAndreas Gohr    /**
348*5de3a6a5SAndreas Gohr     * Select all available groups
349*5de3a6a5SAndreas Gohr     *
350*5de3a6a5SAndreas Gohr     * @todo this should be cached
351*5de3a6a5SAndreas Gohr     * @return array|bool list of all available groups and their properties
352*5de3a6a5SAndreas Gohr     */
353*5de3a6a5SAndreas Gohr    protected function _selectGroups() {
354*5de3a6a5SAndreas Gohr        $sql = $this->getConf('select-groups');
355*5de3a6a5SAndreas Gohr        $result = $this->_query($sql);
356*5de3a6a5SAndreas Gohr        if($result === false) return false;
357*5de3a6a5SAndreas Gohr
358*5de3a6a5SAndreas Gohr        $groups = array();
359*5de3a6a5SAndreas Gohr        foreach($result as $row) {
360*5de3a6a5SAndreas Gohr            if(!isset($row['group'])) {
361*5de3a6a5SAndreas Gohr                $this->_debug("No 'group' field returned from select-groups statement", -1, __LINE__);
362*5de3a6a5SAndreas Gohr                return false;
363*5de3a6a5SAndreas Gohr            }
364*5de3a6a5SAndreas Gohr
365*5de3a6a5SAndreas Gohr            // relayout result with group name as key
366*5de3a6a5SAndreas Gohr            $group = $row['group'];
367*5de3a6a5SAndreas Gohr            $groups[$group] = $row;
368*5de3a6a5SAndreas Gohr        }
369*5de3a6a5SAndreas Gohr
370*5de3a6a5SAndreas Gohr        ksort($groups);
371*5de3a6a5SAndreas Gohr        return $groups;
372*5de3a6a5SAndreas Gohr    }
373*5de3a6a5SAndreas Gohr
374*5de3a6a5SAndreas Gohr    /**
375*5de3a6a5SAndreas Gohr     * Create a new group with the given name
376*5de3a6a5SAndreas Gohr     *
377*5de3a6a5SAndreas Gohr     * @param string $group
378*5de3a6a5SAndreas Gohr     * @return bool
379*5de3a6a5SAndreas Gohr     */
380*5de3a6a5SAndreas Gohr    protected function _insertGroup($group) {
381*5de3a6a5SAndreas Gohr        $sql = $this->getConf('insert-group');
382*5de3a6a5SAndreas Gohr
383*5de3a6a5SAndreas Gohr        $result = $this->_query($sql, array(':group' => $group));
384*5de3a6a5SAndreas Gohr        if($result === false) return false;
385*5de3a6a5SAndreas Gohr        return true;
386*5de3a6a5SAndreas Gohr    }
387*5de3a6a5SAndreas Gohr
388*5de3a6a5SAndreas Gohr    /**
389*5de3a6a5SAndreas Gohr     * Enters the user to the group
390*5de3a6a5SAndreas Gohr     *
391*5de3a6a5SAndreas Gohr     * @param array $userdata all the user data
392*5de3a6a5SAndreas Gohr     * @param array $groupdata all the group data
393*5de3a6a5SAndreas Gohr     * @return bool
394*5de3a6a5SAndreas Gohr     */
395*5de3a6a5SAndreas Gohr    protected function _joinGroup($userdata, $groupdata) {
396*5de3a6a5SAndreas Gohr        $data = array_merge($userdata, $groupdata);
397*5de3a6a5SAndreas Gohr        $sql = $this->getConf('join-group');
398*5de3a6a5SAndreas Gohr        $result = $this->_query($sql, $data);
399*5de3a6a5SAndreas Gohr        if($result === false) return false;
400*5de3a6a5SAndreas Gohr        return true;
401*5de3a6a5SAndreas Gohr    }
402*5de3a6a5SAndreas Gohr
403*5de3a6a5SAndreas Gohr    /**
40470a89417SAndreas Gohr     * Executes a query
40570a89417SAndreas Gohr     *
40670a89417SAndreas Gohr     * @param string $sql The SQL statement to execute
40770a89417SAndreas Gohr     * @param array $arguments Named parameters to be used in the statement
408*5de3a6a5SAndreas Gohr     * @return array|bool The result as associative array, false on error
40970a89417SAndreas Gohr     */
410*5de3a6a5SAndreas Gohr    protected function _query($sql, $arguments = array()) {
411*5de3a6a5SAndreas Gohr        if(empty($sql)) {
412*5de3a6a5SAndreas Gohr            $this->_debug('No SQL query given', -1, __LINE__);
413*5de3a6a5SAndreas Gohr            return false;
414*5de3a6a5SAndreas Gohr        }
415*5de3a6a5SAndreas Gohr
41670a89417SAndreas Gohr        // prepare parameters - we only use those that exist in the SQL
41770a89417SAndreas Gohr        $params = array();
41870a89417SAndreas Gohr        foreach($arguments as $key => $value) {
41970a89417SAndreas Gohr            if(is_array($value)) continue;
42070a89417SAndreas Gohr            if(is_object($value)) continue;
42170a89417SAndreas Gohr            if($key[0] != ':') $key = ":$key"; // prefix with colon if needed
42270a89417SAndreas Gohr            if(strpos($sql, $key) !== false) $params[$key] = $value;
42370a89417SAndreas Gohr        }
42470a89417SAndreas Gohr
42570a89417SAndreas Gohr        // execute
42670a89417SAndreas Gohr        $sth = $this->pdo->prepare($sql);
427*5de3a6a5SAndreas Gohr        try {
42870a89417SAndreas Gohr            $sth->execute($params);
42970a89417SAndreas Gohr            $result = $sth->fetchAll();
430*5de3a6a5SAndreas Gohr        } catch(Exception $e) {
431*5de3a6a5SAndreas Gohr            $dsql = $this->_debugSQL($sql, $params, !defined('DOKU_UNITTEST'));
432*5de3a6a5SAndreas Gohr            $this->_debug($e);
433*5de3a6a5SAndreas Gohr            $this->_debug("SQL: <pre>$dsql</pre>", -1, $e->getLine());
43470a89417SAndreas Gohr            $result = false;
435*5de3a6a5SAndreas Gohr        } finally {
43670a89417SAndreas Gohr            $sth->closeCursor();
43770a89417SAndreas Gohr            $sth = null;
43870a89417SAndreas Gohr        }
43970a89417SAndreas Gohr
440*5de3a6a5SAndreas Gohr        return $result;
441*5de3a6a5SAndreas Gohr    }
44270a89417SAndreas Gohr
44370a89417SAndreas Gohr    /**
444f64dbc90SAndreas Gohr     * Wrapper around msg() but outputs only when debug is enabled
445f64dbc90SAndreas Gohr     *
446f64dbc90SAndreas Gohr     * @param string|Exception $message
447f64dbc90SAndreas Gohr     * @param int $err
448f64dbc90SAndreas Gohr     * @param int $line
449f64dbc90SAndreas Gohr     */
450f64dbc90SAndreas Gohr    protected function _debug($message, $err = 0, $line = 0) {
451f64dbc90SAndreas Gohr        if(!$this->getConf('debug')) return;
452f64dbc90SAndreas Gohr        if(is_a($message, 'Exception')) {
453f64dbc90SAndreas Gohr            $err = -1;
454f64dbc90SAndreas Gohr            $line = $message->getLine();
455f64dbc90SAndreas Gohr            $msg = $message->getMessage();
456f64dbc90SAndreas Gohr        } else {
457f64dbc90SAndreas Gohr            $msg = $message;
458f64dbc90SAndreas Gohr        }
459f64dbc90SAndreas Gohr
460f64dbc90SAndreas Gohr        if(defined('DOKU_UNITTEST')) {
461f64dbc90SAndreas Gohr            printf("\n%s, %s:%d\n", $msg, __FILE__, $line);
462f64dbc90SAndreas Gohr        } else {
463f64dbc90SAndreas Gohr            msg('authpdo: ' . $msg, $err, $line, __FILE__);
464f64dbc90SAndreas Gohr        }
465f64dbc90SAndreas Gohr    }
466*5de3a6a5SAndreas Gohr
467*5de3a6a5SAndreas Gohr    /**
468*5de3a6a5SAndreas Gohr     * Check if the given config strings are set
469*5de3a6a5SAndreas Gohr     *
470*5de3a6a5SAndreas Gohr     * @author  Matthias Grimm <matthiasgrimm@users.sourceforge.net>
471*5de3a6a5SAndreas Gohr     *
472*5de3a6a5SAndreas Gohr     * @param   string[] $keys
473*5de3a6a5SAndreas Gohr     * @return  bool
474*5de3a6a5SAndreas Gohr     */
475*5de3a6a5SAndreas Gohr    protected function _chkcnf($keys) {
476*5de3a6a5SAndreas Gohr        foreach($keys as $key) {
477*5de3a6a5SAndreas Gohr            if(!$this->getConf($key)) return false;
478*5de3a6a5SAndreas Gohr        }
479*5de3a6a5SAndreas Gohr
480*5de3a6a5SAndreas Gohr        return true;
481*5de3a6a5SAndreas Gohr    }
482*5de3a6a5SAndreas Gohr
483*5de3a6a5SAndreas Gohr    /**
484*5de3a6a5SAndreas Gohr     * create an approximation of the SQL string with parameters replaced
485*5de3a6a5SAndreas Gohr     *
486*5de3a6a5SAndreas Gohr     * @param string $sql
487*5de3a6a5SAndreas Gohr     * @param array $params
488*5de3a6a5SAndreas Gohr     * @param bool $htmlescape Should the result be escaped for output in HTML?
489*5de3a6a5SAndreas Gohr     * @return string
490*5de3a6a5SAndreas Gohr     */
491*5de3a6a5SAndreas Gohr    protected function _debugSQL($sql, $params, $htmlescape=true) {
492*5de3a6a5SAndreas Gohr        foreach($params as $key => $val) {
493*5de3a6a5SAndreas Gohr            if(is_int($val)) {
494*5de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val, PDO::PARAM_INT);
495*5de3a6a5SAndreas Gohr            } elseif(is_bool($val)) {
496*5de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val, PDO::PARAM_BOOL);
497*5de3a6a5SAndreas Gohr            } elseif(is_null($val)) {
498*5de3a6a5SAndreas Gohr                $val = 'NULL';
499*5de3a6a5SAndreas Gohr            } else {
500*5de3a6a5SAndreas Gohr                $val = $this->pdo->quote($val);
501*5de3a6a5SAndreas Gohr            }
502*5de3a6a5SAndreas Gohr            $sql = str_replace($key, $val, $sql);
503*5de3a6a5SAndreas Gohr        }
504*5de3a6a5SAndreas Gohr        if($htmlescape) $sql = hsc($sql);
505*5de3a6a5SAndreas Gohr        return $sql;
506*5de3a6a5SAndreas Gohr    }
507f64dbc90SAndreas Gohr}
508f64dbc90SAndreas Gohr
509f64dbc90SAndreas Gohr// vim:ts=4:sw=4:et:
510