]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiGroup.php
include [all] Include and file path should be devided with single space. File path...
[SourceForge/phpwiki.git] / lib / WikiGroup.php
1 <?php
2
3 /*
4  * Copyright (C) 2003, 2004 $ThePhpWikiProgrammingTeam
5  * Copyright (C) 2010 Marc-Etienne Vargenau, Alcatel-Lucent
6  *
7  * This file is part of PhpWiki.
8  *
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 if (!defined('GROUP_METHOD') or
25     !in_array(GROUP_METHOD,
26               array('NONE','WIKIPAGE','DB','FILE','LDAP')))
27     trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
28
29 /* Special group names for ACL */
30 define('GROUP_EVERY',        _("Every"));
31 define('GROUP_ANONYMOUS',    _("Anonymous Users"));
32 define('GROUP_BOGOUSER',    _("Bogo Users"));
33 define('GROUP_SIGNED',        _("Signed Users"));
34 define('GROUP_AUTHENTICATED',    _("Authenticated Users"));
35 define('GROUP_ADMIN',        _("Administrators"));
36 define('GROUP_OWNER',        _("Owner"));
37 define('GROUP_CREATOR',           _("Creator"));
38
39 /**
40  * WikiGroup is an abstract class to provide the base functions for determining
41  * group membership for a specific user. Some functions are user independent.
42  *
43  * Limitation: For the current user only. This must be fixed to be able to query
44  * for membership of any user.
45  *
46  * WikiGroup is an abstract class with three functions:
47  * <ol><li />Provide the static method getGroup with will return the proper
48  *         subclass.
49  *     <li />Provide an interface for subclasses to implement.
50  *     <li />Provide fallover methods (with error msgs) if not impemented in subclass.
51  * </ol>
52  * Do not ever instantiate this class. Use: $group = &WikiGroup::getGroup();
53  * This will instantiate the proper subclass.
54  *
55  * @author Joby Walker <zorloc@imperium.org>
56  * @author Reini Urban
57  */
58 class WikiGroup{
59     /** User name */
60     var $username = '';
61     /** User object if different from current user */
62     var $user;
63     /** The global WikiRequest object */
64     //var $request;
65     /** Array of groups $username is confirmed to belong to */
66     var $membership;
67     /** boolean if not the current user */
68     var $not_current = false;
69
70     /**
71      * Initializes a WikiGroup object which should never happen.  Use:
72      * $group = &WikiGroup::getGroup();
73      * @param object $request The global WikiRequest object -- ignored.
74      */
75     function WikiGroup($not_current = false) {
76         $this->not_current = $not_current;
77         //$this->request =& $GLOBALS['request'];
78     }
79
80     /**
81      * Gets the current username from the internal user object
82      * and erases $this->membership if is different than
83      * the stored $this->username
84      * @return string Current username.
85      */
86     function _getUserName(){
87         global $request;
88         $user = (!empty($this->user)) ? $this->user : $request->getUser();
89         $username = $user->getID();
90         if ($username != $this->username) {
91             $this->membership = array();
92             $this->username = $username;
93         }
94         if (!$this->not_current)
95            $this->user = $user;
96         return $username;
97     }
98
99     /**
100      * Static method to return the WikiGroup subclass used in this wiki.  Controlled
101      * by the constant GROUP_METHOD.
102      * @param  object $request The global WikiRequest object.
103      * @return object Subclass of WikiGroup selected via GROUP_METHOD.
104      */
105     function getGroup($not_current = false){
106         switch (GROUP_METHOD){
107             case "NONE":
108                 return new GroupNone($not_current);
109                 break;
110             case "WIKIPAGE":
111                 return new GroupWikiPage($not_current);
112                 break;
113             case "DB":
114                 if ($GLOBALS['DBParams']['dbtype'] == 'ADODB') {
115                     return new GroupDB_ADODB($not_current);
116                 } elseif ($GLOBALS['DBParams']['dbtype'] == 'SQL') {
117                     return new GroupDb_PearDB($not_current);
118                 } else {
119                     trigger_error("GROUP_METHOD = DB: Unsupported dbtype "
120                                   . $GLOBALS['DBParams']['dbtype'],
121                                   E_USER_ERROR);
122                 }
123                 break;
124             case "FILE":
125                 return new GroupFile($not_current);
126                 break;
127             case "LDAP":
128                 return new GroupLDAP($not_current);
129                 break;
130             default:
131                 trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
132                 return new WikiGroup($not_current);
133         }
134     }
135
136     /** ACL PagePermissions will need those special groups based on the User status only.
137      *  translated
138      */
139     function specialGroup($group){
140         return in_array($group,$this->specialGroups());
141     }
142     /** untranslated */
143     function _specialGroup($group){
144         return in_array($group,$this->_specialGroups());
145     }
146     /** translated */
147     function specialGroups(){
148         return array(
149                      GROUP_EVERY,
150                      GROUP_ANONYMOUS,
151                      GROUP_BOGOUSER,
152                      GROUP_SIGNED,
153                      GROUP_AUTHENTICATED,
154                      GROUP_ADMIN,
155                      GROUP_OWNER,
156                      GROUP_CREATOR);
157     }
158     /** untranslated */
159     function _specialGroups(){
160         return array(
161                      "_EVERY",
162                      "_ANONYMOUS",
163                      "_BOGOUSER",
164                      "_SIGNED",
165                      "_AUTHENTICATED",
166                      "_ADMIN",
167                      "_OWNER",
168                      "_CREATOR");
169     }
170
171     /**
172      * Determines if the current user is a member of a group.
173      *
174      * This method is an abstraction.  The group is ignored, an error is sent, and
175      * false (not a member of the group) is returned.
176      * @param  string  $group Name of the group to check for membership (ignored).
177      * @return boolean True if user is a member, else false (always false).
178      */
179     function isMember($group){
180         if (isset($this->membership[$group]))
181             return $this->membership[$group];
182         if ($this->specialGroup($group)) {
183             return $this->isSpecialMember($group);
184         } else {
185             trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
186                                     'isMember', GROUP_METHOD),
187                           E_USER_WARNING);
188         }
189         return false;
190     }
191
192     function isSpecialMember($group){
193         global $request;
194
195         if (isset($this->membership[$group]))
196             return $this->membership[$group];
197         $user = (!empty($this->user)) ? $this->user : $request->getUser();
198         switch ($group) {
199             case GROUP_EVERY:
200                 return $this->membership[$group] = true;
201             case GROUP_ANONYMOUS:
202                 return $this->membership[$group] = ! $user->isSignedIn();
203             case GROUP_BOGOUSER:
204                 return $this->membership[$group] = (isa($user,'_BogoUser')
205                                                     and $user->_level >= WIKIAUTH_BOGO);
206             case GROUP_SIGNED:
207                 return $this->membership[$group] = $user->isSignedIn();
208             case GROUP_AUTHENTICATED:
209                 return $this->membership[$group] = $user->isAuthenticated();
210             case GROUP_ADMIN:
211                 return $this->membership[$group] = (isset($user->_level)
212                                                     and $user->_level == WIKIAUTH_ADMIN);
213             case GROUP_OWNER:
214             case GROUP_CREATOR:
215                 return false;
216             default:
217                 trigger_error(__sprintf("Undefined method %s for special group %s",
218                                         'isMember',$group),
219                               E_USER_WARNING);
220         }
221         return false;
222     }
223
224     /**
225      * Determines all of the groups of which the current user is a member.
226      *
227      * This method is an abstraction.  An error is sent and an empty
228      * array is returned.
229      * @return array Array of groups to which the user belongs (always empty).
230      */
231     function getAllGroupsIn(){
232         trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
233                                 'getAllGroupsIn', GROUP_METHOD),
234                       E_USER_WARNING);
235         return array();
236     }
237
238     function _allUsers() {
239         static $result = array();
240         if (!empty($result))
241             return $result;
242
243         global $request;
244         /* WikiPage users: */
245         $dbh =& $request->_dbi;
246         $page_iter = $dbh->getAllPages();
247         $users = array();
248         while ($page = $page_iter->next()) {
249             if ($page->isUserPage())
250                 $users[] = $page->_pagename;
251         }
252
253         /* WikiDB users from prefs (not from users): */
254         if (ENABLE_USER_NEW)
255             $dbi = _PassUser::getAuthDbh();
256         else
257             $dbi = false;
258
259         if ($dbi and $dbh->getAuthParam('pref_select')) {
260             //get prefs table
261             $sql = preg_replace('/SELECT .+ FROM/i','SELECT userid FROM',
262                                 $dbh->getAuthParam('pref_select'));
263             //don't strip WHERE, only the userid stuff.
264             $sql = preg_replace('/(WHERE.*?)\s+\w+\s*=\s*["\']\$userid[\'"]/i','\\1 AND 1', $sql);
265             $sql = str_replace('WHERE AND 1','',$sql);
266             if (isa($dbi, 'ADOConnection')) {
267                 $db_result = $dbi->Execute($sql);
268                 foreach ($db_result->GetArray() as $u) {
269                     $users = array_merge($users,array_values($u));
270                 }
271             } elseif (isa($dbi, 'DB_common')) { // PearDB
272                 $users = array_merge($users, $dbi->getCol($sql));
273             }
274         }
275
276         /* WikiDB users from users: */
277         // Fixme: don't strip WHERE, only the userid stuff.
278         if ($dbi and $dbh->getAuthParam('auth_user_exists')) {
279             //don't strip WHERE, only the userid stuff.
280             $sql = preg_replace('/(WHERE.*?)\s+\w+\s*=\s*["\']\$userid[\'"]/i','\\1 AND 1',
281                                 $dbh->getAuthParam('auth_user_exists'));
282             $sql = str_replace('WHERE AND 1','', $sql);
283             if (isa($dbi, 'ADOConnection')) {
284                 $db_result = $dbi->Execute($sql);
285                 foreach ($db_result->GetArray() as $u) {
286                    $users = array_merge($users, array_values($u));
287                 }
288             } elseif (isa($dbi, 'DB_common')) {
289                 $users = array_merge($users, $dbi->getCol($sql));
290             }
291         }
292
293         // remove empty and duplicate users
294         $result = array();
295         foreach ($users as $u) {
296             if (empty($u) or in_array($u,$result)) continue;
297             $result[] = $u;
298         }
299         return $result;
300     }
301
302     /**
303      * Determines all of the members of a particular group.
304      *
305      * This method is an abstraction.  The group is ignored, an error is sent,
306      * and an empty array is returned
307      * @param  string $group Name of the group to get the full membership list of.
308      * @return array  Array of usernames that have joined the group (always empty).
309      */
310     function getMembersOf($group){
311         if ($this->specialGroup($group)) {
312             return $this->getSpecialMembersOf($group);
313         }
314         trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
315                                 'getMembersOf', GROUP_METHOD),
316                       E_USER_WARNING);
317         return array();
318     }
319
320     function getSpecialMembersOf($group) {
321         //$request = &$this->request;
322         $all = $this->_allUsers();
323         $users = array();
324         switch ($group) {
325         case GROUP_EVERY:
326             return $all;
327         case GROUP_ANONYMOUS:
328             return $users;
329         case GROUP_BOGOUSER:
330             foreach ($all as $u) {
331                 if (isWikiWord($u)) $users[] = $u;
332             }
333             return $users;
334         case GROUP_SIGNED:
335             foreach ($all as $u) {
336                 $user = WikiUser($u);
337                 if ($user->isSignedIn()) $users[] = $u;
338             }
339             return $users;
340         case GROUP_AUTHENTICATED:
341             foreach ($all as $u) {
342                 $user = WikiUser($u);
343                 if ($user->isAuthenticated()) $users[] = $u;
344             }
345             return $users;
346         case GROUP_ADMIN:
347             foreach ($all as $u) {
348                 $user = WikiUser($u);
349                 if (isset($user->_level) and $user->_level == WIKIAUTH_ADMIN)
350                     $users[] = $u;
351             }
352             return $users;
353         case GROUP_OWNER:
354         case GROUP_CREATOR:
355             // this could get complex so just return an empty array
356             return false;
357         default:
358             trigger_error(__sprintf("Unknown special group '%s'", $group),
359                           E_USER_WARNING);
360         }
361     }
362
363     /**
364      * Add the current or specified user to a group.
365      *
366      * This method is an abstraction.  The group and user are ignored, an error
367      * is sent, and false (not added) is always returned.
368      * @param  string $group User added to this group.
369      * @param  string $user  Username to add to the group (default = current user).
370      * @return bool   On true user was added, false if not.
371      */
372     function setMemberOf($group, $user = false){
373         trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
374                                 'setMemberOf', GROUP_METHOD),
375                       E_USER_WARNING);
376         return false;
377     }
378
379     /**
380      * Remove the current or specified user to a group.
381      *
382      * This method is an abstraction.  The group and user are ignored, and error
383      * is sent, and false (not removed) is always returned.
384      * @param  string $group User removed from this group.
385      * @param  string $user  Username to remove from the group (default = current user).
386      * @return bool   On true user was removed, false if not.
387      */
388     function removeMemberOf($group, $user = false){
389         trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
390                                 'removeMemberOf', GROUP_METHOD),
391                       E_USER_WARNING);
392         return false;
393     }
394 }
395
396 /**
397  * GroupNone disables all Group funtionality
398  *
399  * All of the GroupNone functions return false or empty values to indicate failure or
400  * no results.  Use GroupNone if group controls are not desired.
401  * @author Joby Walker <zorloc@imperium.org>
402  */
403 class GroupNone extends WikiGroup{
404
405     /**
406      * Constructor
407      *
408      * Ignores the parameter provided.
409      * @param object $request The global WikiRequest object - ignored.
410      */
411     function GroupNone() {
412         //$this->request = &$GLOBALS['request'];
413         return;
414     }
415
416     /**
417      * Determines if the current user is a member of a group.
418      *
419      * The group is ignored and false (not a member of the group) is returned.
420      * @param  string  $group Name of the group to check for membership (ignored).
421      * @return boolean True if user is a member, else false (always false).
422      */
423     function isMember($group){
424         if ($this->specialGroup($group)) {
425             return $this->isSpecialMember($group);
426         } else {
427             return false;
428         }
429     }
430
431     /**
432      * Determines all of the groups of which the current user is a member.
433      *
434      * The group is ignored and an empty array (a member of no groups) is returned.
435      * @param  string $group Name of the group to check for membership (ignored).
436      * @return array  Array of groups to which the user belongs (always empty).
437      */
438     function getAllGroupsIn(){
439         return array();
440     }
441
442     /**
443      * Determines all of the members of a particular group.
444      *
445      * The group is ignored and an empty array (a member of no groups) is returned.
446      * @param  string $group Name of the group to check for membership (ignored).
447      * @return array  Array of groups user belongs to (always empty).
448      */
449     function getMembersOf($group){
450         return array();
451     }
452
453 }
454
455 /**
456  * GroupWikiPage provides group functionality via pages within the Wiki.
457  *
458  * GroupWikiPage is the Wiki way of managing a group.  Every group will have
459  * a page. To modify the membership of the group, one only needs to edit the
460  * membership list on the page.
461  * @author Joby Walker <zorloc@imperium.org>
462  */
463 class GroupWikiPage extends WikiGroup{
464
465     /**
466      * Constructor
467      *
468      * Initializes the three superclass instance variables
469      * @param object $request The global WikiRequest object.
470      */
471     function GroupWikiPage() {
472         //$this->request = &$GLOBALS['request'];
473         $this->username = $this->_getUserName();
474         //$this->username = null;
475         $this->membership = array();
476     }
477
478     /**
479      * Determines if the current user is a member of a group.
480      *
481      * To determine membership in a particular group, this method checks the
482      * superclass instance variable $membership to see if membership has
483      * already been determined.  If not, then the group page is parsed to
484      * determine membership.
485      * @param  string  $group Name of the group to check for membership.
486      * @return boolean True if user is a member, else false.
487      */
488     function isMember($group){
489         if (isset($this->membership[$group])) {
490             return $this->membership[$group];
491         }
492         global $request;
493         $group_page = $request->getPage($group);
494         if ($this->_inGroupPage($group_page)) {
495             $this->membership[$group] = true;
496             return true;
497         }
498         $this->membership[$group] = false;
499         // Let grouppages override certain defaults, such as members of admin
500         if ($this->specialGroup($group)) {
501             return $this->isSpecialMember($group);
502         }
503         return false;
504     }
505
506     /**
507     * Private method to take a WikiDB_Page and parse to determine if the
508     * current_user is a member of the group.
509     * @param object $group_page WikiDB_Page object for the group's page
510     * @return boolean True if user is a member, else false.
511     * @access private
512     */
513     function _inGroupPage($group_page, $strict=false){
514         $group_revision = $group_page->getCurrentRevision();
515         if ($group_revision->hasDefaultContents()) {
516             $group = $group_page->getName();
517             if ($strict) trigger_error(sprintf(_("Group page '%s' does not exist"), $group),
518                                        E_USER_WARNING);
519             return false;
520         }
521         $contents = $group_revision->getContent();
522         $match = '/^\s*[\*\#]+\s*\[?' . $this->username . '\]?(\s|$)/';
523         foreach ($contents as $line){
524             if (preg_match($match, $line)) {
525                 return true;
526             }
527         }
528         return false;
529     }
530
531     /**
532      * Determines all of the groups of which the current user is a member.
533      *
534      * Checks the root Group page ('CategoryGroup') for the list of all groups,
535      * then checks each group to see if the current user is a member.
536      * @param  string $group Name of the group to check for membership.
537      * @return array  Array of groups to which the user belongs.
538      */
539     function getAllGroupsIn(){
540         $membership = array();
541
542         $specialgroups = $this->specialGroups();
543         foreach ($specialgroups as $group) {
544             $this->membership[$group] = $this->isSpecialMember($group);
545         }
546
547         global $request;
548         $dbh = &$request->_dbi;
549         $master_page = $request->getPage(CATEGORY_GROUP_PAGE);
550         $master_list = $master_page->getLinks(true);
551         while ($group_page = $master_list->next()){
552             $group = $group_page->getName();
553             $this->membership[$group] = $this->_inGroupPage($group_page);
554         }
555         foreach ($this->membership as $g => $bool) {
556             if ($bool) $membership[] = $g;
557         }
558         return $membership;
559     }
560
561     /**
562      * Determines all of the members of a particular group.
563      *
564      * Checks a group's page to return all the current members.  Currently this
565      * method is disabled and triggers an error and returns an empty array.
566      * @param  string $group Name of the group to get the full membership list of.
567      * @return array  Array of usernames that have joined the group (always empty).
568      */
569     function getMembersOf($group){
570         if ($this->specialGroup($group))
571             return $this->getSpecialMembersOf($group);
572
573         $group_page = $GLOBALS['request']->getPage($group);
574         $group_revision = $group_page->getCurrentRevision();
575         if ($group_revision->hasDefaultContents()) {
576             trigger_error(sprintf(_("Group %s does not exist"),$group), E_USER_WARNING);
577             return array();
578         }
579         $contents = $group_revision->getContent();
580         // This is not really a reliable way to check if a string is a username. But better than nothing.
581         $match = '/^(\s*[\*\#]+\s*\[?)(\w+)(\]?\s*)$/';
582         $members = array();
583         foreach ($contents as $line){
584             if (preg_match($match, $line, $matches)){
585                 $members[] = $matches[2];
586             }
587         }
588         return $members;
589     }
590 }
591
592 /**
593  * GroupDb is configured by $DbAuthParams[] statements
594  *
595  * Fixme: adodb
596  * @author ReiniUrban
597  */
598 class GroupDb extends WikiGroup {
599
600     var $_is_member, $_group_members, $_user_groups;
601
602     /**
603      * Constructor
604      *
605      * @param object $request The global WikiRequest object. ignored
606      */
607     function GroupDb() {
608         global $DBAuthParams, $DBParams;
609         //$this->request = &$GLOBALS['request'];
610         $this->username = $this->_getUserName();
611         $this->membership = array();
612
613         if (empty($DBAuthParams['group_members']) or
614             empty($DBAuthParams['user_groups']) or
615             empty($DBAuthParams['is_member'])) {
616             trigger_error(_("No or not enough GROUP_DB SQL statements defined"),
617                           E_USER_WARNING);
618             return new GroupNone();
619         }
620         // FIXME: This only works with ENABLE_USER_NEW
621         if (empty($this->user)) {
622             // use _PassUser::prepare instead
623             if (isa($request->getUser(),'_PassUser'))
624                 $user = $request->getUser();
625             else
626                 $user = new _PassUser($this->username);
627         } elseif (!isa($this->user, '_PassUser')) {
628             $user = new _PassUser($this->username);
629         } else {
630             $user =& $this->user;
631         }
632         if (isa($this->user, '_PassUser')) { // TODO: safety by Charles Corrigan
633             $this->_is_member = $user->prepare($DBAuthParams['is_member'],
634                                            array('userid','groupname'));
635             $this->_group_members = $user->prepare($DBAuthParams['group_members'],'groupname');
636             $this->_user_groups = $user->prepare($DBAuthParams['user_groups'],'userid');
637             $this->dbh = $user->_auth_dbi;
638         }
639     }
640 }
641
642 /**
643  * PearDB methods
644  *
645  * @author ReiniUrban
646  */
647 class GroupDb_PearDB extends GroupDb {
648
649     /**
650      * Determines if the current user is a member of a database group.
651      *
652      * @param  string  $group Name of the group to check for membership.
653      * @return boolean True if user is a member, else false.
654      */
655     function isMember($group) {
656         if (isset($this->membership[$group])) {
657             return $this->membership[$group];
658         }
659         $dbh = & $this->dbh;
660         $db_result = $dbh->query(sprintf($this->_is_member,
661                                          $dbh->quote($this->username),
662                                          $dbh->quote($group)));
663         if ($db_result->numRows() > 0) {
664             $this->membership[$group] = true;
665             return true;
666         }
667         $this->membership[$group] = false;
668         // Let override certain defaults, such as members of admin
669         if ($this->specialGroup($group))
670             return $this->isSpecialMember($group);
671         return false;
672     }
673
674     /**
675      * Determines all of the groups of which the current user is a member.
676      *
677      * then checks each group to see if the current user is a member.
678      * @param  string $group Name of the group to check for membership.
679      * @return array  Array of groups to which the user belongs.
680      */
681     function getAllGroupsIn(){
682         $membership = array();
683
684         $dbh = & $this->dbh;
685         $db_result = $dbh->query(sprintf($this->_user_groups, $dbh->quote($this->username)));
686         if ($db_result->numRows() > 0) {
687             while (list($group) = $db_result->fetchRow(DB_FETCHMODE_ORDERED)) {
688                 $membership[] = $group;
689                 $this->membership[$group] = true;
690             }
691         }
692
693         $specialgroups = $this->specialGroups();
694         foreach ($specialgroups as $group) {
695             if ($this->isMember($group)) {
696                 $membership[] = $group;
697             }
698         }
699         return $membership;
700     }
701
702     /**
703      * Determines all of the members of a particular group.
704      *
705      * Checks a group's page to return all the current members.  Currently this
706      * method is disabled and triggers an error and returns an empty array.
707      * @param  string $group Name of the group to get the full membership list of.
708      * @return array  Array of usernames that have joined the group.
709      */
710     function getMembersOf($group){
711
712         $members = array();
713         $dbh = & $this->dbh;
714         $db_result = $dbh->query(sprintf($this->_group_members,$dbh->quote($group)));
715         if ($db_result->numRows() > 0) {
716             while (list($userid) = $db_result->fetchRow(DB_FETCHMODE_ORDERED)) {
717                 $members[] = $userid;
718             }
719         }
720         // add certain defaults, such as members of admin
721         if ($this->specialGroup($group))
722             $members = array_merge($members, $this->getSpecialMembersOf($group));
723         return $members;
724     }
725 }
726
727 /**
728  * ADODB methods
729  *
730  * @author ReiniUrban
731  */
732 class GroupDb_ADODB extends GroupDb {
733
734     /**
735      * Determines if the current user is a member of a database group.
736      *
737      * @param  string  $group Name of the group to check for membership.
738      * @return boolean True if user is a member, else false.
739      */
740     function isMember($group) {
741         if (isset($this->membership[$group])) {
742             return $this->membership[$group];
743         }
744         $dbh = & $this->dbh;
745         $rs = $dbh->Execute(sprintf($this->_is_member,$dbh->qstr($this->username),
746                                     $dbh->qstr($group)));
747         if ($rs->EOF) {
748             $rs->Close();
749         } else {
750             if ($rs->numRows() > 0) {
751                 $this->membership[$group] = true;
752                 $rs->Close();
753                 return true;
754             }
755         }
756         $this->membership[$group] = false;
757         if ($this->specialGroup($group))
758             return $this->isSpecialMember($group);
759
760         return false;
761     }
762
763     /**
764      * Determines all of the groups of which the current user is a member.
765      * then checks each group to see if the current user is a member.
766      *
767      * @param  string $group Name of the group to check for membership.
768      * @return array  Array of groups to which the user belongs.
769      */
770     function getAllGroupsIn(){
771         $membership = array();
772
773         $dbh = & $this->dbh;
774         $rs = $dbh->Execute(sprintf($this->_user_groups, $dbh->qstr($this->username)));
775         if (!$rs->EOF and $rs->numRows() > 0) {
776             while (!$rs->EOF) {
777                 $group = reset($rs->fields);
778                 $membership[] = $group;
779                 $this->membership[$group] = true;
780                 $rs->MoveNext();
781             }
782         }
783         $rs->Close();
784
785         $specialgroups = $this->specialGroups();
786         foreach ($specialgroups as $group) {
787             if ($this->isMember($group)) {
788                 $membership[] = $group;
789             }
790         }
791         return $membership;
792     }
793
794     /**
795      * Determines all of the members of a particular group.
796      *
797      * @param  string $group Name of the group to get the full membership list of.
798      * @return array  Array of usernames that have joined the group.
799      */
800     function getMembersOf($group){
801         $members = array();
802         $dbh = & $this->dbh;
803         $rs = $dbh->Execute(sprintf($this->_group_members,$dbh->qstr($group)));
804         if (!$rs->EOF and $rs->numRows() > 0) {
805             while (!$rs->EOF) {
806                 $members[] = reset($rs->fields);
807                 $rs->MoveNext();
808             }
809         }
810         $rs->Close();
811         // add certain defaults, such as members of admin
812         if ($this->specialGroup($group))
813             $members = array_merge($members, $this->getSpecialMembersOf($group));
814         return $members;
815     }
816 }
817
818 /**
819  * GroupFile is configured by AUTH_GROUP_FILE
820  * groupname: user1 user2 ...
821  *
822  * @author ReiniUrban
823  */
824 class GroupFile extends WikiGroup {
825
826     /**
827      * Constructor
828      *
829      * @param object $request The global WikiRequest object.
830      */
831     function GroupFile(){
832         //$this->request = &$GLOBALS['request'];
833         $this->username = $this->_getUserName();
834         //$this->username = null;
835         $this->membership = array();
836
837         if (!defined('AUTH_GROUP_FILE')) {
838             trigger_error(sprintf(_("%s: not defined"), "AUTH_GROUP_FILE"),
839                           E_USER_WARNING);
840             return false;
841         }
842         if (!file_exists(AUTH_GROUP_FILE)) {
843             trigger_error(sprintf(_("Cannot open AUTH_GROUP_FILE %s"), AUTH_GROUP_FILE),
844                           E_USER_WARNING);
845             return false;
846         }
847         require_once 'lib/pear/File_Passwd.php';
848         $this->_file = new File_Passwd(AUTH_GROUP_FILE,false,AUTH_GROUP_FILE.".lock");
849     }
850
851     /**
852      * Determines if the current user is a member of a group.
853      *
854      * To determine membership in a particular group, this method checks the
855      * superclass instance variable $membership to see if membership has
856      * already been determined.  If not, then the group file is parsed to
857      * determine membership.
858      * @param  string  $group Name of the group to check for membership.
859      * @return boolean True if user is a member, else false.
860      */
861     function isMember($group) {
862         //$request = $this->request;
863         //$username = $this->username;
864         if (isset($this->membership[$group])) {
865             return $this->membership[$group];
866         }
867
868         if (is_array($this->_file->users)) {
869           foreach ($this->_file->users as $g => $u) {
870             $users = explode(' ',$u);
871             if (in_array($this->username,$users)) {
872                 $this->membership[$group] = true;
873                 return true;
874             }
875           }
876         }
877         $this->membership[$group] = false;
878         if ($this->specialGroup($group))
879             return $this->isSpecialMember($group);
880         return false;
881     }
882
883     /**
884      * Determines all of the groups of which the current user is a member.
885      *
886      * then checks each group to see if the current user is a member.
887      * @param  string $group Name of the group to check for membership.
888      * @return array  Array of groups to which the user belongs.
889      */
890     function getAllGroupsIn(){
891         //$username = $this->_getUserName();
892         $membership = array();
893
894         if (is_array($this->_file->users)) {
895           foreach ($this->_file->users as $group => $u) {
896             $users = explode(' ',$u);
897             if (in_array($this->username,$users)) {
898                 $this->membership[$group] = true;
899                 $membership[] = $group;
900             }
901           }
902         }
903
904         $specialgroups = $this->specialGroups();
905         foreach ($specialgroups as $group) {
906             if ($this->isMember($group)) {
907                 $this->membership[$group] = true;
908                 $membership[] = $group;
909             }
910         }
911         return $membership;
912     }
913
914     /**
915      * Determines all of the members of a particular group.
916      *
917      * Return all the current members.
918      * @param  string $group Name of the group to get the full membership list of.
919      * @return array  Array of usernames that have joined the group.
920      */
921     function getMembersOf($group){
922         $members = array();
923         if (!empty($this->_file->users[$group])) {
924             $members = explode(' ',$this->_file->users[$group]);
925         }
926         if ($this->specialGroup($group)) {
927             $members = array_merge($members, $this->getSpecialMembersOf($group));
928         }
929         return $members;
930     }
931 }
932
933 /**
934  * Ldap is configured in index.php
935  *
936  * @author ReiniUrban
937  */
938 class GroupLdap extends WikiGroup {
939
940     /**
941      * Constructor
942      *
943      * @param object $request The global WikiRequest object.
944      */
945     function GroupLdap(){
946         //$this->request = &$GLOBALS['request'];
947         $this->username = $this->_getUserName();
948         $this->membership = array();
949
950         if (!defined("LDAP_AUTH_HOST")) {
951             trigger_error(sprintf(_("%s not defined"), "LDAP_AUTH_HOST"),
952                           E_USER_WARNING);
953             return false;
954         }
955         // We should ignore multithreaded environments, not generally windows.
956         // CGI does work.
957         if (! function_exists('ldap_connect') and (!isWindows() or isCGI())) {
958             // on MacOSX >= 4.3 you'll need PHP_SHLIB_SUFFIX instead.
959             dl("ldap".defined('PHP_SHLIB_SUFFIX') ? PHP_SHLIB_SUFFIX : DLL_EXT);
960             if (! function_exists('ldap_connect')) {
961                 trigger_error(_("No LDAP in this PHP version"), E_USER_WARNING);
962                 return false;
963             }
964         }
965         if (!defined("LDAP_BASE_DN"))
966             define("LDAP_BASE_DN",'');
967         $this->base_dn = LDAP_BASE_DN;
968         // if no users ou (organizational unit) is defined,
969         // then take out the ou= from the base_dn (if exists) and append a default
970         // from users and group
971         if (!LDAP_OU_USERS)
972             if (strstr(LDAP_BASE_DN, "ou="))
973                 $this->base_dn = preg_replace("/(ou=\w+,)?()/","\$2", LDAP_BASE_DN);
974
975         if (!isset($this->user) or !isa($this->user, '_LDAPPassUser'))
976             $this->_user = new _LDAPPassUser('LdapGroupTest'); // to have a valid username
977         else
978             $this->_user =& $this->user;
979     }
980
981     /**
982      * Determines if the current user is a member of a group.
983      * Not ready yet!
984      *
985      * @param  string  $group Name of the group to check for membership.
986      * @return boolean True if user is a member, else false.
987      */
988     function isMember($group) {
989         if (isset($this->membership[$group])) {
990             return $this->membership[$group];
991         }
992         //$request = $this->request;
993         //$username = $this->_getUserName();
994         $this->membership[$group] = in_array($this->username,$this->getMembersOf($group));
995         if ($this->membership[$group])
996             return true;
997         if ($this->specialGroup($group))
998             return $this->isSpecialMember($group);
999     }
1000
1001     /**
1002      * Determines all of the groups of which the current user is a member.
1003      *
1004      * @param  string $group Name of the group to check for membership.
1005      * @return array  Array of groups to which the user belongs.
1006      */
1007     function getAllGroupsIn(){
1008         //$request = &$this->request;
1009         //$username = $this->_getUserName();
1010         $membership = array();
1011
1012         $specialgroups = $this->specialGroups();
1013         foreach ($specialgroups as $group) {
1014             if ($this->isMember($group)) {
1015                 $this->membership[$group] = true;
1016                 $membership[] = $group;
1017             }
1018         }
1019
1020         // must be a valid LDAP server, and username must not contain a wildcard
1021         if ($ldap = $this->_user->_init()) {
1022             $st_search = LDAP_SEARCH_FIELD ? LDAP_SEARCH_FIELD."=".$this->username
1023                                : "uid=".$this->username;
1024             $sr = ldap_search($ldap, (LDAP_OU_USERS ? LDAP_OU_USERS : "ou=Users")
1025                               .($this->base_dn ? ",".$this->base_dn : ''),
1026                               $st_search);
1027             if (!$sr) {
1028          $this->_user->_free();
1029                 return $this->membership;
1030             }
1031             $info = ldap_get_entries($ldap, $sr);
1032             if (empty($info["count"])) {
1033          $this->_user->_free();
1034                 return $this->membership;
1035             }
1036             for ($i = 0; $i < $info["count"]; $i++) {
1037                 if ($info[$i]["gidNumber"]["count"]) {
1038                     $gid = $info[$i]["gidnumber"][0];
1039                     $sr2 = ldap_search($ldap, (LDAP_OU_GROUP ? LDAP_OU_GROUP : "ou=Groups")
1040                                        .($this->base_dn ? ",".$this->base_dn : ''),
1041                                        "gidNumber=$gid");
1042                     if ($sr2) {
1043                         $info2 = ldap_get_entries($ldap, $sr2);
1044                         if (!empty($info2["count"]))
1045                             $membership[] =  $info2[0]["cn"][0];
1046                     }
1047                 }
1048             }
1049         } else {
1050             trigger_error(fmt("Unable to connect to LDAP server %s", LDAP_AUTH_HOST),
1051                           E_USER_WARNING);
1052         }
1053         $this->_user->_free();
1054         //ldap_close($ldap);
1055         $this->membership = $membership;
1056         return $membership;
1057     }
1058
1059     /**
1060      * Determines all of the members of a particular group.
1061      *
1062      * Return all the members of the given group. LDAP just returns the gid of each user
1063      * @param  string $group Name of the group to get the full membership list of.
1064      * @return array  Array of usernames that have joined the group.
1065      */
1066     function getMembersOf($group){
1067         $members = array();
1068         if ($ldap = $this->_user->_init()) {
1069             $base_dn = (LDAP_OU_GROUP ? LDAP_OU_GROUP : "ou=Groups")
1070                 .($this->base_dn ? ",".$this->base_dn : '');
1071             $sr = ldap_search($ldap, $base_dn, "cn=$group");
1072             if ($sr)
1073                 $info = ldap_get_entries($ldap, $sr);
1074             else {
1075                 $info = array('count' => 0);
1076                 trigger_error("LDAP_SEARCH: base=\"$base_dn\" \"(cn=$group)\" failed", E_USER_NOTICE);
1077             }
1078             $base_dn = (LDAP_OU_USERS ? LDAP_OU_USERS : "ou=Users")
1079                 .($this->base_dn ? ",".$this->base_dn : '');
1080             for ($i = 0; $i < $info["count"]; $i++) {
1081                 $gid = $info[$i]["gidNumber"][0];
1082                 //uid=* would be better probably
1083                 $sr2 = ldap_search($ldap, $base_dn, "gidNumber=$gid");
1084                 if ($sr2) {
1085                     $info2 = ldap_get_entries($ldap, $sr2);
1086                     for ($j = 0; $j < $info2["count"]; $j++) {
1087                         $members[] = $info2[$j]["cn"][0];
1088                     }
1089                 } else {
1090                     trigger_error("LDAP_SEARCH: base=\"$base_dn\" \"(gidNumber=$gid)\" failed", E_USER_NOTICE);
1091                 }
1092             }
1093         }
1094         $this->_user->_free();
1095         //ldap_close($ldap);
1096
1097         if ($this->specialGroup($group)) {
1098             $members = array_merge($members, $this->getSpecialMembersOf($group));
1099         }
1100         return $members;
1101     }
1102 }
1103
1104 // Local Variables:
1105 // mode: php
1106 // tab-width: 8
1107 // c-basic-offset: 4
1108 // c-hanging-comment-ender-p: nil
1109 // indent-tabs-mode: nil
1110 // End: