3 * MySQLP authentication backend
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author Andreas Gohr <andi@splitbrain.org>
7 * @author Chris Smith <chris@jalakai.co.uk>
8 * @author Matthias Grimm <matthias.grimmm@sourceforge.net>
11 class auth_mysql extends auth_basic {
14 var $dbver = 0; // database version
15 var $dbrev = 0; // database revision
16 var $dbsub = 0; // database subrevision
18 var $defaultgroup = "";
23 * checks if the mysql interface is available, otherwise it will
24 * set the variable $success of the basis class to false
26 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
28 function __construct() {
30 $this->cnf = $conf['auth']['mysql'];
32 if (method_exists($this, 'auth_basic')){
33 parent::__construct();
36 if(!function_exists('mysql_connect')) {
37 if ($this->cnf['debug']){
38 msg("MySQL err: PHP MySQL extension not found.",-1,__LINE__,__FILE__);
40 $this->success = false;
44 // default to UTF-8, you rarely want something else
45 if(!isset($this->cnf['charset'])) $this->cnf['charset'] = 'utf8';
47 $this->defaultgroup = $conf['defaultgroup'];
49 // set capabilities based upon config strings set
50 if (empty($this->cnf['server']) || empty($this->cnf['user']) ||
51 !isset($this->cnf['password']) || empty($this->cnf['database'])){
53 if ($this->cnf['debug']){
54 msg("MySQL err: insufficient configuration.",-1,__LINE__,__FILE__);
56 $this->success = false;
60 $this->cando['addUser'] = $this->_chkcnf(array(
67 'addUserGroup'),true);
68 $this->cando['delUser'] = $this->_chkcnf(array(
72 $this->cando['modLogin'] = $this->_chkcnf(array(
75 'UpdateTarget'),true);
76 $this->cando['modPass'] = $this->cando['modLogin'];
77 $this->cando['modName'] = $this->cando['modLogin'];
78 $this->cando['modMail'] = $this->cando['modLogin'];
79 $this->cando['modGroups'] = $this->_chkcnf(array(
87 'delUserGroup'),true);
88 /* getGroups is not yet supported
89 $this->cando['getGroups'] = $this->_chkcnf(array('getGroups',
90 'getGroupID'),false); */
91 $this->cando['getUsers'] = $this->_chkcnf(array(
95 $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'),false);
99 * Check if the given config strings are set
101 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
104 function _chkcnf($keys, $wop=false){
105 foreach ($keys as $key){
106 if (empty($this->cnf[$key])) return false;
109 /* write operation and lock array filled with tables names? */
110 if ($wop && (!is_array($this->cnf['TablesToLock']) ||
111 !count($this->cnf['TablesToLock']))){
119 * Checks if the given user exists and the given plaintext password
120 * is correct. Furtheron it might be checked wether the user is
121 * member of the right group
123 * Depending on which SQL string is defined in the config, password
124 * checking is done here (getpass) or by the database (passcheck)
126 * @param $user user who would like access
127 * @param $pass user's clear text password to check
130 * @author Andreas Gohr <andi@splitbrain.org>
131 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
133 function checkPass($user,$pass){
136 if($this->_openDB()) {
137 $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['checkPass']);
138 $sql = str_replace('%{pass}',$this->_escape($pass),$sql);
139 $sql = str_replace('%{dgroup}',$this->_escape($this->defaultgroup),$sql);
140 $result = $this->_queryDB($sql);
142 if($result !== false && count($result) == 1) {
143 if($this->cnf['forwardClearPass'] == 1)
146 $rc = auth_verifyPassword($pass,$result[0]['pass']);
156 * Returns info about the given user needs to contain
157 * at least these fields:
158 * name string full name of the user
159 * mail string email addres of the user
160 * grps array list of groups the user is in
162 * @param $user user's nick to get data for
164 * @author Andreas Gohr <andi@splitbrain.org>
165 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
167 function getUserData($user){
168 if($this->_openDB()) {
169 $this->_lockTables("READ");
170 $info = $this->_getUserInfo($user);
171 $this->_unlockTables();
181 * Create a new User. Returns false if the user already exists,
182 * null when an error occurred and true if everything went well.
184 * The new user will be added to the default group by this
185 * function if grps are not specified (default behaviour).
187 * @param $user nick of the user
188 * @param $pwd clear text password
189 * @param $name full name of the user
190 * @param $mail email address
191 * @param $grps array of groups the user should become member of
193 * @author Andreas Gohr <andi@splitbrain.org>
194 * @author Chris Smith <chris@jalakai.co.uk>
195 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
197 function createUser($user,$pwd,$name,$mail,$grps=null){
198 if($this->_openDB()) {
199 if (($info = $this->_getUserInfo($user)) !== false)
200 return false; // user already exists
202 // set defaultgroup if no groups were given
204 $grps = array($this->defaultgroup);
206 $this->_lockTables("WRITE");
207 $pwd = $this->cnf['forwardClearPass'] ? $pwd : auth_cryptPassword($pwd);
208 $rc = $this->_addUser($user,$pwd,$name,$mail,$grps);
209 $this->_unlockTables();
211 if ($rc) return true;
213 return null; // return error
217 * Modify user data [public function]
219 * An existing user dataset will be modified. Changes are given in an array.
221 * The dataset update will be rejected if the user name should be changed
222 * to an already existing one.
224 * The password must be provides unencrypted. Pasword cryption is done
225 * automatically if configured.
227 * If one or more groups could't be updated, an error would be set. In
228 * this case the dataset might already be changed and we can't rollback
229 * the changes. Transactions would be really usefull here.
231 * modifyUser() may be called without SQL statements defined that are
232 * needed to change group membership (for example if only the user profile
233 * should be modified). In this case we asure that we don't touch groups
234 * even $changes['grps'] is set by mistake.
236 * @param $user nick of the user to be changed
237 * @param $changes array of field/value pairs to be changed (password
238 * will be clear text)
239 * @return bool true on success, false on error
241 * @author Chris Smith <chris@jalakai.co.uk>
242 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
244 function modifyUser($user, $changes) {
247 if (!is_array($changes) || !count($changes))
248 return true; // nothing to change
250 if($this->_openDB()) {
251 $this->_lockTables("WRITE");
253 if (($uid = $this->_getUserID($user))) {
254 $rc = $this->_updateUserInfo($changes, $uid);
256 if ($rc && isset($changes['grps']) && $this->cando['modGroups']) {
257 $groups = $this->_getGroups($user);
258 $grpadd = array_diff($changes['grps'], $groups);
259 $grpdel = array_diff($groups, $changes['grps']);
261 foreach($grpadd as $group)
262 if (($this->_addUserToGroup($user, $group, 1)) == false)
265 foreach($grpdel as $group)
266 if (($this->_delUserFromGroup($user, $group)) == false)
271 $this->_unlockTables();
280 * Remove one or more users from the list of registered users
282 * @param array $users array of users to be deleted
283 * @return int the number of users deleted
285 * @author Christopher Smith <chris@jalakai.co.uk>
286 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
288 function deleteUsers($users) {
291 if($this->_openDB()) {
292 if (is_array($users) && count($users)) {
293 $this->_lockTables("WRITE");
294 foreach ($users as $user) {
295 if ($this->_delUser($user))
298 $this->_unlockTables();
308 * Counts users which meet certain $filter criteria.
310 * @param array $filter filter criteria in item/pattern pairs
311 * @return count of found users.
313 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
315 function getUserCount($filter=array()) {
318 if($this->_openDB()) {
319 $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter);
321 if ($this->dbver >= 4) {
322 $sql = substr($sql, 6); /* remove 'SELECT' or 'select' */
323 $sql = "SELECT SQL_CALC_FOUND_ROWS".$sql." LIMIT 1";
324 $this->_queryDB($sql);
325 $result = $this->_queryDB("SELECT FOUND_ROWS()");
326 $rc = $result[0]['FOUND_ROWS()'];
327 } else if (($result = $this->_queryDB($sql)))
328 $rc = count($result);
336 * Bulk retrieval of user data. [public function]
338 * @param first index of first user to be returned
339 * @param limit max number of users to be returned
340 * @param filter array of field/pattern pairs
341 * @return array of userinfo (refer getUserData for internal userinfo details)
343 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
345 function retrieveUsers($first=0,$limit=10,$filter=array()) {
348 if($this->_openDB()) {
349 $this->_lockTables("READ");
350 $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter);
351 $sql .= " ".$this->cnf['SortOrder']." LIMIT $first, $limit";
352 $result = $this->_queryDB($sql);
354 if (!empty($result)) {
355 foreach ($result as $user)
356 if (($info = $this->_getUserInfo($user['user'])))
357 $out[$user['user']] = $info;
360 $this->_unlockTables();
367 * Give user membership of a group [public function]
371 * @return bool true on success, false on error
373 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
375 function joinGroup($user, $group) {
378 if ($this->_openDB()) {
379 $this->_lockTables("WRITE");
380 $rc = $this->_addUserToGroup($user, $group);
381 $this->_unlockTables();
388 * Remove user from a group [public function]
390 * @param $user user that leaves a group
391 * @param $group group to leave
394 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
396 function leaveGroup($user, $group) {
399 if ($this->_openDB()) {
400 $this->_lockTables("WRITE");
401 $uid = $this->_getUserID($user);
402 $rc = $this->_delUserFromGroup($user, $group);
403 $this->_unlockTables();
410 * MySQL is case-insensitive
412 function isCaseSensitive(){
417 * Adds a user to a group.
419 * If $force is set to '1' non existing groups would be created.
421 * The database connection must already be established. Otherwise
422 * this function does nothing and returns 'false'. It is strongly
423 * recommended to call this function only after all participating
424 * tables (group and usergroup) have been locked.
426 * @param $user user to add to a group
427 * @param $group name of the group
428 * @param $force '1' create missing groups
429 * @return bool 'true' on success, 'false' on error
431 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
433 function _addUserToGroup($user, $group, $force=0) {
436 if (($this->dbcon) && ($user)) {
437 $gid = $this->_getGroupID($group);
439 if ($force) { // create missing groups
440 $sql = str_replace('%{group}',$this->_escape($group),$this->cnf['addGroup']);
441 $gid = $this->_modifyDB($sql);
442 $newgroup = 1; // group newly created
444 if (!$gid) return false; // group didn't exist and can't be created
447 $sql = $this->cnf['addUserGroup'];
448 if(strpos($sql,'%{uid}') !== false){
449 $uid = $this->_getUserID($user);
450 $sql = str_replace('%{uid}', $this->_escape($uid),$sql);
452 $sql = str_replace('%{user}', $this->_escape($user),$sql);
453 $sql = str_replace('%{gid}', $this->_escape($gid),$sql);
454 $sql = str_replace('%{group}',$this->_escape($group),$sql);
455 if ($this->_modifyDB($sql) !== false) return true;
457 if ($newgroup) { // remove previously created group on error
458 $sql = str_replace('%{gid}', $this->_escape($gid),$this->cnf['delGroup']);
459 $sql = str_replace('%{group}',$this->_escape($group),$sql);
460 $this->_modifyDB($sql);
467 * Remove user from a group
469 * @param $user user that leaves a group
470 * @param $group group to leave
471 * @return bool true on success, false on error
473 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
475 function _delUserFromGroup($user, $group) {
478 if (($this->dbcon) && ($user)) {
479 $sql = $this->cnf['delUserGroup'];
480 if(strpos($sql,'%{uid}') !== false){
481 $uid = $this->_getUserID($user);
482 $sql = str_replace('%{uid}', $this->_escape($uid),$sql);
484 $gid = $this->_getGroupID($group);
486 $sql = str_replace('%{user}', $this->_escape($user),$sql);
487 $sql = str_replace('%{gid}', $this->_escape($gid),$sql);
488 $sql = str_replace('%{group}',$this->_escape($group),$sql);
489 $rc = $this->_modifyDB($sql) == 0 ? true : false;
496 * Retrieves a list of groups the user is a member off.
498 * The database connection must already be established
499 * for this function to work. Otherwise it will return
502 * @param $user user whose groups should be listed
503 * @return bool false on error
504 * @return array array containing all groups on success
506 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
508 function _getGroups($user) {
512 $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getGroups']);
513 $result = $this->_queryDB($sql);
515 if($result !== false && count($result)) {
516 foreach($result as $row)
517 $groups[] = $row['group'];
525 * Retrieves the user id of a given user name
527 * The database connection must already be established
528 * for this function to work. Otherwise it will return
531 * @param $user user whose id is desired
534 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
536 function _getUserID($user) {
538 $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getUserID']);
539 $result = $this->_queryDB($sql);
540 return $result === false ? false : $result[0]['id'];
546 * Adds a new User to the database.
548 * The database connection must already be established
549 * for this function to work. Otherwise it will return
552 * @param $user login of the user
553 * @param $pwd encrypted password
554 * @param $name full name of the user
555 * @param $mail email address
556 * @param $grps array of groups the user should become member of
559 * @author Andreas Gohr <andi@splitbrain.org>
560 * @author Chris Smith <chris@jalakai.co.uk>
561 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
563 function _addUser($user,$pwd,$name,$mail,$grps){
564 if($this->dbcon && is_array($grps)) {
565 $sql = str_replace('%{user}', $this->_escape($user),$this->cnf['addUser']);
566 $sql = str_replace('%{pass}', $this->_escape($pwd),$sql);
567 $sql = str_replace('%{name}', $this->_escape($name),$sql);
568 $sql = str_replace('%{email}',$this->_escape($mail),$sql);
569 $uid = $this->_modifyDB($sql);
572 foreach($grps as $group) {
573 $gid = $this->_addUserToGroup($user, $group, 1);
574 if ($gid === false) break;
577 if ($gid) return true;
579 /* remove the new user and all group relations if a group can't
580 * be assigned. Newly created groups will remain in the database
581 * and won't be removed. This might create orphaned groups but
582 * is not a big issue so we ignore this problem here.
584 $this->_delUser($user);
585 if ($this->cnf['debug'])
586 msg ("MySQL err: Adding user '$user' to group '$group' failed.",-1,__LINE__,__FILE__);
594 * Deletes a given user and all his group references.
596 * The database connection must already be established
597 * for this function to work. Otherwise it will return
600 * @param $user user whose id is desired
603 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
605 function _delUser($user) {
607 $uid = $this->_getUserID($user);
609 $sql = str_replace('%{uid}',$this->_escape($uid),$this->cnf['delUserRefs']);
610 $this->_modifyDB($sql);
611 $sql = str_replace('%{uid}',$this->_escape($uid),$this->cnf['delUser']);
612 $sql = str_replace('%{user}', $this->_escape($user),$sql);
613 $this->_modifyDB($sql);
623 * Gets the data for a specific user The database connection
624 * must already be established for this function to work.
625 * Otherwise it will return 'false'.
627 * @param $user user's nick to get data for
628 * @return bool false on error
629 * @return array user info on success
631 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
633 function _getUserInfo($user){
634 $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getUserInfo']);
635 $result = $this->_queryDB($sql);
636 if($result !== false && count($result)) {
638 $info['grps'] = $this->_getGroups($user);
645 * Updates the user info in the database
647 * Update a user data structure in the database according changes
648 * given in an array. The user name can only be changes if it didn't
649 * exists already. If the new user name exists the update procedure
650 * will be aborted. The database keeps unchanged.
652 * The database connection has already to be established for this
653 * function to work. Otherwise it will return 'false'.
655 * The password will be crypted if necessary.
657 * @param $changes array of items to change as pairs of item and value
658 * @param $uid user id of dataset to change, must be unique in DB
659 * @return true on success or false on error
661 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
663 function _updateUserInfo($changes, $uid) {
664 $sql = $this->cnf['updateUser']." ";
669 foreach ($changes as $item => $value) {
670 if ($item == 'user') {
671 if (($this->_getUserID($changes['user']))) {
672 $err = 1; /* new username already exists */
673 break; /* abort update */
675 if ($cnt++ > 0) $sql .= ", ";
676 $sql .= str_replace('%{user}',$value,$this->cnf['UpdateLogin']);
677 } else if ($item == 'name') {
678 if ($cnt++ > 0) $sql .= ", ";
679 $sql .= str_replace('%{name}',$value,$this->cnf['UpdateName']);
680 } else if ($item == 'pass') {
681 if (!$this->cnf['forwardClearPass'])
682 $value = auth_cryptPassword($value);
683 if ($cnt++ > 0) $sql .= ", ";
684 $sql .= str_replace('%{pass}',$value,$this->cnf['UpdatePass']);
685 } else if ($item == 'mail') {
686 if ($cnt++ > 0) $sql .= ", ";
687 $sql .= str_replace('%{email}',$value,$this->cnf['UpdateEmail']);
693 $sql .= " ".str_replace('%{uid}', $uid, $this->cnf['UpdateTarget']);
694 if(get_class($this) == 'auth_mysql') $sql .= " LIMIT 1"; //some PgSQL inheritance comp.
695 $this->_modifyDB($sql);
704 * Retrieves the group id of a given group name
706 * The database connection must already be established
707 * for this function to work. Otherwise it will return
710 * @param $group group name which id is desired
713 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
715 function _getGroupID($group) {
717 $sql = str_replace('%{group}',$this->_escape($group),$this->cnf['getGroupID']);
718 $result = $this->_queryDB($sql);
719 return $result === false ? false : $result[0]['id'];
725 * Opens a connection to a database and saves the handle for further
726 * usage in the object. The successful call to this functions is
727 * essential for most functions in this object.
731 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
735 $con = @mysql_connect ($this->cnf['server'], $this->cnf['user'], $this->cnf['password']);
737 if ((mysql_select_db($this->cnf['database'], $con))) {
738 if ((preg_match("/^(\d+)\.(\d+)\.(\d+).*/", mysql_get_server_info ($con), $result)) == 1) {
739 $this->dbver = $result[1];
740 $this->dbrev = $result[2];
741 $this->dbsub = $result[3];
744 if(!empty($this->cnf['charset'])){
745 mysql_query('SET CHARACTER SET "' . $this->cnf['charset'] . '"', $con);
747 return true; // connection and database successfully opened
750 if ($this->cnf['debug'])
751 msg("MySQL err: No access to database {$this->cnf['database']}.",-1,__LINE__,__FILE__);
753 } else if ($this->cnf['debug'])
754 msg ("MySQL err: Connection to {$this->cnf['user']}@{$this->cnf['server']} not possible.",
755 -1,__LINE__,__FILE__);
757 return false; // connection failed
759 return true; // connection already open
763 * Closes a database connection.
765 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
767 function _closeDB() {
769 mysql_close ($this->dbcon);
775 * Sends a SQL query to the database and transforms the result into
776 * an associative array.
778 * This function is only able to handle queries that returns a
779 * table such as SELECT.
781 * @param $query SQL string that contains the query
782 * @return array with the result table
784 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
786 function _queryDB($query) {
787 if($this->cnf['debug'] >= 2){
788 msg('MySQL query: '.hsc($query),0,__LINE__,__FILE__);
791 $resultarray = array();
793 $result = @mysql_query($query,$this->dbcon);
795 while (($t = mysql_fetch_assoc($result)) !== false)
797 mysql_free_result ($result);
800 if ($this->cnf['debug'])
801 msg('MySQL err: '.mysql_error($this->dbcon),-1,__LINE__,__FILE__);
807 * Sends a SQL query to the database
809 * This function is only able to handle queries that returns
810 * either nothing or an id value such as INPUT, DELETE, UPDATE, etc.
812 * @param $query SQL string that contains the query
813 * @return insert id or 0, false on error
815 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
817 function _modifyDB($query) {
819 $result = @mysql_query($query,$this->dbcon);
821 $rc = mysql_insert_id($this->dbcon); //give back ID on insert
822 if ($rc !== false) return $rc;
824 if ($this->cnf['debug'])
825 msg('MySQL err: '.mysql_error($this->dbcon),-1,__LINE__,__FILE__);
831 * Locked a list of tables for exclusive access so that modifications
832 * to the database can't be disturbed by other threads. The list
833 * could be set with $conf['auth']['mysql']['TablesToLock'] = array()
835 * If aliases for tables are used in SQL statements, also this aliases
836 * must be locked. For eg. you use a table 'user' and the alias 'u' in
837 * some sql queries, the array must looks like this (order is important):
838 * array("user", "user AS u");
840 * MySQL V3 is not able to handle transactions with COMMIT/ROLLBACK
841 * so that this functionality is simulated by this function. Nevertheless
842 * it is not as powerful as transactions, it is a good compromise in safty.
844 * @param $mode could be 'READ' or 'WRITE'
846 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
848 function _lockTables($mode) {
850 if (is_array($this->cnf['TablesToLock']) && !empty($this->cnf['TablesToLock'])) {
851 if ($mode == "READ" || $mode == "WRITE") {
852 $sql = "LOCK TABLES ";
854 foreach ($this->cnf['TablesToLock'] as $table) {
855 if ($cnt++ != 0) $sql .= ", ";
856 $sql .= "$table $mode";
858 $this->_modifyDB($sql);
867 * Unlock locked tables. All existing locks of this thread will be
870 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
872 function _unlockTables() {
874 $this->_modifyDB("UNLOCK TABLES");
881 * Transforms the filter settings in an filter string for a SQL database
882 * The database connection must already be established, otherwise the
883 * original SQL string without filter criteria will be returned.
885 * @param $sql SQL string to which the $filter criteria should be added
886 * @param $filter array of filter criteria as pairs of item and pattern
887 * @return SQL string with attached $filter criteria on success
888 * @return the original SQL string on error.
890 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
892 function _createSQLFilter($sql, $filter) {
897 foreach ($filter as $item => $pattern) {
898 $tmp = '%'.$this->_escape($pattern).'%';
899 if ($item == 'user') {
900 if ($cnt++ > 0) $SQLfilter .= " AND ";
901 $SQLfilter .= str_replace('%{user}',$tmp,$this->cnf['FilterLogin']);
902 } else if ($item == 'name') {
903 if ($cnt++ > 0) $SQLfilter .= " AND ";
904 $SQLfilter .= str_replace('%{name}',$tmp,$this->cnf['FilterName']);
905 } else if ($item == 'mail') {
906 if ($cnt++ > 0) $SQLfilter .= " AND ";
907 $SQLfilter .= str_replace('%{email}',$tmp,$this->cnf['FilterEmail']);
908 } else if ($item == 'grps') {
909 if ($cnt++ > 0) $SQLfilter .= " AND ";
910 $SQLfilter .= str_replace('%{group}',$tmp,$this->cnf['FilterGroup']);
914 // we have to check SQLfilter here and must not use $cnt because if
915 // any of cnf['Filter????'] is not defined, a malformed SQL string
916 // would be generated.
918 if (strlen($SQLfilter)) {
919 $glue = strpos(strtolower($sql),"where") ? " AND " : " WHERE ";
920 $sql = $sql.$glue.$SQLfilter;
928 * Escape a string for insertion into the database
930 * @author Andreas Gohr <andi@splitbrain.org>
931 * @param string $string The string to escape
932 * @param boolean $like Escape wildcard chars as well?
934 function _escape($string,$like=false){
936 $string = mysql_real_escape_string($string, $this->dbcon);
938 $string = addslashes($string);
941 $string = addcslashes($string,'%_');
947 //Setup VIM: ex: et ts=2 :