2 rcs_id('$Id: WikiGroup.php,v 1.11 2004-02-07 10:41:25 rurban Exp $');
4 Copyright 2003, 2004 $ThePhpWikiProgrammingTeam
6 This file is part of PhpWiki.
8 PhpWiki is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 PhpWiki is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with PhpWiki; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 // For now we provide no default memberhsip method. This might change.
24 // (!defined('GROUP_METHOD')) define('GROUP_METHOD', "WIKIPAGE");
26 if (!defined('GROUP_METHOD') or
27 !in_array(GROUP_METHOD,
28 array('NONE','WIKIPAGE','DB','FILE','LDAP')))
29 trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
31 /* Special group names for ACL */
32 define('GROUP_EVERY', _("Every"));
33 define('GROUP_ANONYMOUS', _("Anonymous Users"));
34 define('GROUP_BOGOUSERS', _("Bogo Users"));
35 define('GROUP_SIGNED', _("Signed Users"));
36 define('GROUP_AUTHENTICATED', _("Authenticated Users"));
37 define('GROUP_ADMIN', _("Administrators"));
40 * WikiGroup is an abstract class to provide the base functions for determining
43 * WikiGroup is an abstract class with three functions:
44 * <ol><li />Provide the static method getGroup with will return the proper
46 * <li />Provide an interface for subclasses to implement.
47 * <li />Provide fallover methods (with error msgs) if not impemented in subclass.
49 * Do not ever instantiate this class use: $group = &WikiGroup::getGroup($request);
50 * This will instantiate the proper subclass.
51 * @author Joby Walker <zorloc@imperium.org>
56 /** The global WikiRequest object */
58 /** Array of groups $username is confirmed to belong to */
62 * Initializes a WikiGroup object which should never happen. Use:
63 * $group = &WikiGroup::getGroup($request);
64 * @param object $request The global WikiRequest object -- ignored.
66 function WikiGroup(&$request){
71 * Gets the current username and erases $this->membership if is different than
72 * the stored $this->username
73 * @return string Current username.
75 function _getUserName(){
76 $request = &$this->request;
77 $user = $request->getUser();
78 $username = $user->getID();
79 if ($username != $this->username) {
80 $this->membership = array();
81 $this->username = $username;
87 * Static method to return the WikiGroup subclass used in this wiki. Controlled
88 * by the constant GROUP_METHOD.
89 * @param object $request The global WikiRequest object.
90 * @return object Subclass of WikiGroup selected via GROUP_METHOD.
92 function getGroup($request){
93 switch (GROUP_METHOD){
95 return new GroupNone($request);
98 return new GroupWikiPage($request);
101 return new GroupDB($request);
104 return new GroupFile($request);
107 return new GroupLDAP($request);
110 trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
111 return new WikiGroup($request);
115 /* ACL PagePermissions will need those special groups based on the User status only */
116 function specialGroup($group){
117 return in_array($group,
127 * Determines if the current user is a member of a group.
129 * This method is an abstraction. The group is ignored, an error is sent, and
130 * false (not a member of the group) is returned.
131 * @param string $group Name of the group to check for membership (ignored).
132 * @return boolean True if user is a member, else false (always false).
134 function isMember($group){
135 if ($this->specialGroup($group)) {
136 $request = &$this->request;
137 $user = $request->getUser();
139 case GROUP_EVERY: return true;
140 case GROUP_ANONYMOUS: return ! $user->isSigned();
141 case GROUP_BOGOUSERS: return isa($user,'_BogoUser');
142 case GROUP_SIGNED: return $user->isSigned();
143 case GROUP_AUTHENTICATED: return $user->isAuthenticated();
144 case GROUP_ADMIN: return $user->isAdmin();
146 trigger_error(__sprintf("Undefined method %s for special group %s",
151 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
152 'isMember',GROUP_METHOD),
159 * Determines all of the groups of which the current user is a member.
161 * This method is an abstraction. An error is sent and an empty
163 * @return array Array of groups to which the user belongs (always empty).
165 function getAllGroupsIn(){
166 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
167 'getAllGroupsIn',GROUP_METHOD),
173 * Determines all of the members of a particular group.
175 * This method is an abstraction. The group is ignored, an error is sent,
176 * and an empty array is returned
177 * @param string $group Name of the group to get the full membership list of.
178 * @return array Array of usernames that have joined the group (always empty).
180 function getMembersOf($group){
181 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
182 'getMembersOf',GROUP_METHOD),
188 * Add the current or specified user to a group.
190 * This method is an abstraction. The group and user are ignored, an error
191 * is sent, and false (not added) is always returned.
192 * @param string $group User added to this group.
193 * @param string $user Username to add to the group (default = current user).
194 * @return bool On true user was added, false if not.
196 function setMemberOf($group, $user = false){
197 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
198 'setMemberOf',GROUP_METHOD),
204 * Remove the current or specified user to a group.
206 * This method is an abstraction. The group and user are ignored, and error
207 * is sent, and false (not removed) is always returned.
208 * @param string $group User removed from this group.
209 * @param string $user Username to remove from the group (default = current user).
210 * @return bool On true user was removed, false if not.
212 function removeMemberOf($group, $user = false){
213 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
214 'removeMemberOf',GROUP_METHOD),
221 * GroupNone disables all Group funtionality
223 * All of the GroupNone functions return false or empty values to indicate failure or
224 * no results. Use GroupNone if group controls are not desired.
225 * @author Joby Walker <zorloc@imperium.org>
227 class GroupNone extends WikiGroup{
232 * Ignores the parameter provided.
233 * @param object $request The global WikiRequest object - ignored.
235 function GroupNone(&$request){
240 * Determines if the current user is a member of a group.
242 * The group is ignored and false (not a member of the group) is returned.
243 * @param string $group Name of the group to check for membership (ignored).
244 * @return boolean True if user is a member, else false (always false).
246 function isMember($group){
247 if ($this->specialGroup($group)) {
248 return WikiGroup::isMember($group);
255 * Determines all of the groups of which the current user is a member.
257 * The group is ignored and an empty array (a member of no groups) is returned.
258 * @param string $group Name of the group to check for membership (ignored).
259 * @return array Array of groups to which the user belongs (always empty).
261 function getAllGroupsIn(){
266 * Determines all of the members of a particular group.
268 * The group is ignored and an empty array (a member of no groups) is returned.
269 * @param string $group Name of the group to check for membership (ignored).
270 * @return array Array of groups user belongs to (always empty).
272 function getMembersOf($group){
279 * GroupWikiPage provides group functionality via pages within the Wiki.
281 * GroupWikiPage is the Wiki way of managing a group. Every group will have
282 * a page. To modify the membership of the group, one only needs to edit the
283 * membership list on the page.
284 * @author Joby Walker <zorloc@imperium.org>
286 class GroupWikiPage extends WikiGroup{
291 * Initiallizes the three superclass instance variables
292 * @param object $request The global WikiRequest object.
294 function GroupWikiPage(&$request){
295 $this->request = &$request;
296 $this->username = null;
297 $this->membership = array();
301 * Determines if the current user is a member of a group.
303 * To determine membership in a particular group, this method checks the
304 * superclass instance variable $membership to see if membership has
305 * already been determined. If not, then the group page is parsed to
306 * determine membership.
307 * @param string $group Name of the group to check for membership.
308 * @return boolean True if user is a member, else false.
310 function isMember($group){
311 if ($this->specialGroup($group))
312 return WikiGroup::isMember($group);
314 $request = $this->request;
315 $username = $this->_getUserName();
316 if (isset($this->membership[$group])) {
317 return $this->membership[$group];
319 $group_page = $request->getPage($group);
320 if ($this->_inGroupPage($group_page)) {
321 $this->membership[$group] = true;
324 $this->membership[$group] = false;
329 * Private method to take a WikiDB_Page and parse to determine if the
330 * current_user is a member of the group.
331 * @param object $group_page WikiDB_Page object for the group's page
332 * @return boolean True if user is a member, else false.
335 function _inGroupPage($group_page){
336 $group_revision = $group_page->getCurrentRevision();
337 if ($group_revision->hasDefaultContents()) {
338 $group = $group_page->getName();
339 trigger_error(sprintf(_("Group %s does not exist"),$group), E_USER_WARNING);
342 $contents = $group_revision->getContent();
343 $match = '/^\s*[\*\#]+\s*' . $username . '\s*$/';
344 foreach($contents as $line){
345 if (preg_match($match, $line)) {
353 * Determines all of the groups of which the current user is a member.
355 * Checks the root Group page ('CategoryGroup') for the list of all groups,
356 * then checks each group to see if the current user is a member.
357 * @param string $group Name of the group to check for membership.
358 * @return array Array of groups to which the user belongs.
360 function getAllGroupsIn(){
361 $request = &$this->request;
362 $username = $this->_getUserName();
363 $membership = array();
364 $dbh = &$request->getDbh();
365 $master_page = $request->getPage('CategoryGroup');
366 $master_list = $master_page->getLinks(true);
367 while($group_page = $master_list->next()){
368 if ($this->_inGroupPage($group_page)) {
369 $group = $group_page->getName();
370 $membership[$group] = true;
372 $membership[$group] = false;
375 $this->membership = $membership;
380 * Determines all of the members of a particular group.
382 * Checks a group's page to return all the current members. Currently this
383 * method is disabled and triggers an error and returns an empty array.
384 * @param string $group Name of the group to get the full membership list of.
385 * @return array Array of usernames that have joined the group (always empty).
387 function getMembersOf($group){
388 trigger_error("GroupWikiPage::getMembersOf is not yet implimented",
392 * Waiting for a reliable way to check if a string is a username.
393 $request = $this->request;
395 $group_page = $request->getPage($group);
396 $group_revision = $group_page->getCurrentRevision();
397 if ($group_revision->hasDefaultContents()) {
398 trigger_error("Group $group does not exist", E_USER_WARNING);
401 $contents = $group_revision->getContent();
402 $match = '/^(\s*[\*\#]+\s*)(\w+)(\s*)$/';
404 foreach($contents as $line){
406 if(preg_match($match, $line, $matches)){
407 $members[] = $matches[2];
416 * GroupDb is configured by $DbAuthParams[] statements
420 class GroupDb extends WikiGroup {
422 var $_is_member, $_group_members, $_user_groups;
426 * @param object $request The global WikiRequest object.
428 function GroupDb(&$request){
429 global $DBAuthParams;
430 $this->request = &$request;
431 $this->username = null;
432 $this->membership = array();
434 if (empty($DBAuthParams['group_members']) or
435 empty($DBAuthParams['user_groups']) or
436 empty($DBAuthParams['is_member'])) {
437 trigger_error(_("No or not enough GROUP_DB SQL statements defined"), E_USER_WARNING);
440 _PassUser::getAuthDbh();
441 $this->_is_member = $this->_auth_dbi->prepare(str_replace(array('"$userid"','"$groupname"'),array('?','?'),$DBAuthParams['is_member']));
442 $this->_group_members = $this->_auth_dbi->prepare(str_replace('"$groupname"','?',$DBAuthParams['group_members']));
443 $this->_user_groups = $this->_auth_dbi->prepare(str_replace('"$userid"','?',$DBAuthParams['user_groups']));
447 * Determines if the current user is a member of a group.
449 * To determine membership in a particular group, this method checks the
450 * superclass instance variable $membership to see if membership has
451 * already been determined. If not, then the group page is parsed to
452 * determine membership.
453 * @param string $group Name of the group to check for membership.
454 * @return boolean True if user is a member, else false.
456 function isMember($group) {
457 if ($this->specialGroup($group))
458 return WikiGroup::isMember($group);
460 $request = $this->request;
461 $username = $this->_getUserName();
462 if (isset($this->membership[$group])) {
463 return $this->membership[$group];
465 $dbh = _PassUser::getAuthDbh();
466 $db_result = $dbh->execute($this->_is_member,array($username,$group));
467 if ($db_result->numRows() > 0) {
468 $this->membership[$group] = true;
471 $this->membership[$group] = false;
476 * Determines all of the groups of which the current user is a member.
478 * then checks each group to see if the current user is a member.
479 * @param string $group Name of the group to check for membership.
480 * @return array Array of groups to which the user belongs.
482 function getAllGroupsIn(){
483 $request = &$this->request;
484 $username = $this->_getUserName();
485 $membership = array();
487 $dbh = _PassUser::getAuthDbh();
488 $db_result = $dbh->execute($this->_user_groups,$username);
489 if ($db_result->numRows() > 0) {
490 while (list($group) = $db_result->fetchRow()) {
491 $membership[] = $group;
494 $this->membership = $membership;
499 * Determines all of the members of a particular group.
501 * Checks a group's page to return all the current members. Currently this
502 * method is disabled and triggers an error and returns an empty array.
503 * @param string $group Name of the group to get the full membership list of.
504 * @return array Array of usernames that have joined the group.
506 function getMembersOf($group){
507 $request = &$this->request;
508 $username = $this->_getUserName();
511 $dbh = _PassUser::getAuthDbh();
512 $db_result = $dbh->execute($this->_group_members,$group);
513 if ($db_result->numRows() > 0) {
514 while (list($userid) = $db_result->fetchRow()) {
515 $members[] = $userid;
523 * GroupFile is configured by AUTH_GROUP_FILE
524 * groupname: user1 user2 ...
528 class GroupFile extends WikiGroup {
533 * @param object $request The global WikiRequest object.
535 function GroupFile(&$request){
536 $this->request = &$request;
537 $this->username = null;
538 $this->membership = array();
540 if (!defined('AUTH_GROUP_FILE')) {
541 trigger_error(_("AUTH_GROUP_FILE not defined"), E_USER_WARNING);
544 if (!file_exists(AUTH_GROUP_FILE)) {
545 trigger_error(sprintf(_("Cannot open AUTH_GROUP_FILE %s"), AUTH_GROUP_FILE), E_USER_WARNING);
548 require 'lib/pear/File_Passwd.php';
549 $this->_file = File_Passwd($file);
553 * Determines if the current user is a member of a group.
555 * To determine membership in a particular group, this method checks the
556 * superclass instance variable $membership to see if membership has
557 * already been determined. If not, then the group file is parsed to
558 * determine membership.
559 * @param string $group Name of the group to check for membership.
560 * @return boolean True if user is a member, else false.
562 function isMember($group) {
563 if ($this->specialGroup($group))
564 return WikiGroup::isMember($group);
566 $request = $this->request;
567 $username = $this->_getUserName();
568 if (isset($this->membership[$group])) {
569 return $this->membership[$group];
572 foreach ($this->_file->users[] as $g => $u) {
573 $users = explode(' ',$u);
574 if (in_array($username,$users)) {
575 $this->membership[$group] = true;
579 $this->membership[$group] = false;
584 * Determines all of the groups of which the current user is a member.
586 * then checks each group to see if the current user is a member.
587 * @param string $group Name of the group to check for membership.
588 * @return array Array of groups to which the user belongs.
590 function getAllGroupsIn(){
591 $request = &$this->request;
592 $username = $this->_getUserName();
593 $membership = array();
595 foreach ($this->_file->users[] as $group => $u) {
596 $users = explode(' ',$u);
597 if (in_array($username,$users)) {
598 $this->membership[$group] = true;
599 $membership[] = $group;
602 $this->membership = $membership;
607 * Determines all of the members of a particular group.
609 * Checks a group's page to return all the current members. Currently this
610 * method is disabled and triggers an error and returns an empty array.
611 * @param string $group Name of the group to get the full membership list of.
612 * @return array Array of usernames that have joined the group.
614 function getMembersOf($group){
615 $request = &$this->request;
616 $username = $this->_getUserName();
619 if (!empty($this->_file->users[$group])) {
620 return explode(' ',$this->_file->users[$group]);
627 * Ldap is configured in index.php
631 class GroupLdap extends WikiGroup {
636 * @param object $request The global WikiRequest object.
638 function GroupLdap(&$request){
639 $this->request = &$request;
640 $this->username = null;
641 $this->membership = array();
643 if (!defined("LDAP_AUTH_HOST")) {
644 trigger_error(_("LDAP_AUTH_HOST not defined"), E_USER_WARNING);
647 if (! function_exists('ldap_connect')) {
649 if (! function_exists('ldap_connect')) {
650 trigger_error(_("No LDAP in this PHP version"), E_USER_WARNING);
654 if (!defined("LDAP_BASE_DN"))
655 define("LDAP_BASE_DN",'');
656 $this->base_dn = LDAP_BASE_DN;
657 if (strstr("ou=",LDAP_BASE_DN))
658 $this->base_dn = preg_replace("/(ou=\w+,)?()/","\$2",LDAP_BASE_DN);
662 * Determines if the current user is a member of a group.
665 * @param string $group Name of the group to check for membership.
666 * @return boolean True if user is a member, else false.
668 function isMember($group) {
669 if ($this->specialGroup($group))
670 return WikiGroup::isMember($group);
672 if (isset($this->membership[$group])) {
673 return $this->membership[$group];
675 $request = $this->request;
676 $username = $this->_getUserName();
678 $this->membership[$group] = in_array($username,$this->getMembersOf($group));
679 return $this->membership[$group];
683 * Determines all of the groups of which the current user is a member.
685 * @param string $group Name of the group to check for membership.
686 * @return array Array of groups to which the user belongs.
688 function getAllGroupsIn(){
689 $request = &$this->request;
690 $username = $this->_getUserName();
691 $membership = array();
693 if ($ldap = ldap_connect(LDAP_AUTH_HOST)) { // must be a valid LDAP server!
694 $r = @ldap_bind($ldap); // this is an anonymous bind
695 $sr = ldap_search($ldap, "ou=Users,".$this->base_dn,"uid=$username");
696 $info = ldap_get_entries($ldap, $sr);
697 for ($i = 0; $i < $info["count"]; $i++) {
698 if ($info[$i]["gidnumber"]["count"]) {
699 $gid = $info[$i]["gidnumber"][0];
700 $sr2 = ldap_search($ldap, "ou=Groups,".$this->base_dn,"gidNumber=$gid");
701 $info2 = ldap_get_entries($ldap, $sr2);
703 $membership[] = $info2[0]["cn"][0];
708 $this->membership = $membership;
713 * Determines all of the members of a particular group.
715 * Return all the members of the given group. LDAP just returns the gid of each user
716 * @param string $group Name of the group to get the full membership list of.
717 * @return array Array of usernames that have joined the group.
719 function getMembersOf($group){
721 if ($ldap = ldap_connect(LDAP_AUTH_HOST)) { // must be a valid LDAP server!
722 $r = @ldap_bind($ldap); // this is an anonymous bind
723 $sr = ldap_search($ldap, "ou=Groups,".$this->base_dn,"cn=$group");
724 $info = ldap_get_entries($ldap, $sr);
725 for ($i = 0; $i < $info["count"]; $i++) {
726 $gid = $info[$i]["gidnumber"][0];
727 $sr2 = ldap_search($ldap, "ou=Users,".$this->base_dn,"gidNumber=$gid");
728 $info2 = ldap_get_entries($ldap, $sr2);
729 for ($j = 0; $j < $info2["count"]; $j++) {
730 $members[] = $info2[$j]["cn"][0];
739 // $Log: not supported by cvs2svn $
740 // Revision 1.10 2004/02/03 09:45:39 rurban
741 // LDAP cleanup, start of new Pref classes
743 // Revision 1.9 2004/02/01 09:14:11 rurban
744 // Started with Group_Ldap (not yet ready)
745 // added new _AuthInfo plugin to help in auth problems (warning: may display passwords)
746 // fixed some configurator vars
747 // renamed LDAP_AUTH_SEARCH to LDAP_BASE_DN
748 // changed PHPWIKI_VERSION from 1.3.8a to 1.3.8pre
749 // USE_DB_SESSION defaults to true on SQL
750 // changed GROUP_METHOD definition to string, not constants
751 // changed sample user DBAuthParams from UPDATE to REPLACE to be able to
752 // create users. (Not to be used with external databases generally, but
753 // with the default internal user table)
755 // fixed the IndexAsConfigProblem logic. this was flawed:
756 // scripts which are the same virtual path defined their own lib/main call
757 // (hmm, have to test this better, phpwiki.sf.net/demo works again)
759 // Revision 1.8 2004/01/27 23:23:39 rurban
760 // renamed ->Username => _userid for consistency
761 // renamed mayCheckPassword => mayCheckPass
762 // fixed recursion problem in WikiUserNew
763 // fixed bogo login (but not quite 100% ready yet, password storage)
765 // Revision 1.7 2004/01/26 16:52:40 rurban
766 // added GroupDB and GroupFile classes
768 // Revision 1.6 2003/12/07 19:29:11 carstenklapp
769 // Code Housecleaning: fixed syntax errors. (php -l *.php)
771 // Revision 1.5 2003/02/22 20:49:55 dairiki
772 // Fixes for "Call-time pass by reference has been deprecated" errors.
774 // Revision 1.4 2003/01/21 04:02:39 zorloc
775 // Added Log entry and page footer.
782 // c-hanging-comment-ender-p: nil
783 // indent-tabs-mode: nil