[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 // must be run within Dokuwiki 3 if(!defined('DOKU_INC')) die(); 4 5 /** 6 * PostgreSQL authentication backend 7 * 8 * This class inherits much functionality from the MySQL class 9 * and just reimplements the Postgres specific parts. 10 * 11 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 12 * @author Andreas Gohr <andi@splitbrain.org> 13 * @author Chris Smith <chris@jalakai.co.uk> 14 * @author Matthias Grimm <matthias.grimmm@sourceforge.net> 15 * @author Jan Schumann <js@schumann-it.com> 16 */ 17 class auth_plugin_authpgsql extends auth_plugin_authmysql { 18 19 /** 20 * Constructor 21 * 22 * checks if the pgsql interface is available, otherwise it will 23 * set the variable $success of the basis class to false 24 * 25 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 26 * @author Andreas Gohr <andi@splitbrain.org> 27 */ 28 public function __construct() { 29 // we don't want the stuff the MySQL constructor does, but the grandparent might do something 30 DokuWiki_Auth_Plugin::__construct(); 31 32 if(!function_exists('pg_connect')) { 33 $this->_debug("PgSQL err: PHP Postgres extension not found.", -1, __LINE__, __FILE__); 34 $this->success = false; 35 return; 36 } 37 38 $this->loadConfig(); 39 40 // set capabilities based upon config strings set 41 if(empty($this->conf['user']) || 42 empty($this->conf['password']) || empty($this->conf['database']) 43 ) { 44 $this->_debug("PgSQL err: insufficient configuration.", -1, __LINE__, __FILE__); 45 $this->success = false; 46 return; 47 } 48 49 $this->cando['addUser'] = $this->_chkcnf( 50 array( 51 'getUserInfo', 52 'getGroups', 53 'addUser', 54 'getUserID', 55 'getGroupID', 56 'addGroup', 57 'addUserGroup' 58 ) 59 ); 60 $this->cando['delUser'] = $this->_chkcnf( 61 array( 62 'getUserID', 63 'delUser', 64 'delUserRefs' 65 ) 66 ); 67 $this->cando['modLogin'] = $this->_chkcnf( 68 array( 69 'getUserID', 70 'updateUser', 71 'UpdateTarget' 72 ) 73 ); 74 $this->cando['modPass'] = $this->cando['modLogin']; 75 $this->cando['modName'] = $this->cando['modLogin']; 76 $this->cando['modMail'] = $this->cando['modLogin']; 77 $this->cando['modGroups'] = $this->_chkcnf( 78 array( 79 'getUserID', 80 'getGroups', 81 'getGroupID', 82 'addGroup', 83 'addUserGroup', 84 'delGroup', 85 'getGroupID', 86 'delUserGroup' 87 ) 88 ); 89 /* getGroups is not yet supported 90 $this->cando['getGroups'] = $this->_chkcnf(array('getGroups', 91 'getGroupID')); */ 92 $this->cando['getUsers'] = $this->_chkcnf( 93 array( 94 'getUsers', 95 'getUserInfo', 96 'getGroups' 97 ) 98 ); 99 $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers')); 100 } 101 102 /** 103 * Check if the given config strings are set 104 * 105 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 106 * 107 * @param string[] $keys 108 * @param bool $wop 109 * @return bool 110 */ 111 protected function _chkcnf($keys, $wop = false) { 112 foreach($keys as $key) { 113 if(empty($this->conf[$key])) return false; 114 } 115 return true; 116 } 117 118 /** 119 * Counts users which meet certain $filter criteria. 120 * 121 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 122 * 123 * @param array $filter filter criteria in item/pattern pairs 124 * @return int count of found users. 125 */ 126 public function getUserCount($filter = array()) { 127 $rc = 0; 128 129 if($this->_openDB()) { 130 $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter); 131 132 // no equivalent of SQL_CALC_FOUND_ROWS in pgsql? 133 if(($result = $this->_queryDB($sql))) { 134 $rc = count($result); 135 } 136 $this->_closeDB(); 137 } 138 return $rc; 139 } 140 141 /** 142 * Bulk retrieval of user data 143 * 144 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 145 * 146 * @param int $first index of first user to be returned 147 * @param int $limit max number of users to be returned 148 * @param array $filter array of field/pattern pairs 149 * @return array userinfo (refer getUserData for internal userinfo details) 150 */ 151 public function retrieveUsers($first = 0, $limit = 0, $filter = array()) { 152 $out = array(); 153 154 if($this->_openDB()) { 155 $this->_lockTables("READ"); 156 $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter); 157 $sql .= " ".$this->conf['SortOrder']; 158 if($limit) $sql .= " LIMIT $limit"; 159 if($first) $sql .= " OFFSET $first"; 160 $result = $this->_queryDB($sql); 161 162 foreach($result as $user) { 163 if(($info = $this->_getUserInfo($user['user']))) { 164 $out[$user['user']] = $info; 165 } 166 } 167 168 $this->_unlockTables(); 169 $this->_closeDB(); 170 } 171 return $out; 172 } 173 174 // @inherit function joinGroup($user, $group) 175 // @inherit function leaveGroup($user, $group) { 176 177 /** 178 * Adds a user to a group. 179 * 180 * If $force is set to true non existing groups would be created. 181 * 182 * The database connection must already be established. Otherwise 183 * this function does nothing and returns 'false'. 184 * 185 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 186 * @author Andreas Gohr <andi@splitbrain.org> 187 * 188 * @param string $user user to add to a group 189 * @param string $group name of the group 190 * @param bool $force create missing groups 191 * @return bool true on success, false on error 192 */ 193 protected function _addUserToGroup($user, $group, $force = false) { 194 $newgroup = 0; 195 196 if(($this->dbcon) && ($user)) { 197 $gid = $this->_getGroupID($group); 198 if(!$gid) { 199 if($force) { // create missing groups 200 $sql = str_replace('%{group}', addslashes($group), $this->conf['addGroup']); 201 $this->_modifyDB($sql); 202 //group should now exists try again to fetch it 203 $gid = $this->_getGroupID($group); 204 $newgroup = 1; // group newly created 205 } 206 } 207 if(!$gid) return false; // group didn't exist and can't be created 208 209 $sql = $this->conf['addUserGroup']; 210 if(strpos($sql, '%{uid}') !== false) { 211 $uid = $this->_getUserID($user); 212 $sql = str_replace('%{uid}', addslashes($uid), $sql); 213 } 214 $sql = str_replace('%{user}', addslashes($user), $sql); 215 $sql = str_replace('%{gid}', addslashes($gid), $sql); 216 $sql = str_replace('%{group}', addslashes($group), $sql); 217 if($this->_modifyDB($sql) !== false) { 218 $this->_flushUserInfoCache($user); 219 return true; 220 } 221 222 if($newgroup) { // remove previously created group on error 223 $sql = str_replace('%{gid}', addslashes($gid), $this->conf['delGroup']); 224 $sql = str_replace('%{group}', addslashes($group), $sql); 225 $this->_modifyDB($sql); 226 } 227 } 228 return false; 229 } 230 231 // @inherit function _delUserFromGroup($user $group) 232 // @inherit function _getGroups($user) 233 // @inherit function _getUserID($user) 234 235 /** 236 * Adds a new User to the database. 237 * 238 * The database connection must already be established 239 * for this function to work. Otherwise it will return 240 * 'false'. 241 * 242 * @param string $user login of the user 243 * @param string $pwd encrypted password 244 * @param string $name full name of the user 245 * @param string $mail email address 246 * @param array $grps array of groups the user should become member of 247 * @return bool 248 * 249 * @author Andreas Gohr <andi@splitbrain.org> 250 * @author Chris Smith <chris@jalakai.co.uk> 251 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 252 */ 253 protected function _addUser($user, $pwd, $name, $mail, $grps) { 254 if($this->dbcon && is_array($grps)) { 255 $sql = str_replace('%{user}', addslashes($user), $this->conf['addUser']); 256 $sql = str_replace('%{pass}', addslashes($pwd), $sql); 257 $sql = str_replace('%{name}', addslashes($name), $sql); 258 $sql = str_replace('%{email}', addslashes($mail), $sql); 259 if($this->_modifyDB($sql)) { 260 $uid = $this->_getUserID($user); 261 } else { 262 return false; 263 } 264 265 $group = ''; 266 $gid = false; 267 268 if($uid) { 269 foreach($grps as $group) { 270 $gid = $this->_addUserToGroup($user, $group, true); 271 if($gid === false) break; 272 } 273 274 if($gid !== false){ 275 $this->_flushUserInfoCache($user); 276 return true; 277 } else { 278 /* remove the new user and all group relations if a group can't 279 * be assigned. Newly created groups will remain in the database 280 * and won't be removed. This might create orphaned groups but 281 * is not a big issue so we ignore this problem here. 282 */ 283 $this->_delUser($user); 284 $this->_debug("PgSQL err: Adding user '$user' to group '$group' failed.", -1, __LINE__, __FILE__); 285 } 286 } 287 } 288 return false; 289 } 290 291 /** 292 * Opens a connection to a database and saves the handle for further 293 * usage in the object. The successful call to this functions is 294 * essential for most functions in this object. 295 * 296 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 297 * 298 * @return bool 299 */ 300 protected function _openDB() { 301 if(!$this->dbcon) { 302 $dsn = $this->conf['server'] ? 'host='.$this->conf['server'] : ''; 303 $dsn .= ' port='.$this->conf['port']; 304 $dsn .= ' dbname='.$this->conf['database']; 305 $dsn .= ' user='.$this->conf['user']; 306 $dsn .= ' password='.conf_decodeString($this->conf['password']); 307 308 $con = @pg_connect($dsn); 309 if($con) { 310 $this->dbcon = $con; 311 return true; // connection and database successfully opened 312 } else { 313 $this->_debug( 314 "PgSQL err: Connection to {$this->conf['user']}@{$this->conf['server']} not possible.", 315 -1, __LINE__, __FILE__ 316 ); 317 } 318 return false; // connection failed 319 } 320 return true; // connection already open 321 } 322 323 /** 324 * Closes a database connection. 325 * 326 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 327 */ 328 protected function _closeDB() { 329 if($this->dbcon) { 330 pg_close($this->dbcon); 331 $this->dbcon = 0; 332 } 333 } 334 335 /** 336 * Sends a SQL query to the database and transforms the result into 337 * an associative array. 338 * 339 * This function is only able to handle queries that returns a 340 * table such as SELECT. 341 * 342 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 343 * 344 * @param string $query SQL string that contains the query 345 * @return array|false the result table 346 */ 347 protected function _queryDB($query) { 348 $resultarray = array(); 349 if($this->dbcon) { 350 $result = @pg_query($this->dbcon, $query); 351 if($result) { 352 while(($t = pg_fetch_assoc($result)) !== false) 353 $resultarray[] = $t; 354 pg_free_result($result); 355 return $resultarray; 356 } else{ 357 $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__); 358 } 359 } 360 return false; 361 } 362 363 /** 364 * Executes an update or insert query. This differs from the 365 * MySQL one because it does NOT return the last insertID 366 * 367 * @author Andreas Gohr <andi@splitbrain.org> 368 * 369 * @param string $query 370 * @return bool 371 */ 372 protected function _modifyDB($query) { 373 if($this->dbcon) { 374 $result = @pg_query($this->dbcon, $query); 375 if($result) { 376 pg_free_result($result); 377 return true; 378 } 379 $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__); 380 } 381 return false; 382 } 383 384 /** 385 * Start a transaction 386 * 387 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 388 * 389 * @param string $mode could be 'READ' or 'WRITE' 390 * @return bool 391 */ 392 protected function _lockTables($mode) { 393 if($this->dbcon) { 394 $this->_modifyDB('BEGIN'); 395 return true; 396 } 397 return false; 398 } 399 400 /** 401 * Commit a transaction 402 * 403 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 404 * 405 * @return bool 406 */ 407 protected function _unlockTables() { 408 if($this->dbcon) { 409 $this->_modifyDB('COMMIT'); 410 return true; 411 } 412 return false; 413 } 414 415 /** 416 * Escape a string for insertion into the database 417 * 418 * @author Andreas Gohr <andi@splitbrain.org> 419 * 420 * @param string $string The string to escape 421 * @param bool $like Escape wildcard chars as well? 422 * @return string 423 */ 424 protected function _escape($string, $like = false) { 425 $string = pg_escape_string($string); 426 if($like) { 427 $string = addcslashes($string, '%_'); 428 } 429 return $string; 430 } 431 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body