]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiGroup.php
fixed explodePageList: wrong sortby argument order in UnfoldSubpages
[SourceForge/phpwiki.git] / lib / WikiGroup.php
1 <?php
2 rcs_id('$Id: WikiGroup.php,v 1.22 2004-03-12 15:48:07 rurban Exp $');
3 /*
4  Copyright 2003, 2004 $ThePhpWikiProgrammingTeam
5
6  This file is part of PhpWiki.
7
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.
12
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.
17
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
21  */
22
23 // For now we provide no default membership method. This might change.
24 // (!defined('GROUP_METHOD')) define('GROUP_METHOD', "WIKIPAGE");
25
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);
30     
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_HASHOMEPAGE',     _("HasHomePage"));
36 define('GROUP_SIGNED',          _("Signed Users"));
37 define('GROUP_AUTHENTICATED',   _("Authenticated Users"));
38 define('GROUP_ADMIN',           _("Administrators"));
39 define('GROUP_OWNER',           _("Owner"));
40 define('GROUP_CREATOR',         _("Creator"));
41
42 /**
43  * WikiGroup is an abstract class to provide the base functions for determining
44  * group membership.
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($request);
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     /** The global WikiRequest object */
62     var $request;
63     /** Array of groups $username is confirmed to belong to */
64     var $membership;
65     
66     /**
67      * Initializes a WikiGroup object which should never happen.  Use:
68      * $group = &WikiGroup::getGroup($request);
69      * @param object $request The global WikiRequest object -- ignored.
70      */ 
71     function WikiGroup(&$request){    
72         $this->request = $request;
73     }
74
75     /**
76      * Gets the current username and erases $this->membership if is different than
77      * the stored $this->username
78      * @return string Current username.
79      */ 
80     function _getUserName(){
81         $request = &$this->request;
82         $user = $request->getUser();
83         $username = $user->getID();
84         if ($username != $this->username) {
85             $this->membership = array();
86             $this->username = $username;
87         }
88         return $username;
89     }
90     
91     /**
92      * Static method to return the WikiGroup subclass used in this wiki.  Controlled
93      * by the constant GROUP_METHOD.
94      * @param object $request The global WikiRequest object.
95      * @return object Subclass of WikiGroup selected via GROUP_METHOD.
96      */ 
97     function getGroup($request){
98         switch (GROUP_METHOD){
99             case "NONE": 
100                 return new GroupNone($request);
101                 break;
102             case "WIKIPAGE":
103                 return new GroupWikiPage($request);
104                 break;
105             case "DB":
106                 if ($GLOBALS['DBParams']['dbtype'] == 'ADODB') {
107                     return new GroupDB_ADODB($request);
108                 } elseif ($GLOBALS['DBParams']['dbtype'] == 'SQL') {
109                     return new GroupDb_PearDB($request);
110                 } else {
111                     trigger_error("GroupDb: unsupported dbtype " . $DBParams['dbtype'],
112                                   E_USER_ERROR);
113                 }
114                 break;
115             case "FILE": 
116                 return new GroupFile($request);
117                 break;
118             case "LDAP": 
119                 return new GroupLDAP($request);
120                 break;
121             default:
122                 trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
123                 return new WikiGroup($request);
124         }
125     }
126
127     /* ACL PagePermissions will need those special groups based on the User status only */
128     function specialGroup($group){
129         return in_array($group,$this->specialGroups());
130     }
131
132     function specialGroups(){
133         return array(
134                      GROUP_EVERY,
135                      GROUP_ANONYMOUS,
136                      GROUP_BOGOUSERS,
137                      GROUP_SIGNED,
138                      GROUP_AUTHENTICATED,
139                      GROUP_ADMIN);
140     }
141
142     /**
143      * Determines if the current user is a member of a group.
144      * 
145      * This method is an abstraction.  The group is ignored, an error is sent, and
146      * false (not a member of the group) is returned.
147      * @param string $group Name of the group to check for membership (ignored).
148      * @return boolean True if user is a member, else false (always false).
149      */ 
150     function isMember($group){
151         if (isset($this->membership[$group]))
152             return $this->membership[$group];
153         if ($this->specialGroup($group)) {
154             $request = &$this->request;
155             $user = $request->getUser();
156             switch ($group) {
157             case GROUP_EVERY:           return $this->membership[$group] = true;
158             case GROUP_ANONYMOUS:       return $this->membership[$group] = ! $user->isSignedIn();
159             case GROUP_BOGOUSERS:       return $this->membership[$group] = isa($user,'_BogoUser');
160             case GROUP_SIGNED:          return $this->membership[$group] = $user->isSignedIn();
161             case GROUP_AUTHENTICATED:   return $this->membership[$group] = $user->isAuthenticated();
162             case GROUP_ADMIN:           return $this->membership[$group] = $user->isAdmin();
163             default:
164                 trigger_error(__sprintf("Undefined method %s for special group %s",
165                                         'isMember',$group),
166                               E_USER_WARNING);
167             }
168         } else {
169             trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
170                                     'isMember',GROUP_METHOD),
171                           E_USER_WARNING);
172         }
173         return false;
174     }
175     
176     /**
177      * Determines all of the groups of which the current user is a member.
178      * 
179      * This method is an abstraction.  An error is sent and an empty 
180      * array is returned.
181      * @return array Array of groups to which the user belongs (always empty).
182      */ 
183     function getAllGroupsIn(){
184         trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
185                                 'getAllGroupsIn',GROUP_METHOD),
186                       E_USER_WARNING);
187         return array();
188     }
189
190     function _allUsers() {
191         static $result = array();
192         if (!empty($result))
193                 return $result;
194                 
195         /* WikiPage users: */
196         $dbh = $this->request->getDbh();
197         $page_iter = $dbh->getAllPages();
198         while ($page = $page_iter->next()) {
199             if ($page->isUserPage())
200                 $users[] = $page->_pagename;
201         }
202
203         /* WikiDB users from prefs (not from users): */
204         $dbi = _PassUser::getAuthDbh();
205         if ($dbi and !empty($GLOBALS['DBAuthParams']['pref_select'])) {
206             //get prefs table
207             $sql = preg_replace('/SELECT .+ FROM/i','SELECT userid FROM',$GLOBALS['DBAuthParams']['pref_select']);
208             //don't strip WHERE, only the userid stuff.
209             $sql = preg_replace('/(WHERE.*?)\s+\w+\s*=\s*"\$userid"/i','\\1 AND 1',$sql);
210             $sql = str_replace('WHERE AND 1','',$sql);
211             if ($GLOBALS['DBParams']['dbtype'] == 'ADODB') {
212                 $db_result = $dbi->Execute($sql);
213                 foreach ($db_result->GetArray() as $u) {
214                    $users = array_merge($users,array_values($u));
215                 }
216             } elseif ($GLOBALS['DBParams']['dbtype'] == 'SQL') {
217                 $users = array_merge($users,$dbi->getCol($sql));
218             }
219         }
220
221         /* WikiDB users from users: */
222         // Fixme: don't strip WHERE, only the userid stuff.
223         if ($dbi and !empty($GLOBALS['DBAuthParams']['auth_user_exists'])) {
224             //don't strip WHERE, only the userid stuff.
225             $sql = preg_replace('/(WHERE.*?)\s+\w+\s*=\s*"\$userid"/i','\\1 AND 1',$GLOBALS['DBAuthParams']['auth_user_exists']);
226             $sql = str_replace('WHERE AND 1','',$sql);
227             if ($GLOBALS['DBParams']['dbtype'] == 'ADODB') {
228                 $db_result = $dbi->Execute($sql);
229                 foreach ($db_result->GetArray() as $u) {
230                    $users = array_merge($users,array_values($u));
231                 }
232             } elseif ($GLOBALS['DBParams']['dbtype'] == 'SQL') {
233                 $users = array_merge($users,$dbi->getCol($sql));
234             }
235         }
236
237         // remove empty and duplicate users
238         $result = array();
239         foreach ($users as $u) {
240             if (empty($u) or in_array($u,$result)) continue;
241             $result[] = $u;
242         }
243         return $result;
244     }
245
246     /**
247      * Determines all of the members of a particular group.
248      * 
249      * This method is an abstraction.  The group is ignored, an error is sent, 
250      * and an empty array is returned
251      * @param string $group Name of the group to get the full membership list of.
252      * @return array Array of usernames that have joined the group (always empty).
253      */ 
254     function getMembersOf($group){
255         if ($this->specialGroup($group)) {
256             //$request = &$this->request;
257             $all = $this->_allUsers();
258             $users = array();
259             switch ($group) {
260             case GROUP_EVERY:           
261                 return $all;
262             case GROUP_ANONYMOUS:       
263                 return $users;
264             case GROUP_BOGOUSERS:       
265                 foreach ($all as $u) {
266                     if (isWikiWord($user)) $users[] = $u;
267                 }
268                 return $users;
269             case GROUP_SIGNED:          
270                 foreach ($all as $u) {
271                     $user = WikiUser($u);
272                     if ($user->isSignedIn()) $users[] = $u;
273                 }
274                 return $users;
275             case GROUP_AUTHENTICATED:
276                 foreach ($all as $u) {
277                     $user = WikiUser($u);
278                     if ($user->isAuthenticated()) $users[] = $u;
279                 }
280                 return $users;
281             case GROUP_ADMIN:           
282                 foreach ($all as $u) {
283                     $user = WikiUser($u);
284                     if ($user->isAdmin()) $users[] = $u;
285                 }
286                 return $users;
287             default:
288                 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
289                                         'getMembersOf',GROUP_METHOD),
290                               E_USER_WARNING);
291             }
292         }
293         trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
294                                 'getMembersOf',GROUP_METHOD),
295                       E_USER_WARNING);
296         return array();
297     }
298
299     /**
300      * Add the current or specified user to a group.
301      * 
302      * This method is an abstraction.  The group and user are ignored, an error 
303      * is sent, and false (not added) is always returned.
304      * @param string $group User added to this group.
305      * @param string $user Username to add to the group (default = current user).
306      * @return bool On true user was added, false if not.
307      */ 
308     function setMemberOf($group, $user = false){
309         trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
310                                 'setMemberOf',GROUP_METHOD),
311                       E_USER_WARNING);
312         return false;
313     }
314     
315     /**
316      * Remove the current or specified user to a group.
317      * 
318      * This method is an abstraction.  The group and user are ignored, and error
319      * is sent, and false (not removed) is always returned.
320      * @param string $group User removed from this group.
321      * @param string $user Username to remove from the group (default = current user).
322      * @return bool On true user was removed, false if not.
323      */ 
324     function removeMemberOf($group, $user = false){
325         trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
326                                 'removeMemberOf',GROUP_METHOD),
327                       E_USER_WARNING);
328         return false;
329     }
330 }
331
332 /**
333  * GroupNone disables all Group funtionality
334  * 
335  * All of the GroupNone functions return false or empty values to indicate failure or 
336  * no results.  Use GroupNone if group controls are not desired.
337  * @author Joby Walker <zorloc@imperium.org>
338  */ 
339 class GroupNone extends WikiGroup{
340
341     /**
342      * Constructor
343      * 
344      * Ignores the parameter provided.
345      * @param object $request The global WikiRequest object - ignored.
346      */ 
347     function GroupNone(&$request){
348         $this->request = &$request;
349         return;
350     }    
351
352     /**
353      * Determines if the current user is a member of a group.
354      * 
355      * The group is ignored and false (not a member of the group) is returned.
356      * @param string $group Name of the group to check for membership (ignored).
357      * @return boolean True if user is a member, else false (always false).
358      */ 
359     function isMember($group){
360         if ($this->specialGroup($group)) {
361             return WikiGroup::isMember($group);
362         } else {
363             return false;
364         }
365     }
366     
367     /**
368      * Determines all of the groups of which the current user is a member.
369      * 
370      * The group is ignored and an empty array (a member of no groups) is returned.
371      * @param string $group Name of the group to check for membership (ignored).
372      * @return array Array of groups to which the user belongs (always empty).
373      */ 
374     function getAllGroupsIn(){
375         return array();
376     }
377
378     /**
379      * Determines all of the members of a particular group.
380      * 
381      * The group is ignored and an empty array (a member of no groups) is returned.
382      * @param string $group Name of the group to check for membership (ignored).
383      * @return array Array of groups user belongs to (always empty).
384      */ 
385     function getMembersOf($group){
386         return array();
387     }
388
389 }
390
391 /**
392  * GroupWikiPage provides group functionality via pages within the Wiki.
393  * 
394  * GroupWikiPage is the Wiki way of managing a group.  Every group will have 
395  * a page. To modify the membership of the group, one only needs to edit the 
396  * membership list on the page.
397  * @author Joby Walker <zorloc@imperium.org>
398  */ 
399 class GroupWikiPage extends WikiGroup{
400     
401     /**
402      * Constructor
403      * 
404      * Initializes the three superclass instance variables
405      * @param object $request The global WikiRequest object.
406      */ 
407     function GroupWikiPage(&$request){
408         $this->request = &$request;
409         $this->username = $this->_getUserName();
410         //$this->username = null;
411         $this->membership = array();
412     }
413
414     /**
415      * Determines if the current user is a member of a group.
416      * 
417      * To determine membership in a particular group, this method checks the 
418      * superclass instance variable $membership to see if membership has 
419      * already been determined.  If not, then the group page is parsed to 
420      * determine membership.
421      * @param string $group Name of the group to check for membership.
422      * @return boolean True if user is a member, else false.
423      */ 
424     function isMember($group){
425         if ($this->specialGroup($group))
426             return WikiGroup::isMember($group);
427
428         $request = $this->request;
429         //$username = $this->_getUserName();
430         if (isset($this->membership[$group])) {
431             return $this->membership[$group];
432         }
433         $group_page = $request->getPage($group);
434         if ($this->_inGroupPage($group_page)) {
435             $this->membership[$group] = true;
436             return true;
437         }
438         $this->membership[$group] = false;
439         return false;
440     }
441     
442     /**
443     * Private method to take a WikiDB_Page and parse to determine if the
444     * current_user is a member of the group.
445     * @param object $group_page WikiDB_Page object for the group's page
446     * @return boolean True if user is a member, else false.
447     * @access private
448     */
449     function _inGroupPage($group_page){
450         $group_revision = $group_page->getCurrentRevision();
451         if ($group_revision->hasDefaultContents()) {
452             $group = $group_page->getName();
453             trigger_error(sprintf(_("Group %s does not exist"),$group), E_USER_WARNING);
454             return false;
455         }
456         $contents = $group_revision->getContent();
457         $match = '/^\s*[\*\#]+\s*' . $this->username . '\s*$/';
458         foreach ($contents as $line){
459             if (preg_match($match, $line)) {
460                 return true;
461             }
462         }
463         return false;
464     }
465     
466     /**
467      * Determines all of the groups of which the current user is a member.
468      * 
469      * Checks the root Group page ('CategoryGroup') for the list of all groups, 
470      * then checks each group to see if the current user is a member.
471      * @param string $group Name of the group to check for membership.
472      * @return array Array of groups to which the user belongs.
473      */ 
474     function getAllGroupsIn(){
475         $request = &$this->request;
476         //$username = $this->_getUserName();
477         $membership = array();
478
479         $specialgroups = $this->specialGroups();
480         foreach ($specialgroups as $group) {
481             $this->membership[$group] = $this->isMember($group);
482         }
483
484         $dbh = &$request->getDbh();
485         $master_page = $request->getPage(_("CategoryGroup"));
486         $master_list = $master_page->getLinks(true);
487         while ($group_page = $master_list->next()){
488             $group = $group_page->getName();
489             $this->membership[$group] = $this->_inGroupPage($group_page);
490         }
491         foreach ($this->membership as $g => $bool) {
492             if ($bool) $membership[] = $g;
493         }
494         return $membership;
495     }
496
497     /**
498      * Determines all of the members of a particular group.
499      * 
500      * Checks a group's page to return all the current members.  Currently this
501      * method is disabled and triggers an error and returns an empty array.
502      * @param string $group Name of the group to get the full membership list of.
503      * @return array Array of usernames that have joined the group (always empty).
504      */ 
505     function getMembersOf($group){
506         if ($this->specialGroup($group))
507             return WikiGroup::getMembersOf($group);
508
509         trigger_error("GroupWikiPage::getMembersOf is not yet implimented",
510                       E_USER_WARNING);
511         return array();
512         /*
513         * Waiting for a reliable way to check if a string is a username.
514         $request = $this->request;
515         $user = $this->user;
516         $group_page = $request->getPage($group);
517         $group_revision = $group_page->getCurrentRevision();
518         if ($group_revision->hasDefaultContents()) {
519             trigger_error("Group $group does not exist", E_USER_WARNING);
520             return false;
521         }
522         $contents = $group_revision->getContent();
523         $match = '/^(\s*[\*\#]+\s*)(\w+)(\s*)$/';
524         $members = array();
525         foreach($contents as $line){
526             $matches = array();
527             if(preg_match($match, $line, $matches)){
528                 $members[] = $matches[2];
529             }
530         }
531         return $members;
532         */
533     }
534 }
535
536 /**
537  * GroupDb is configured by $DbAuthParams[] statements
538  * 
539  * Fixme: adodb
540  * @author ReiniUrban
541  */ 
542 class GroupDb extends WikiGroup {
543     
544     var $_is_member, $_group_members, $_user_groups;
545
546     /**
547      * Constructor
548      * 
549      * @param object $request The global WikiRequest object. ignored
550      */ 
551     function GroupDb(&$request){
552         global $DBAuthParams, $DBParams;
553         $this->request = &$request;
554         $this->username = $this->_getUserName();
555         $this->membership = array();
556
557         if (empty($DBAuthParams['group_members']) or 
558             empty($DBAuthParams['user_groups']) or
559             empty($DBAuthParams['is_member'])) {
560             trigger_error(_("No or not enough GROUP_DB SQL statements defined"), E_USER_WARNING);
561             return new GroupNone(&$request);
562         }
563         $this->_is_member = str_replace(array('"$userid"','"$groupname"'),
564                                         array('%s','%s'),
565                                         $DBAuthParams['is_member']);
566         $this->_group_members = str_replace('"$groupname"',
567                                             '%s',
568                                             $DBAuthParams['group_members']);
569         $this->_user_groups = str_replace('"$userid"',
570                                           '%s',
571                                           $DBAuthParams['user_groups']);
572         $this->dbh = _PassUser::getAuthDbh();
573     }
574 }
575
576 /**
577  * PearDB methods
578  * 
579  * @author ReiniUrban
580  */ 
581 class GroupDb_PearDB extends GroupDb {
582     
583     /**
584      * Determines if the current user is a member of a database group.
585      * 
586      * @param string $group Name of the group to check for membership.
587      * @return boolean True if user is a member, else false.
588      */ 
589     function isMember($group) {
590         if ($this->specialGroup($group))
591             return WikiGroup::isMember($group);
592
593         if (isset($this->membership[$group])) {
594             return $this->membership[$group];
595         }
596         $dbh = & $this->dbh;
597         $db_result = $dbh->query(sprintf($this->_is_member,$dbh->quote($this->username),$dbh->quote($group)));
598         if ($db_result->numRows() > 0) {
599             $this->membership[$group] = true;
600             return true;
601         }
602         $this->membership[$group] = false;
603         return false;
604     }
605     
606     /**
607      * Determines all of the groups of which the current user is a member.
608      * 
609      * then checks each group to see if the current user is a member.
610      * @param string $group Name of the group to check for membership.
611      * @return array Array of groups to which the user belongs.
612      */ 
613     function getAllGroupsIn(){
614
615         $membership = array();
616         $specialgroups = $this->specialGroups();
617         foreach ($specialgroups as $group) {
618             if ($this->isMember($group)) {
619                 $membership[] = $group;
620             }
621         }
622         $dbh = & $this->dbh;
623         $db_result = $dbh->query(sprintf($this->_user_groups,$dbh->quote($this->username)));
624         if ($db_result->numRows() > 0) {
625             while (list($group) = $db_result->fetchRow()) {
626                 $membership[] = $group;
627                 $this->membership[$group] = true;
628             }
629         }
630         return $membership;
631     }
632
633     /**
634      * Determines all of the members of a particular group.
635      * 
636      * Checks a group's page to return all the current members.  Currently this
637      * method is disabled and triggers an error and returns an empty array.
638      * @param string $group Name of the group to get the full membership list of.
639      * @return array Array of usernames that have joined the group.
640      */ 
641     function getMembersOf($group){
642         if ($this->specialGroup($group))
643             return WikiGroup::getMembersOf($group);
644
645         $members = array();
646         $dbh = & $this->dbh;
647         $db_result = $dbh->query(sprintf($this->_group_members,$dbh->quote($group)));
648         if ($db_result->numRows() > 0) {
649             while (list($userid) = $db_result->fetchRow()) {
650                 $members[] = $userid;
651             }
652         }
653         return $members;
654     }
655 }
656
657 /**
658  * ADODB methods
659  * 
660  * @author ReiniUrban
661  */ 
662 class GroupDb_ADODB extends GroupDb {
663
664     /**
665      * Determines if the current user is a member of a database group.
666      * 
667      * @param string $group Name of the group to check for membership.
668      * @return boolean True if user is a member, else false.
669      */ 
670     function isMember($group) {
671         if ($this->specialGroup($group))
672             return WikiGroup::isMember($group);
673
674         if (isset($this->membership[$group])) {
675             return $this->membership[$group];
676         }
677         $dbh = & $this->dbh;
678         $rs = $dbh->Execute(sprintf($this->_is_member,$dbh->qstr($this->username),$dbh->qstr($group)));
679         if ($rs->EOF) {
680             $rs->Close();
681         } else {
682             if ($rs->numRows() > 0) {
683                 $this->membership[$group] = true;
684                 $rs->Close();
685                 return true;
686             }
687         }
688         $this->membership[$group] = false;
689         return false;
690     }
691     
692     /**
693      * Determines all of the groups of which the current user is a member.
694      * then checks each group to see if the current user is a member.
695      *
696      * @param string $group Name of the group to check for membership.
697      * @return array Array of groups to which the user belongs.
698      */ 
699     function getAllGroupsIn(){
700
701         $membership = array();
702         $specialgroups = $this->specialGroups();
703         foreach ($specialgroups as $group) {
704             if ($this->isMember($group)) {
705                 $membership[] = $group;
706             }
707         }
708         $dbh = & $this->dbh;
709         $rs = $dbh->Execute(sprintf($this->_user_groups,$dbh->qstr($this->username)));
710         if (!$rs->EOF and $rs->numRows() > 0) {
711             while (!$rs->EOF) {
712                 $group = reset($rs->fields);
713                 $membership[] = $group;
714                 $this->membership[$group] = true;
715                 $rs->MoveNext();
716             }
717         }
718         $rs->Close();
719         return $membership;
720     }
721
722     /**
723      * Determines all of the members of a particular group.
724      * 
725      * @param string $group Name of the group to get the full membership list of.
726      * @return array Array of usernames that have joined the group.
727      */ 
728     function getMembersOf($group){
729         if ($this->specialGroup($group))
730             return WikiGroup::getMembersOf($group);
731             
732         $members = array();
733         $dbh = & $this->dbh;
734         $rs = $dbh->Execute(sprintf($this->_group_members,$dbh->qstr($group)));
735         if (!$rs->EOF and $rs->numRows() > 0) {
736             while (!$rs->EOF) {
737                 $members[] = reset($rs->fields);
738                 $rs->MoveNext();
739             }
740         }
741         $rs->Close();
742         return $members;
743     }
744 }
745
746 /**
747  * GroupFile is configured by AUTH_GROUP_FILE
748  * groupname: user1 user2 ...
749  * 
750  * @author ReiniUrban
751  */ 
752 class GroupFile extends WikiGroup {
753     
754     /**
755      * Constructor
756      * 
757      * @param object $request The global WikiRequest object.
758      */ 
759     function GroupFile(&$request){
760         $this->request = &$request;
761         $this->username = $this->_getUserName();
762         //$this->username = null;
763         $this->membership = array();
764
765         if (!defined('AUTH_GROUP_FILE')) {
766             trigger_error(_("AUTH_GROUP_FILE not defined"), E_USER_WARNING);
767             return false;
768         }
769         if (!file_exists(AUTH_GROUP_FILE)) {
770             trigger_error(sprintf(_("Cannot open AUTH_GROUP_FILE %s"), AUTH_GROUP_FILE), E_USER_WARNING);
771             return false;
772         }
773         require_once('lib/pear/File_Passwd.php');
774         $this->_file = new File_Passwd(AUTH_GROUP_FILE,true);
775     }
776
777     /**
778      * Determines if the current user is a member of a group.
779      * 
780      * To determine membership in a particular group, this method checks the 
781      * superclass instance variable $membership to see if membership has 
782      * already been determined.  If not, then the group file is parsed to 
783      * determine membership.
784      * @param string $group Name of the group to check for membership.
785      * @return boolean True if user is a member, else false.
786      */ 
787     function isMember($group) {
788         if ($this->specialGroup($group))
789             return WikiGroup::isMember($group);
790
791         //$request = $this->request;
792         //$username = $this->username;
793         if (isset($this->membership[$group])) {
794             return $this->membership[$group];
795         }
796
797         if (is_array($this->_file->users)) {
798           foreach ($this->_file->users as $g => $u) {
799             $users = explode(' ',$u);
800             if (in_array($this->username,$users)) {
801                 $this->membership[$group] = true;
802                 return true;
803             }
804           }
805         }
806         $this->membership[$group] = false;
807         return false;
808     }
809     
810     /**
811      * Determines all of the groups of which the current user is a member.
812      * 
813      * then checks each group to see if the current user is a member.
814      * @param string $group Name of the group to check for membership.
815      * @return array Array of groups to which the user belongs.
816      */ 
817     function getAllGroupsIn(){
818         //$username = $this->_getUserName();
819         $membership = array();
820
821         $specialgroups = $this->specialGroups();
822         foreach ($specialgroups as $group) {
823             if ($this->isMember($group)) {
824                 $this->membership[$group] = true;
825                 $membership[] = $group;
826             }
827         }
828         if (is_array($this->_file->users)) {
829           foreach ($this->_file->users as $group => $u) {
830             $users = explode(' ',$u);
831             if (in_array($this->username,$users)) {
832                 $this->membership[$group] = true;
833                 $membership[] = $group;
834             }
835           }
836         }
837         return $membership;
838     }
839
840     /**
841      * Determines all of the members of a particular group.
842      * 
843      * Return all the current members.
844      * @param string $group Name of the group to get the full membership list of.
845      * @return array Array of usernames that have joined the group.
846      */ 
847     function getMembersOf($group){
848         if ($this->specialGroup($group)) {
849             return WikiGroup::getMembersOf($group);
850         } else {
851             if (!empty($this->_file->users[$group])) {
852                 return explode(' ',$this->_file->users[$group]);
853             }
854             return array();
855         }
856     }
857 }
858
859 /**
860  * Ldap is configured in index.php
861  * 
862  * @author ReiniUrban
863  */ 
864 class GroupLdap extends WikiGroup {
865     
866     /**
867      * Constructor
868      * 
869      * @param object $request The global WikiRequest object.
870      */ 
871     function GroupLdap(&$request){
872         $this->request = &$request;
873         $this->username = $this->_getUserName();
874         $this->membership = array();
875
876         if (!defined("LDAP_AUTH_HOST")) {
877             trigger_error(_("LDAP_AUTH_HOST not defined"), E_USER_WARNING);
878             return false;
879         }
880         if (! function_exists('ldap_connect')) {
881             dl("ldap".DLL_EXT);
882             if (! function_exists('ldap_connect')) {
883                 trigger_error(_("No LDAP in this PHP version"), E_USER_WARNING);
884                 return false;
885             }
886         }
887         if (!defined("LDAP_BASE_DN"))
888             define("LDAP_BASE_DN",'');
889         $this->base_dn = LDAP_BASE_DN;
890         if (strstr("ou=",LDAP_BASE_DN))
891             $this->base_dn =  preg_replace("/(ou=\w+,)?()/","\$2",LDAP_BASE_DN);
892     }
893
894     /**
895      * Determines if the current user is a member of a group.
896      * Not ready yet!
897      * 
898      * @param string $group Name of the group to check for membership.
899      * @return boolean True if user is a member, else false.
900      */ 
901     function isMember($group) {
902         if ($this->specialGroup($group))
903             return WikiGroup::isMember($group);
904
905         if (isset($this->membership[$group])) {
906             return $this->membership[$group];
907         }
908         //$request = $this->request;
909         //$username = $this->_getUserName();
910
911         $this->membership[$group] = in_array($this->username,$this->getMembersOf($group));
912         return $this->membership[$group];
913     }
914     
915     /**
916      * Determines all of the groups of which the current user is a member.
917      *
918      * @param string $group Name of the group to check for membership.
919      * @return array Array of groups to which the user belongs.
920      */ 
921     function getAllGroupsIn(){
922         //$request = &$this->request;
923         //$username = $this->_getUserName();
924         $membership = array();
925
926         $specialgroups = $this->specialGroups();
927         foreach ($specialgroups as $group) {
928             if ($this->isMember($group)) {
929                 $this->membership[$group] = true;
930                 $membership[] = $group;
931             }
932         }
933         if ($ldap = ldap_connect(LDAP_AUTH_HOST)) { // must be a valid LDAP server!
934             if (defined('LDAP_AUTH_USER'))
935                 if (defined('LDAP_AUTH_PASSWORD'))
936                     // Windows Active Directory Server is strict
937                     $r = @ldap_bind($ldap,LDAP_AUTH_USER,LDAP_AUTH_PASSWORD); 
938                 else
939                     $r = @ldap_bind($ldap,LDAP_AUTH_USER); 
940             else
941                 $r = @ldap_bind($ldap); // this is an anonymous bind
942             if (!empty($LDAP_SET_OPTION)) {
943                 foreach ($LDAP_SET_OPTION as $key => $value) {
944                     ldap_set_option($ldap,$key,$value);
945                 }
946             }
947             $st_search = defined('LDAP_SEARCH_FIELD') 
948                 ? LDAP_SEARCH_FIELD."=".$this->username
949                 : "uid=".$this->username;
950             $sr = ldap_search($ldap, "ou=Users,".$this->base_dn,$st_search);
951             $info = ldap_get_entries($ldap, $sr);
952             for ($i = 0; $i < $info["count"]; $i++) {
953                 if ($info[$i]["gidnumber"]["count"]) {
954                   $gid = $info[$i]["gidnumber"][0];
955                   $sr2 = ldap_search($ldap, "ou=Groups,".$this->base_dn,"gidNumber=$gid");
956                   $info2 = ldap_get_entries($ldap, $sr2);
957                   if ($info2["count"])
958                     $membership[] =  $info2[0]["cn"][0];
959                 }
960             }
961         } else {
962             trigger_error(fmt("Unable to connect to LDAP server %s", LDAP_AUTH_HOST), 
963                           E_USER_WARNING);
964         }
965         ldap_close($ldap);
966         $this->membership = $membership;
967         return $membership;
968     }
969
970     /**
971      * Determines all of the members of a particular group.
972      * 
973      * Return all the members of the given group. LDAP just returns the gid of each user
974      * @param string $group Name of the group to get the full membership list of.
975      * @return array Array of usernames that have joined the group.
976      */ 
977     function getMembersOf($group){
978         if ($this->specialGroup($group))
979             return WikiGroup::getMembersOf($group);
980
981         $members = array();
982         if ($ldap = ldap_connect(LDAP_AUTH_HOST)) { // must be a valid LDAP server!
983             $r = @ldap_bind($ldap);                 // this is an anonymous bind
984             $sr = ldap_search($ldap, "ou=Groups,".$this->base_dn,"cn=$group");
985             $info = ldap_get_entries($ldap, $sr);
986             for ($i = 0; $i < $info["count"]; $i++) {
987                 $gid = $info[$i]["gidnumber"][0];
988                 $sr2 = ldap_search($ldap, "ou=Users,".$this->base_dn,"gidNumber=$gid");
989                 $info2 = ldap_get_entries($ldap, $sr2);
990                 for ($j = 0; $j < $info2["count"]; $j++) {
991                     $members[] = $info2[$j]["cn"][0];
992                 }
993             }
994         }
995         ldap_close($ldap);
996         return $members;
997     }
998 }
999
1000 // $Log: not supported by cvs2svn $
1001 // Revision 1.21  2004/03/12 11:18:24  rurban
1002 // fixed ->membership chache
1003 //
1004 // Revision 1.20  2004/03/12 10:47:30  rurban
1005 // fixed GroupDB for ADODB
1006 //
1007 // Revision 1.19  2004/03/11 16:27:30  rurban
1008 // fixed GroupFile::getMembersOf for special groups
1009 // added authenticated bind for GroupLdap (Windows AD) as in WikiUserNew
1010 //
1011 // Revision 1.18  2004/03/11 13:30:47  rurban
1012 // fixed File Auth for user and group
1013 // missing only getMembersOf(Authenticated Users),getMembersOf(Every),getMembersOf(Signed Users)
1014 //
1015 // Revision 1.17  2004/03/10 15:38:48  rurban
1016 // store current user->page and ->action in session for WhoIsOnline
1017 // better WhoIsOnline icon
1018 // fixed WhoIsOnline warnings
1019 //
1020 // Revision 1.15  2004/03/09 12:11:57  rurban
1021 // prevent from undefined DBAuthParams warning
1022 //
1023 // Revision 1.14  2004/03/08 19:30:01  rurban
1024 // fixed Theme->getButtonURL
1025 // AllUsers uses now WikiGroup (also DB User and DB Pref users)
1026 // PageList fix for empty pagenames
1027 //
1028 // Revision 1.13  2004/03/08 18:17:09  rurban
1029 // added more WikiGroup::getMembersOf methods, esp. for special groups
1030 // fixed $LDAP_SET_OPTIONS
1031 // fixed _AuthInfo group methods
1032 //
1033 // Revision 1.12  2004/02/23 21:30:25  rurban
1034 // more PagePerm stuff: (working against 1.4.0)
1035 //   ACL editing and simplification of ACL's to simple rwx------ string
1036 //   not yet working.
1037 //
1038 // Revision 1.11  2004/02/07 10:41:25  rurban
1039 // fixed auth from session (still double code but works)
1040 // fixed GroupDB
1041 // fixed DbPassUser upgrade and policy=old
1042 // added GroupLdap
1043 //
1044 // Revision 1.10  2004/02/03 09:45:39  rurban
1045 // LDAP cleanup, start of new Pref classes
1046 //
1047 // Revision 1.9  2004/02/01 09:14:11  rurban
1048 // Started with Group_Ldap (not yet ready)
1049 // added new _AuthInfo plugin to help in auth problems (warning: may display passwords)
1050 // fixed some configurator vars
1051 // renamed LDAP_AUTH_SEARCH to LDAP_BASE_DN
1052 // changed PHPWIKI_VERSION from 1.3.8a to 1.3.8pre
1053 // USE_DB_SESSION defaults to true on SQL
1054 // changed GROUP_METHOD definition to string, not constants
1055 // changed sample user DBAuthParams from UPDATE to REPLACE to be able to
1056 //   create users. (Not to be used with external databases generally, but
1057 //   with the default internal user table)
1058 //
1059 // fixed the IndexAsConfigProblem logic. this was flawed:
1060 //   scripts which are the same virtual path defined their own lib/main call
1061 //   (hmm, have to test this better, phpwiki.sf.net/demo works again)
1062 //
1063 // Revision 1.8  2004/01/27 23:23:39  rurban
1064 // renamed ->Username => _userid for consistency
1065 // renamed mayCheckPassword => mayCheckPass
1066 // fixed recursion problem in WikiUserNew
1067 // fixed bogo login (but not quite 100% ready yet, password storage)
1068 //
1069 // Revision 1.7  2004/01/26 16:52:40  rurban
1070 // added GroupDB and GroupFile classes
1071 //
1072 // Revision 1.6  2003/12/07 19:29:11  carstenklapp
1073 // Code Housecleaning: fixed syntax errors. (php -l *.php)
1074 //
1075 // Revision 1.5  2003/02/22 20:49:55  dairiki
1076 // Fixes for "Call-time pass by reference has been deprecated" errors.
1077 //
1078 // Revision 1.4  2003/01/21 04:02:39  zorloc
1079 // Added Log entry and page footer.
1080 //
1081
1082 // Local Variables:
1083 // mode: php
1084 // tab-width: 8
1085 // c-basic-offset: 4
1086 // c-hanging-comment-ender-p: nil
1087 // indent-tabs-mode: nil
1088 // End:
1089 ?>