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