1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/dokuwiki_ynh.git synced 2024-09-03 18:26:20 +02:00
dokuwiki_ynh/sources/lib/plugins/authmysql/auth.php

980 lines
34 KiB
PHP

<?php
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
/**
* MySQL authentication backend
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthias.grimmm@sourceforge.net>
* @author Jan Schumann <js@schumann-it.com>
*/
class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
/** @var resource holds the database connection */
protected $dbcon = 0;
/** @var int database version*/
protected $dbver = 0;
/** @var int database revision */
protected $dbrev = 0;
/** @var int database subrevision */
protected $dbsub = 0;
/**
* Constructor
*
* checks if the mysql interface is available, otherwise it will
* set the variable $success of the basis class to false
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
public function __construct() {
parent::__construct();
if(!function_exists('mysql_connect')) {
$this->_debug("MySQL err: PHP MySQL extension not found.", -1, __LINE__, __FILE__);
$this->success = false;
return;
}
// set capabilities based upon config strings set
if(!$this->getConf('server') || !$this->getConf('user') || !$this->getConf('database')) {
$this->_debug("MySQL err: insufficient configuration.", -1, __LINE__, __FILE__);
$this->success = false;
return;
}
$this->cando['addUser'] = $this->_chkcnf(
array(
'getUserInfo',
'getGroups',
'addUser',
'getUserID',
'getGroupID',
'addGroup',
'addUserGroup'
), true
);
$this->cando['delUser'] = $this->_chkcnf(
array(
'getUserID',
'delUser',
'delUserRefs'
), true
);
$this->cando['modLogin'] = $this->_chkcnf(
array(
'getUserID',
'updateUser',
'UpdateTarget'
), true
);
$this->cando['modPass'] = $this->cando['modLogin'];
$this->cando['modName'] = $this->cando['modLogin'];
$this->cando['modMail'] = $this->cando['modLogin'];
$this->cando['modGroups'] = $this->_chkcnf(
array(
'getUserID',
'getGroups',
'getGroupID',
'addGroup',
'addUserGroup',
'delGroup',
'getGroupID',
'delUserGroup'
), true
);
/* getGroups is not yet supported
$this->cando['getGroups'] = $this->_chkcnf(array('getGroups',
'getGroupID'),false); */
$this->cando['getUsers'] = $this->_chkcnf(
array(
'getUsers',
'getUserInfo',
'getGroups'
), false
);
$this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'), false);
if($this->getConf('debug') >= 2) {
$candoDebug = '';
foreach($this->cando as $cd => $value) {
if($value) { $value = 'yes'; } else { $value = 'no'; }
$candoDebug .= $cd . ": " . $value . " | ";
}
$this->_debug("authmysql cando: " . $candoDebug, 0, __LINE__, __FILE__);
}
}
/**
* Check if the given config strings are set
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
* @param array $keys
* @param bool $wop is this a check for a write operation?
* @return bool
*/
protected function _chkcnf($keys, $wop = false) {
foreach($keys as $key) {
if(!$this->getConf($key)) return false;
}
/* write operation and lock array filled with tables names? */
if($wop && (!is_array($this->getConf('TablesToLock')) ||
!count($this->getConf('TablesToLock')))
) {
return false;
}
return true;
}
/**
* Checks if the given user exists and the given plaintext password
* is correct. Furtheron it might be checked wether the user is
* member of the right group
*
* Depending on which SQL string is defined in the config, password
* checking is done here (getpass) or by the database (passcheck)
*
* @param string $user user who would like access
* @param string $pass user's clear text password to check
* @return bool
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
public function checkPass($user, $pass) {
global $conf;
$rc = false;
if($this->_openDB()) {
$sql = str_replace('%{user}', $this->_escape($user), $this->getConf('checkPass'));
$sql = str_replace('%{pass}', $this->_escape($pass), $sql);
$sql = str_replace('%{dgroup}', $this->_escape($conf['defaultgroup']), $sql);
$result = $this->_queryDB($sql);
if($result !== false && count($result) == 1) {
if($this->getConf('forwardClearPass') == 1)
$rc = true;
else
$rc = auth_verifyPassword($pass, $result[0]['pass']);
}
$this->_closeDB();
}
return $rc;
}
/**
* Return user info
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user user login to get data for
* @return array|bool
*/
public function getUserData($user) {
if($this->_openDB()) {
$this->_lockTables("READ");
$info = $this->_getUserInfo($user);
$this->_unlockTables();
$this->_closeDB();
} else
$info = false;
return $info;
}
/**
* Create a new User. Returns false if the user already exists,
* null when an error occurred and true if everything went well.
*
* The new user will be added to the default group by this
* function if grps are not specified (default behaviour).
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user nick of the user
* @param string $pwd clear text password
* @param string $name full name of the user
* @param string $mail email address
* @param array $grps array of groups the user should become member of
* @return bool|null
*/
public function createUser($user, $pwd, $name, $mail, $grps = null) {
global $conf;
if($this->_openDB()) {
if(($info = $this->_getUserInfo($user)) !== false)
return false; // user already exists
// set defaultgroup if no groups were given
if($grps == null)
$grps = array($conf['defaultgroup']);
$this->_lockTables("WRITE");
$pwd = $this->getConf('forwardClearPass') ? $pwd : auth_cryptPassword($pwd);
$rc = $this->_addUser($user, $pwd, $name, $mail, $grps);
$this->_unlockTables();
$this->_closeDB();
if($rc) return true;
}
return null; // return error
}
/**
* Modify user data
*
* An existing user dataset will be modified. Changes are given in an array.
*
* The dataset update will be rejected if the user name should be changed
* to an already existing one.
*
* The password must be provides unencrypted. Pasword cryption is done
* automatically if configured.
*
* If one or more groups could't be updated, an error would be set. In
* this case the dataset might already be changed and we can't rollback
* the changes. Transactions would be really usefull here.
*
* modifyUser() may be called without SQL statements defined that are
* needed to change group membership (for example if only the user profile
* should be modified). In this case we asure that we don't touch groups
* even $changes['grps'] is set by mistake.
*
* @author Chris Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user nick of the user to be changed
* @param array $changes array of field/value pairs to be changed (password will be clear text)
* @return bool true on success, false on error
*/
public function modifyUser($user, $changes) {
$rc = false;
if(!is_array($changes) || !count($changes))
return true; // nothing to change
if($this->_openDB()) {
$this->_lockTables("WRITE");
if(($uid = $this->_getUserID($user))) {
$rc = $this->_updateUserInfo($changes, $uid);
if($rc && isset($changes['grps']) && $this->cando['modGroups']) {
$groups = $this->_getGroups($user);
$grpadd = array_diff($changes['grps'], $groups);
$grpdel = array_diff($groups, $changes['grps']);
foreach($grpadd as $group)
if(($this->_addUserToGroup($user, $group, 1)) == false)
$rc = false;
foreach($grpdel as $group)
if(($this->_delUserFromGroup($user, $group)) == false)
$rc = false;
}
}
$this->_unlockTables();
$this->_closeDB();
}
return $rc;
}
/**
* [public function]
*
* Remove one or more users from the list of registered users
*
* @param array $users array of users to be deleted
* @return int the number of users deleted
*
* @author Christopher Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function deleteUsers($users) {
$count = 0;
if($this->_openDB()) {
if(is_array($users) && count($users)) {
$this->_lockTables("WRITE");
foreach($users as $user) {
if($this->_delUser($user))
$count++;
}
$this->_unlockTables();
}
$this->_closeDB();
}
return $count;
}
/**
* Counts users which meet certain $filter criteria.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param array $filter filter criteria in item/pattern pairs
* @return int count of found users
*/
public function getUserCount($filter = array()) {
$rc = 0;
if($this->_openDB()) {
$sql = $this->_createSQLFilter($this->getConf('getUsers'), $filter);
if($this->dbver >= 4) {
$sql = substr($sql, 6); /* remove 'SELECT' or 'select' */
$sql = "SELECT SQL_CALC_FOUND_ROWS".$sql." LIMIT 1";
$this->_queryDB($sql);
$result = $this->_queryDB("SELECT FOUND_ROWS()");
$rc = $result[0]['FOUND_ROWS()'];
} else if(($result = $this->_queryDB($sql)))
$rc = count($result);
$this->_closeDB();
}
return $rc;
}
/**
* Bulk retrieval of user data
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param int $first index of first user to be returned
* @param int $limit max number of users to be returned
* @param array|string $filter array of field/pattern pairs
* @return array userinfo (refer getUserData for internal userinfo details)
*/
public function retrieveUsers($first = 0, $limit = 0, $filter = array()) {
$out = array();
if($this->_openDB()) {
$this->_lockTables("READ");
$sql = $this->_createSQLFilter($this->getConf('getUsers'), $filter);
$sql .= " ".$this->getConf('SortOrder');
if($limit) {
$sql .= " LIMIT $first, $limit";
} elseif($first) {
$sql .= " LIMIT $first";
}
$result = $this->_queryDB($sql);
if(!empty($result)) {
foreach($result as $user)
if(($info = $this->_getUserInfo($user['user'])))
$out[$user['user']] = $info;
}
$this->_unlockTables();
$this->_closeDB();
}
return $out;
}
/**
* Give user membership of a group
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user
* @param string $group
* @return bool true on success, false on error
*/
protected function joinGroup($user, $group) {
$rc = false;
if($this->_openDB()) {
$this->_lockTables("WRITE");
$rc = $this->_addUserToGroup($user, $group);
$this->_unlockTables();
$this->_closeDB();
}
return $rc;
}
/**
* Remove user from a group
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user user that leaves a group
* @param string $group group to leave
* @return bool
*/
protected function leaveGroup($user, $group) {
$rc = false;
if($this->_openDB()) {
$this->_lockTables("WRITE");
$rc = $this->_delUserFromGroup($user, $group);
$this->_unlockTables();
$this->_closeDB();
}
return $rc;
}
/**
* MySQL is case-insensitive
*/
public function isCaseSensitive() {
return false;
}
/**
* Adds a user to a group.
*
* If $force is set to true non existing groups would be created.
*
* The database connection must already be established. Otherwise
* this function does nothing and returns 'false'. It is strongly
* recommended to call this function only after all participating
* tables (group and usergroup) have been locked.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user user to add to a group
* @param string $group name of the group
* @param bool $force create missing groups
* @return bool true on success, false on error
*/
protected function _addUserToGroup($user, $group, $force = false) {
$newgroup = 0;
if(($this->dbcon) && ($user)) {
$gid = $this->_getGroupID($group);
if(!$gid) {
if($force) { // create missing groups
$sql = str_replace('%{group}', $this->_escape($group), $this->getConf('addGroup'));
$gid = $this->_modifyDB($sql);
$newgroup = 1; // group newly created
}
if(!$gid) return false; // group didn't exist and can't be created
}
$sql = $this->getConf('addUserGroup');
if(strpos($sql, '%{uid}') !== false) {
$uid = $this->_getUserID($user);
$sql = str_replace('%{uid}', $this->_escape($uid), $sql);
}
$sql = str_replace('%{user}', $this->_escape($user), $sql);
$sql = str_replace('%{gid}', $this->_escape($gid), $sql);
$sql = str_replace('%{group}', $this->_escape($group), $sql);
if($this->_modifyDB($sql) !== false) return true;
if($newgroup) { // remove previously created group on error
$sql = str_replace('%{gid}', $this->_escape($gid), $this->getConf('delGroup'));
$sql = str_replace('%{group}', $this->_escape($group), $sql);
$this->_modifyDB($sql);
}
}
return false;
}
/**
* Remove user from a group
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user user that leaves a group
* @param string $group group to leave
* @return bool true on success, false on error
*/
protected function _delUserFromGroup($user, $group) {
$rc = false;
if(($this->dbcon) && ($user)) {
$sql = $this->getConf('delUserGroup');
if(strpos($sql, '%{uid}') !== false) {
$uid = $this->_getUserID($user);
$sql = str_replace('%{uid}', $this->_escape($uid), $sql);
}
$gid = $this->_getGroupID($group);
if($gid) {
$sql = str_replace('%{user}', $this->_escape($user), $sql);
$sql = str_replace('%{gid}', $this->_escape($gid), $sql);
$sql = str_replace('%{group}', $this->_escape($group), $sql);
$rc = $this->_modifyDB($sql) == 0 ? true : false;
}
}
return $rc;
}
/**
* Retrieves a list of groups the user is a member off.
*
* The database connection must already be established
* for this function to work. Otherwise it will return
* false.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user user whose groups should be listed
* @return bool|array false on error, all groups on success
*/
protected function _getGroups($user) {
$groups = array();
if($this->dbcon) {
$sql = str_replace('%{user}', $this->_escape($user), $this->getConf('getGroups'));
$result = $this->_queryDB($sql);
if($result !== false && count($result)) {
foreach($result as $row)
$groups[] = $row['group'];
}
return $groups;
}
return false;
}
/**
* Retrieves the user id of a given user name
*
* The database connection must already be established
* for this function to work. Otherwise it will return
* false.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user user whose id is desired
* @return mixed user id
*/
protected function _getUserID($user) {
if($this->dbcon) {
$sql = str_replace('%{user}', $this->_escape($user), $this->getConf('getUserID'));
$result = $this->_queryDB($sql);
return $result === false ? false : $result[0]['id'];
}
return false;
}
/**
* Adds a new User to the database.
*
* The database connection must already be established
* for this function to work. Otherwise it will return
* false.
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user login of the user
* @param string $pwd encrypted password
* @param string $name full name of the user
* @param string $mail email address
* @param array $grps array of groups the user should become member of
* @return bool
*/
protected function _addUser($user, $pwd, $name, $mail, $grps) {
if($this->dbcon && is_array($grps)) {
$sql = str_replace('%{user}', $this->_escape($user), $this->getConf('addUser'));
$sql = str_replace('%{pass}', $this->_escape($pwd), $sql);
$sql = str_replace('%{name}', $this->_escape($name), $sql);
$sql = str_replace('%{email}', $this->_escape($mail), $sql);
$uid = $this->_modifyDB($sql);
$gid = false;
$group = '';
if($uid) {
foreach($grps as $group) {
$gid = $this->_addUserToGroup($user, $group, 1);
if($gid === false) break;
}
if($gid !== false){
return true;
} else {
/* remove the new user and all group relations if a group can't
* be assigned. Newly created groups will remain in the database
* and won't be removed. This might create orphaned groups but
* is not a big issue so we ignore this problem here.
*/
$this->_delUser($user);
$this->_debug("MySQL err: Adding user '$user' to group '$group' failed.", -1, __LINE__, __FILE__);
}
}
}
return false;
}
/**
* Deletes a given user and all his group references.
*
* The database connection must already be established
* for this function to work. Otherwise it will return
* false.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user user whose id is desired
* @return bool
*/
protected function _delUser($user) {
if($this->dbcon) {
$uid = $this->_getUserID($user);
if($uid) {
$sql = str_replace('%{uid}', $this->_escape($uid), $this->getConf('delUserRefs'));
$this->_modifyDB($sql);
$sql = str_replace('%{uid}', $this->_escape($uid), $this->getConf('delUser'));
$sql = str_replace('%{user}', $this->_escape($user), $sql);
$this->_modifyDB($sql);
return true;
}
}
return false;
}
/**
* getUserInfo
*
* Gets the data for a specific user The database connection
* must already be established for this function to work.
* Otherwise it will return 'false'.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $user user's nick to get data for
* @return bool|array false on error, user info on success
*/
protected function _getUserInfo($user) {
$sql = str_replace('%{user}', $this->_escape($user), $this->getConf('getUserInfo'));
$result = $this->_queryDB($sql);
if($result !== false && count($result)) {
$info = $result[0];
$info['grps'] = $this->_getGroups($user);
return $info;
}
return false;
}
/**
* Updates the user info in the database
*
* Update a user data structure in the database according changes
* given in an array. The user name can only be changes if it didn't
* exists already. If the new user name exists the update procedure
* will be aborted. The database keeps unchanged.
*
* The database connection has already to be established for this
* function to work. Otherwise it will return 'false'.
*
* The password will be crypted if necessary.
*
* @param array $changes array of items to change as pairs of item and value
* @param mixed $uid user id of dataset to change, must be unique in DB
* @return bool true on success or false on error
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
protected function _updateUserInfo($changes, $uid) {
$sql = $this->getConf('updateUser')." ";
$cnt = 0;
$err = 0;
if($this->dbcon) {
foreach($changes as $item => $value) {
if($item == 'user') {
if(($this->_getUserID($changes['user']))) {
$err = 1; /* new username already exists */
break; /* abort update */
}
if($cnt++ > 0) $sql .= ", ";
$sql .= str_replace('%{user}', $value, $this->getConf('UpdateLogin'));
} else if($item == 'name') {
if($cnt++ > 0) $sql .= ", ";
$sql .= str_replace('%{name}', $value, $this->getConf('UpdateName'));
} else if($item == 'pass') {
if(!$this->getConf('forwardClearPass'))
$value = auth_cryptPassword($value);
if($cnt++ > 0) $sql .= ", ";
$sql .= str_replace('%{pass}', $value, $this->getConf('UpdatePass'));
} else if($item == 'mail') {
if($cnt++ > 0) $sql .= ", ";
$sql .= str_replace('%{email}', $value, $this->getConf('UpdateEmail'));
}
}
if($err == 0) {
if($cnt > 0) {
$sql .= " ".str_replace('%{uid}', $uid, $this->getConf('UpdateTarget'));
if(get_class($this) == 'auth_mysql') $sql .= " LIMIT 1"; //some PgSQL inheritance comp.
$this->_modifyDB($sql);
}
return true;
}
}
return false;
}
/**
* Retrieves the group id of a given group name
*
* The database connection must already be established
* for this function to work. Otherwise it will return
* false.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $group group name which id is desired
* @return mixed group id
*/
protected function _getGroupID($group) {
if($this->dbcon) {
$sql = str_replace('%{group}', $this->_escape($group), $this->getConf('getGroupID'));
$result = $this->_queryDB($sql);
return $result === false ? false : $result[0]['id'];
}
return false;
}
/**
* Opens a connection to a database and saves the handle for further
* usage in the object. The successful call to this functions is
* essential for most functions in this object.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @return bool
*/
protected function _openDB() {
if(!$this->dbcon) {
$con = @mysql_connect($this->getConf('server'), $this->getConf('user'), $this->getConf('password'));
if($con) {
if((mysql_select_db($this->getConf('database'), $con))) {
if((preg_match('/^(\d+)\.(\d+)\.(\d+).*/', mysql_get_server_info($con), $result)) == 1) {
$this->dbver = $result[1];
$this->dbrev = $result[2];
$this->dbsub = $result[3];
}
$this->dbcon = $con;
if($this->getConf('charset')) {
mysql_query('SET CHARACTER SET "'.$this->getConf('charset').'"', $con);
}
return true; // connection and database successfully opened
} else {
mysql_close($con);
$this->_debug("MySQL err: No access to database {$this->getConf('database')}.", -1, __LINE__, __FILE__);
}
} else {
$this->_debug(
"MySQL err: Connection to {$this->getConf('user')}@{$this->getConf('server')} not possible.",
-1, __LINE__, __FILE__
);
}
return false; // connection failed
}
return true; // connection already open
}
/**
* Closes a database connection.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
protected function _closeDB() {
if($this->dbcon) {
mysql_close($this->dbcon);
$this->dbcon = 0;
}
}
/**
* Sends a SQL query to the database and transforms the result into
* an associative array.
*
* This function is only able to handle queries that returns a
* table such as SELECT.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $query SQL string that contains the query
* @return array with the result table
*/
protected function _queryDB($query) {
if($this->getConf('debug') >= 2) {
msg('MySQL query: '.hsc($query), 0, __LINE__, __FILE__);
}
$resultarray = array();
if($this->dbcon) {
$result = @mysql_query($query, $this->dbcon);
if($result) {
while(($t = mysql_fetch_assoc($result)) !== false)
$resultarray[] = $t;
mysql_free_result($result);
return $resultarray;
}
$this->_debug('MySQL err: '.mysql_error($this->dbcon), -1, __LINE__, __FILE__);
}
return false;
}
/**
* Sends a SQL query to the database
*
* This function is only able to handle queries that returns
* either nothing or an id value such as INPUT, DELETE, UPDATE, etc.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $query SQL string that contains the query
* @return int|bool insert id or 0, false on error
*/
protected function _modifyDB($query) {
if($this->getConf('debug') >= 2) {
msg('MySQL query: '.hsc($query), 0, __LINE__, __FILE__);
}
if($this->dbcon) {
$result = @mysql_query($query, $this->dbcon);
if($result) {
$rc = mysql_insert_id($this->dbcon); //give back ID on insert
if($rc !== false) return $rc;
}
$this->_debug('MySQL err: '.mysql_error($this->dbcon), -1, __LINE__, __FILE__);
}
return false;
}
/**
* Locked a list of tables for exclusive access so that modifications
* to the database can't be disturbed by other threads. The list
* could be set with $conf['plugin']['authmysql']['TablesToLock'] = array()
*
* If aliases for tables are used in SQL statements, also this aliases
* must be locked. For eg. you use a table 'user' and the alias 'u' in
* some sql queries, the array must looks like this (order is important):
* array("user", "user AS u");
*
* MySQL V3 is not able to handle transactions with COMMIT/ROLLBACK
* so that this functionality is simulated by this function. Nevertheless
* it is not as powerful as transactions, it is a good compromise in safty.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $mode could be 'READ' or 'WRITE'
* @return bool
*/
protected function _lockTables($mode) {
if($this->dbcon) {
$ttl = $this->getConf('TablesToLock');
if(is_array($ttl) && !empty($ttl)) {
if($mode == "READ" || $mode == "WRITE") {
$sql = "LOCK TABLES ";
$cnt = 0;
foreach($ttl as $table) {
if($cnt++ != 0) $sql .= ", ";
$sql .= "$table $mode";
}
$this->_modifyDB($sql);
return true;
}
}
}
return false;
}
/**
* Unlock locked tables. All existing locks of this thread will be
* abrogated.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
protected function _unlockTables() {
if($this->dbcon) {
$this->_modifyDB("UNLOCK TABLES");
return true;
}
return false;
}
/**
* Transforms the filter settings in an filter string for a SQL database
* The database connection must already be established, otherwise the
* original SQL string without filter criteria will be returned.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
* @param string $sql SQL string to which the $filter criteria should be added
* @param array $filter array of filter criteria as pairs of item and pattern
* @return string SQL string with attached $filter criteria on success, original SQL string on error
*/
protected function _createSQLFilter($sql, $filter) {
$SQLfilter = "";
$cnt = 0;
if($this->dbcon) {
foreach($filter as $item => $pattern) {
$tmp = '%'.$this->_escape($pattern).'%';
if($item == 'user') {
if($cnt++ > 0) $SQLfilter .= " AND ";
$SQLfilter .= str_replace('%{user}', $tmp, $this->getConf('FilterLogin'));
} else if($item == 'name') {
if($cnt++ > 0) $SQLfilter .= " AND ";
$SQLfilter .= str_replace('%{name}', $tmp, $this->getConf('FilterName'));
} else if($item == 'mail') {
if($cnt++ > 0) $SQLfilter .= " AND ";
$SQLfilter .= str_replace('%{email}', $tmp, $this->getConf('FilterEmail'));
} else if($item == 'grps') {
if($cnt++ > 0) $SQLfilter .= " AND ";
$SQLfilter .= str_replace('%{group}', $tmp, $this->getConf('FilterGroup'));
}
}
// we have to check SQLfilter here and must not use $cnt because if
// any of cnf['Filter????'] is not defined, a malformed SQL string
// would be generated.
if(strlen($SQLfilter)) {
$glue = strpos(strtolower($sql), "where") ? " AND " : " WHERE ";
$sql = $sql.$glue.$SQLfilter;
}
}
return $sql;
}
/**
* Escape a string for insertion into the database
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $string The string to escape
* @param boolean $like Escape wildcard chars as well?
* @return string
*/
protected function _escape($string, $like = false) {
if($this->dbcon) {
$string = mysql_real_escape_string($string, $this->dbcon);
} else {
$string = addslashes($string);
}
if($like) {
$string = addcslashes($string, '%_');
}
return $string;
}
/**
* Wrapper around msg() but outputs only when debug is enabled
*
* @param string $message
* @param int $err
* @param int $line
* @param string $file
* @return void
*/
protected function _debug($message, $err, $line, $file) {
if(!$this->getConf('debug')) return;
msg($message, $err, $line, $file);
}
}