1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4/** 5 * A framework for authentication and authorization in PHP applications 6 * 7 * LiveUser_Admin is meant to be used with the LiveUser package. 8 * It is composed of all the classes necessary to administrate 9 * data used by LiveUser. 10 * 11 * You'll be able to add/edit/delete/get things like: 12 * * Rights 13 * * Users 14 * * Groups 15 * * Areas 16 * * Applications 17 * * Subgroups 18 * * ImpliedRights 19 * 20 * And all other entities within LiveUser. 21 * 22 * At the moment we support the following storage containers: 23 * * DB 24 * * MDB 25 * * MDB2 26 * 27 * But it takes no time to write up your own storage container, 28 * so if you like to use native mysql functions straight, then it's possible 29 * to do so in under a hour! 30 * 31 * PHP version 4 and 5 32 * 33 * LICENSE: This library is free software; you can redistribute it and/or 34 * modify it under the terms of the GNU Lesser General Public 35 * License as published by the Free Software Foundation; either 36 * version 2.1 of the License, or (at your option) any later version. 37 * 38 * This library is distributed in the hope that it will be useful, 39 * but WITHOUT ANY WARRANTY; without even the implied warranty of 40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 41 * Lesser General Public License for more details. 42 * 43 * You should have received a copy of the GNU Lesser General Public 44 * License along with this library; if not, write to the Free Software 45 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 46 * MA 02111-1307 USA 47 * 48 * 49 * @category authentication 50 * @package LiveUser_Admin 51 * @author Markus Wolff <wolff@21st.de> 52 * @author Helgi �ormar �orbj�rnsson <dufuz@php.net> 53 * @author Lukas Smith <smith@pooteeweet.org> 54 * @author Arnaud Limbourg <arnaud@php.net> 55 * @author Christian Dickmann <dickmann@php.net> 56 * @author Matt Scifo <mscifo@php.net> 57 * @author Bjoern Kraus <krausbn@php.net> 58 * @copyright 2002-2006 Markus Wolff 59 * @license http://www.gnu.org/licenses/lgpl.txt 60 * @version $Id: Medium.php 211313 2006-04-13 09:29:20Z lsmith $ 61 * @link http://pear.php.net/LiveUser_Admin 62 */ 63 64define('LIVEUSER_GROUP_TYPE_ALL', 1); 65define('LIVEUSER_GROUP_TYPE_ROLE', 2); 66define('LIVEUSER_GROUP_TYPE_USER', 3); 67 68 /** 69 * Require parent class definition. 70 */ 71require_once 'LiveUser/Admin/Perm/Simple.php'; 72 73/** 74 * Medium permission administration class that extends the Simple class with the 75 * ability to create, update, remove and assign groups. 76 * 77 * This class provides a set of functions for implementing a user 78 * permission management system on live websites. All authorisation 79 * backends/containers must be extensions of this base class. 80 * 81 * @category authentication 82 * @package LiveUser_Admin 83 * @author Markus Wolff <wolff@21st.de> 84 * @author Bjoern Kraus <krausbn@php.net> 85 * @author Helgi �ormar �orbj�rnsson <dufuz@php.net> 86 * @copyright 2002-2006 Markus Wolff 87 * @license http://www.gnu.org/licenses/lgpl.txt 88 * @version Release: @package_version@ 89 * @link http://pear.php.net/LiveUser_Admin 90 */ 91class LiveUser_Admin_Perm_Medium extends LiveUser_Admin_Perm_Simple 92{ 93 /** 94 * Constructor 95 * 96 * @return void 97 * 98 * @access protected 99 */ 100 function LiveUser_Admin_Perm_Medium() 101 { 102 // Define the required tables for the Medium container. Used by the query builder 103 $this->LiveUser_Admin_Perm_Simple(); 104 $this->selectable_tables['getUsers'][] = 'groupusers'; 105 $this->selectable_tables['getGroups'] = array('groups', 'groupusers', 'grouprights', 'rights', 'translations'); 106 $this->withFieldMethodMap['group_id'] = 'getGroups'; 107 } 108 109 /** 110 * Add a group 111 * 112 * @param array containing atleast the key-value-pairs of all required 113 * columns in the group table 114 * @return int|bool false on error, true (or new id) on success 115 * 116 * @access public 117 */ 118 function addGroup($data) 119 { 120 $result = $this->_storage->insert('groups', $data); 121 // todo: notify observer 122 return $result; 123 } 124 125 /** 126 * Update groups 127 * 128 * @param array containing the key value pairs of columns to update 129 * @param array key values pairs (value may be a string or an array) 130 * This will construct the WHERE clause of your update 131 * Be careful, if you leave this blank no WHERE clause 132 * will be used and all groups will be affected by the update 133 * @return int|bool false on error, the affected rows on success 134 * 135 * @access public 136 */ 137 function updateGroup($data, $filters) 138 { 139 $result = $this->_storage->update('groups', $data, $filters); 140 // todo: notify observer 141 return $result; 142 } 143 144 /** 145 * Remove groups and all their relevant relations 146 * 147 * @param array key values pairs (value may be a string or an array) 148 * This will construct the WHERE clause of your update 149 * Be careful, if you leave this blank no WHERE clause 150 * will be used and all groups will be affected by the removed 151 * @return int|bool false on error, the affected rows on success 152 * 153 * @access public 154 */ 155 function removeGroup($filters) 156 { 157 // Prepare the filters. Based on the provided filters a new array will be 158 // created with the corresponding group_id's. If the filters are empty, 159 // cause an error or just have no result 0 or false will be returned 160 $filters = $this->_makeRemoveFilter($filters, 'group_id', 'getGroups'); 161 if (!$filters) { 162 return $filters; 163 } 164 165 // Clean up the database so no unnessacary information is left behind (members, granted rights) 166 // Remove all the users that are members of this group. 167 $result = $this->removeUserFromGroup($filters); 168 if ($result === false) { 169 return false; 170 } 171 172 // Remove the group. 173 $result = $this->revokeGroupRight($filters); 174 if ($result === false) { 175 return false; 176 } 177 178 $result = $this->_storage->delete('groups', $filters); 179 // todo: notify observer 180 return $result; 181 } 182 183 /** 184 * Grant group a right 185 * 186 * <code> 187 * // grant user id 13 the right NEWS_CHANGE 188 * $data = array( 189 * 'right_id' => NEWS_CHANGE, 190 * 'group_id' => 13 191 * ); 192 * $lua->perm->grantGroupRight($data); 193 * </code> 194 * 195 * @param array containing the group_id and right_id and optionally a right_level 196 * @return 197 * 198 * @access public 199 */ 200 function grantGroupRight($data) 201 { 202 // Sanity check on the right level, if not set, use the default 203 if (!array_key_exists('right_level', $data)) { 204 $data['right_level'] = LIVEUSER_MAX_LEVEL; 205 } 206 207 // check if the group has already been granted that right 208 $filters = array( 209 'group_id' => $data['group_id'], 210 'right_id' => $data['right_id'], 211 ); 212 213 $count = $this->_storage->selectCount('grouprights', 'right_id', $filters); 214 215 // It did already.. Add an error to the stack. 216 if ($count > 0) { 217 $this->stack->push( 218 LIVEUSER_ADMIN_ERROR, 'exception', 219 array('msg' => 'This group with id '.$data['group_id']. 220 ' has already been granted the right id '.$data['right_id']) 221 ); 222 return false; 223 } 224 225 $result = $this->_storage->insert('grouprights', $data); 226 // todo: notify observer 227 return $result; 228 } 229 230 /** 231 * Update right(s) for the given group(s) 232 * 233 * @param array containing the key value pairs of columns to update 234 * @param array key values pairs (value may be a string or an array) 235 * This will construct the WHERE clause of your update 236 * Be careful, if you leave this blank no WHERE clause 237 * will be used and all groups will be affected by the update 238 * @return int|bool false on error, the affected rows on success 239 * 240 * @access public 241 */ 242 function updateGroupRight($data, $filters) 243 { 244 $result = $this->_storage->update('grouprights', $data, $filters); 245 // todo: notify observer 246 return $result; 247 } 248 249 /** 250 * Revoke (remove) right(s) from the group(s) 251 * 252 * @param array key values pairs (value may be a string or an array) 253 * This will construct the WHERE clause of your update 254 * Be careful, if you leave this blank no WHERE clause 255 * will be used and all groups will be affected by the remove 256 * @return int|bool false on error, the affected rows on success 257 * 258 * @access public 259 */ 260 function revokeGroupRight($filters) 261 { 262 $result = $this->_storage->delete('grouprights', $filters); 263 // todo: notify observer 264 return $result; 265 } 266 267 /** 268 * Add a user to agroup 269 * 270 * @param array containing the perm_user_id and group_id 271 * @return 272 * 273 * @access public 274 */ 275 function addUserToGroup($data) 276 { 277 // check if the userhas already been granted added to that group 278 $filters = array( 279 'perm_user_id' => $data['perm_user_id'], 280 'group_id' => $data['group_id'], 281 ); 282 283 $count = $this->_storage->selectCount('groupusers', 'group_id', $filters); 284 285 // It already had been added. Return true. 286 if ($count > 0) { 287 return true; 288 } 289 290 $result = $this->_storage->insert('groupusers', $data); 291 // todo: notify observer 292 return $result; 293 } 294 295 /** 296 * Remove user(s) from group(s) 297 * 298 * @param array key values pairs (value may be a string or an array) 299 * This will construct the WHERE clause of your update 300 * Be careful, if you leave this blank no WHERE clause 301 * will be used and all users will be affected by the remove 302 * @return int|bool false on error, the affected rows on success 303 * 304 * @access public 305 */ 306 function removeUserFromGroup($filters) 307 { 308 $result = $this->_storage->delete('groupusers', $filters); 309 // todo: notify observer 310 return $result; 311 } 312 313 /** 314 * Fetches rights 315 * 316 * @param array containing key-value pairs for: 317 * 'fields' - ordered array containing the fields to fetch 318 * if empty all fields from the user table are fetched 319 * 'filters' - key values pairs (value may be a string or an array) 320 * 'orders' - key value pairs (values 'ASC' or 'DESC') 321 * 'rekey' - if set to true, returned array will have the 322 * first column as its first dimension 323 * 'group' - if set to true and $rekey is set to true, then 324 * all values with the same first column will be 325 * wrapped in an array 326 * 'limit' - number of rows to select 327 * 'offset' - first row to select 328 * 'select' - determines what query method to use: 329 * 'one' -> queryOne, 'row' -> queryRow, 330 * 'col' -> queryCol, 'all' ->queryAll (default) 331 * 'selectable_tables' - array list of tables that may be 332 * joined to in this query, the first element is 333 * the root table from which the joins are done 334 * 'by_group' - if joins should be done using the 'userrights' 335 * (false default) or through the 'grouprights' 336 * and 'groupusers' tables (true) 337 * @return bool|array false on failure or array with selected data 338 * 339 * @access public 340 */ 341 function getRights($params = array()) 342 { 343 $selectable_tables = $this->_findSelectableTables('getRights' , $params); 344 $root_table = reset($selectable_tables); 345 346 // If the by_group is present, and the grouprights table is not in the selectable_tables: 347 if (array_key_exists('by_group', $params) 348 && $params['by_group'] 349 && !in_array('grouprights', $selectable_tables) 350 ) { 351 unset($params['by_group']); 352 $key = array_search('userrights', $selectable_tables); 353 if ($key) { 354 // add the groupusers, replace the userrights with 355 // the grouprights and prepend the root table 356 $selectable_tables[0] = 'groupusers'; 357 $selectable_tables[$key] = 'grouprights'; 358 array_unshift($selectable_tables, $root_table); 359 } else { 360 // add the groupusers, prepend the grouprights and the root table 361 $selectable_tables[0] = 'groupusers'; 362 array_unshift($selectable_tables, 'grouprights'); 363 array_unshift($selectable_tables, $root_table); 364 } 365 } 366 367 return $this->_makeGet($params, $root_table, $selectable_tables); 368 } 369 370 /** 371 * Remove rights and all their relevant relations 372 * 373 * @param array key values pairs (value may be a string or an array) 374 * This will construct the WHERE clause of your update 375 * Be careful, if you leave this blank no WHERE clause 376 * will be used and all rights will be affected by the remove 377 * @return int|bool false on error, the affected rows on success 378 * 379 * @access public 380 */ 381 function removeRight($filters) 382 { 383 $filters = $this->_makeRemoveFilter($filters, 'right_id', 'getRights'); 384 if (!$filters) { 385 return $filters; 386 } 387 388 $result = $this->revokeGroupRight($filters); 389 if ($result === false) { 390 return false; 391 } 392 393 return parent::removeRight($filters); 394 } 395 396 /** 397 * Remove users and all their relevant relations 398 * 399 * @param array key values pairs (value may be a string or an array) 400 * This will construct the WHERE clause of your update 401 * Be careful, if you leave this blank no WHERE clause 402 * will be used and all users will be affected by the removed 403 * @return int|bool false on error, the affected rows on success 404 * 405 * @access public 406 */ 407 function removeUser($filters) 408 { 409 // Prepare the filters. Based on the provided filters a new array will be 410 // created with the corresponding perm_user_id's. If the filters are empty, 411 // cause an error or just have no result 0 or false will be returned 412 $filters = $this->_makeRemoveFilter($filters, 'perm_user_id', 'getUsers'); 413 if (!$filters) { 414 return $filters; 415 } 416 417 // Remove the users from any group it might be a member of. 418 // If an error occures, return false. 419 $result = $this->removeUserFromGroup($filters); 420 if ($result === false) { 421 return false; 422 } 423 424 // remove the user using Perm Simple. 425 return parent::removeUser($filters); 426 } 427 428 /** 429 * Fetches groups 430 * 431 * @param array containing key-value pairs for: 432 * 'fields' - ordered array containing the fields to fetch 433 * if empty all fields from the user table are fetched 434 * 'filters' - key values pairs (value may be a string or an array) 435 * 'orders' - key value pairs (values 'ASC' or 'DESC') 436 * 'rekey' - if set to true, returned array will have the 437 * first column as its first dimension 438 * 'group' - if set to true and $rekey is set to true, then 439 * all values with the same first column will be 440 * wrapped in an array 441 * 'limit' - number of rows to select 442 * 'offset' - first row to select 443 * 'select' - determines what query method to use: 444 * 'one' -> queryOne, 'row' -> queryRow, 445 * 'col' -> queryCol, 'all' ->queryAll (default) 446 * 'selectable_tables' - array list of tables that may be 447 * joined to in this query, the first element is 448 * the root table from which the joins are done 449 * @return bool|array false on failure or array with selected data 450 * 451 * @access public 452 */ 453 function getGroups($params = array()) 454 { 455 $selectable_tables = $this->_findSelectableTables('getGroups' , $params); 456 $root_table = reset($selectable_tables); 457 458 return $this->_makeGet($params, $root_table, $selectable_tables); 459 } 460} 461?> 462