2 rcs_id('$Id: WikiUserNew.php,v 1.2 2003-12-03 21:45:48 carstenklapp Exp $');
4 // This is a complete rewrite of the old WikiUser code but it is not
5 // implemented yet. Much of the existing UserPreferences class should
6 // work fine with this but a few other parts of PhpWiki need to be
7 // refitted: main.php, config.php, index.php. --Carsten
10 // Returns a user object, which contains the user's preferences.
12 // Given no name, returns an _AnonUser (anonymous user) object, who
13 // may or may not have a cookie. Given a user name, returns a
14 // _BogoUser object, who may or may not have a cookie and/or
15 // NamesakePage, a _PassUser object or an _AdminUser object.
17 // Takes care of passwords, all preference loading/storing in the
18 // user's page and any cookies. main.php will query the user object to
19 // verify the password as appropriate.
22 define('WIKIAUTH_ANON', 0); // Not signed in.
23 define('WIKIAUTH_BOGO', 1); // Any valid WikiWord is enough.
24 define('WIKIAUTH_USER', 2); // Bogo user with a password.
25 define('WIKIAUTH_ADMIN', 10); // UserName == ADMIN_USER.
26 define('WIKIAUTH_FORBIDDEN', -1); // Completely not allowed.
28 if (!defined('COOKIE_EXPIRATION_DAYS')) define('COOKIE_EXPIRATION_DAYS', 365);
29 if (!defined('COOKIE_DOMAIN')) define('COOKIE_DOMAIN', '/');
31 if (!defined('EDITWIDTH_MIN_COLS')) define('EDITWIDTH_MIN_COLS', 30);
32 if (!defined('EDITWIDTH_MAX_COLS')) define('EDITWIDTH_MAX_COLS', 150);
33 if (!defined('EDITWIDTH_DEFAULT_COLS')) define('EDITWIDTH_DEFAULT_COLS', 80);
35 if (!defined('EDITHEIGHT_MIN_ROWS')) define('EDITHEIGHT_MIN_ROWS', 5);
36 if (!defined('EDITHEIGHT_MAX_ROWS')) define('EDITHEIGHT_MAX_ROWS', 80);
37 if (!defined('EDITHEIGHT_DEFAULT_ROWS')) define('EDITHEIGHT_DEFAULT_ROWS', 22);
39 define('TIMEOFFSET_MIN_HOURS', -26);
40 define('TIMEOFFSET_MAX_HOURS', 26);
41 if (!defined('TIMEOFFSET_DEFAULT_HOURS')) define('TIMEOFFSET_DEFAULT_HOURS', 0);
44 function WikiUser ($UserName = '') {
45 //TODO: check sessionvar for username & save username into sessionvar
46 //TODO: how to implement PassUser?
49 return new _AdminUser($UserName);
52 return new _BogoUser($UserName);
55 // check for autologin pref in cookie and upgrade user object
56 $_AnonUser = new _AnonUser();
57 if ($UserName = $_AnonUser->UserName && $_AnonUser->_prefs->get('autologin')) {
58 if ($UserName == ADMIN_USER)
59 return new _AdminUser($UserName);
61 return new _BogoUser($UserName);
66 // For the future... think about...
67 // if (isa($user, '_AdminUser'))
68 // if (isa($user, '_DeactivatedUser'))
72 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
74 // Base _WikiUser class.
77 var $_level = WIKIAUTH_FORBIDDEN;
79 var _HomePagehandle = false;
84 function _WikiUser($UserName = '') {
86 $this->UserName = $UserName;
87 $this->_HomePagehandle = $this->hasHomePage();
89 $this->loadPreferences();
91 // returns page_handle to user's home page or false if none
92 function hasHomePage() {
93 if ($this->UserName) {
94 if ($this->_HomePagehandle) {
95 return $this->_HomePagehandle;
98 // check db again (maybe someone else created it since
101 $this->_HomePagehandle = $request->getPage($this->UserName);
102 return $this->_HomePagehandle;
109 function checkPass($submitted_password) {
110 // By definition, an undefined user class cannot sign in.
119 var $_level = WIKIAUTH_ANON;
121 // Anon only gets to load and save prefs in a cookie, that's it.
122 function loadPreferences() {
124 if ($cookie = $request->getCookieVar(WIKI_NAME)) {
125 if (! $unboxedcookie = $this->_prefs->unpack($cookie)) {
126 trigger_error(_("Format of UserPreferences cookie not recognised.") . " "
127 . _("Default preferences will be used."),
130 // TODO: try reading userid from old PhpWiki cookie
131 // formats, then delete old cookie from browser!
134 // try old cookie format.
135 //$cookie = $request->getCookieVar('WIKI_ID');
139 * Only keep the cookie if it matches the UserName who is
140 * signing in or if this really is an Anon login (no
141 * username). (Remember, _BogoUser and higher inherit this
144 if (! $this->UserName || $this->UserName == $unboxedcookie['userid']) {
145 $this->_prefs = new UserPreferences($unboxedcookie);
146 $this->UserName = $unboxedcookie['userid'];
150 function savePreferences() {
151 // Allow for multiple wikis in same domain. Encode only the
152 // _prefs array of the UserPreference object. Ideally the
153 // prefs array should just be imploded into a single string or
154 // something so it is completely human readable by the end
155 // user. In that case stricter error checking will be needed
156 // when loading the cookie.
157 setcookie(WIKI_NAME, $this->_prefs->pack($this->_prefs->getAll()),
158 COOKIE_EXPIRATION_DAYS, COOKIE_DOMAIN);
165 var $_level = WIKIAUTH_BOGO;
167 function _BogoUser($UserName) {
168 $this->_username = $UserName;
169 $this->_prefs = $this->loadPreferences();
172 function loadPreferences() {
173 // Read cookie first, Bogo's homepage prefs could have been
175 _AnonUser::loadPreferences();
176 // User may have deleted cookie, retrieve from his
177 // NamesakePage if there is one.
178 if ((! $this->_prefs) && $this->_HomePagehandle) {
179 if ($restored_from_page = $this->_prefs->unpack($this->_HomePagehandle->get('_prefs'))) {
180 $this->_prefs = new UserPreferences($restored_from_page);
184 function savePreferences() {
185 _AnonUser::savePreferences();
186 // Encode only the _prefs array of the UserPreference object
187 $serialized = $this->_prefs->pack($this->_prefs->getAll());
188 $this->_HomePagehandle->set('_prefs', $serialized);
191 function checkPass($submitted_password) {
192 // By definition, BogoUser has an empty password.
196 function _checkPass($submitted_password, $stored_password) {
202 var $_level = WIKIAUTH_USER;
204 //TODO: if (ALLOW_USER_PASSWORDS)
206 function loadPreferences() {
209 // We don't necessarily have to read the cookie first. Since
210 // the user has a password, the prefs stored in the homepage
211 // cannot be arbitrarily altered by other Bogo users.
214 //TODO: alternatively obtain $stored_password from external auth
215 function checkPass($submitted_password) {
216 $stored_password = $this->_prefs->get('passwd');
217 return $this->_checkPass($submitted_password, $stored_password);
220 //TODO: remove crypt() function check from config.php:396
221 function _checkPass($submitted_password, $stored_password) {
222 if(!empty($submitted_password)) {
223 if (defined('ENCRYPTED_PASSWD') && ENCRYPTED_PASSWD) {
224 // Verify against encrypted password.
225 if (function_exists('crypt')) {
226 if (crypt($submitted_password, $stored_password) == $stored_password )
227 return true; // matches encrypted password
232 trigger_error(_("The crypt function is not available in this version of PHP.") . " "
233 . _("Please set ENCRYPTED_PASSWD to false in index.php and change ADMIN_PASSWD."),
239 // Verify against cleartext password.
240 if ($submitted_password == $stored_password)
243 // Check whether we forgot to enable ENCRYPTED_PASSWD
244 if (function_exists('crypt')) {
245 if (crypt($submitted_password, $stored_password) == $stored_password) {
246 trigger_error(_("Please set ENCRYPTED_PASSWD to true in index.php."),
261 var $_level = WIKIAUTH_ADMIN;
263 function checkPass($submitted_password) {
264 $stored_password = ADMIN_PASSWD;
265 return $this->_checkPass($submitted_password, $stored_password);
269 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
271 class _UserPreference
273 function _UserPreference ($default_value) {
274 $this->default_value = $default_value;
277 function sanify ($value) {
278 return (string)$value;
281 function update ($value) {
285 class _UserPreference_numeric
286 extends _UserPreference
288 function _UserPreference_numeric ($default, $minval = false,
290 $this->_UserPreference((double)$default);
291 $this->_minval = (double)$minval;
292 $this->_maxval = (double)$maxval;
295 function sanify ($value) {
296 $value = (double)$value;
297 if ($this->_minval !== false && $value < $this->_minval)
298 $value = $this->_minval;
299 if ($this->_maxval !== false && $value > $this->_maxval)
300 $value = $this->_maxval;
305 class _UserPreference_int
306 extends _UserPreference_numeric
308 function _UserPreference_int ($default, $minval = false, $maxval = false) {
309 $this->_UserPreference_numeric((int)$default, (int)$minval,
313 function sanify ($value) {
314 return (int)parent::sanify((int)$value);
318 class _UserPreference_bool
319 extends _UserPreference
321 function _UserPreference_bool ($default = false) {
322 $this->_UserPreference((bool)$default);
325 function sanify ($value) {
326 if (is_array($value)) {
327 /* This allows for constructs like:
329 * <input type="hidden" name="pref[boolPref][]" value="0" />
330 * <input type="checkbox" name="pref[boolPref][]" value="1" />
332 * (If the checkbox is not checked, only the hidden input
333 * gets sent. If the checkbox is sent, both inputs get
336 foreach ($value as $val) {
342 return (bool) $value;
346 class _UserPreference_language
347 extends _UserPreference
349 function _UserPreference_language ($default = DEFAULT_LANGUAGE) {
350 $this->_UserPreference($default);
353 // FIXME: check for valid locale
354 function sanify ($value) {
355 // Revert to DEFAULT_LANGUAGE if user does not specify
356 // language in UserPreferences or chooses <system language>.
357 if ($value == '' or empty($value))
358 $value = DEFAULT_LANGUAGE;
360 return (string) $value;
364 class _UserPreference_theme
365 extends _UserPreference
367 function _UserPreference_theme ($default = THEME) {
368 $this->_UserPreference($default);
371 function sanify ($value) {
372 if (file_exists($this->_themefile($value)))
374 return $this->default_value;
377 function update ($newvalue) {
379 include_once($this->_themefile($newvalue));
381 include_once($this->_themefile(THEME));
384 function _themefile ($theme) {
385 return "themes/$theme/themeinfo.php";
389 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
391 // don't save default preferences for efficiency.
392 class UserPreferences
394 function UserPreferences ($saved_prefs = false) {
395 // userid stored too, to ensure the prefs are being loaded for
396 // the correct (currently signing in) userid if stored in a
400 'userid' => new _UserPreference(''),
401 'passwd' => new _UserPreference(''),
402 'autologin' => new _UserPreference_bool(),
403 'email' => new _UserPreference(''),
404 'emailVerified' => new _UserPreference_bool(),
405 'notifyPages' => new _UserPreference(''),
406 'theme' => new _UserPreference_theme(THEME),
407 'lang' => new _UserPreference_language(DEFAULT_LANGUAGE),
408 'editWidth' => new _UserPreference_int(EDITWIDTH_DEFAULT_COLS,
411 'noLinkIcons' => new _UserPreference_bool(),
412 'editHeight' => new _UserPreference_int(EDITHEIGHT_DEFAULT_ROWS,
414 EDITHEIGHT_DEFAULT_ROWS),
415 'timeOffset' => new _UserPreference_numeric(TIMEOFFSET_DEFAULT_HOURS,
416 TIMEOFFSET_MIN_HOURS,
417 TIMEOFFSET_MAX_HOURS),
418 'relativeDates' => new _UserPreference_bool()
421 if (is_array($saved_prefs)) {
422 foreach ($saved_prefs as $name => $value)
423 $this->set($name, $value);
427 function _getPref ($name) {
428 if (!isset($this->_prefs[$name])) {
429 if ($name == 'passwd2') return false;
430 trigger_error("$name: unknown preference", E_USER_NOTICE);
433 return $this->_prefs[$name];
436 function get ($name) {
437 if (isset($this->_prefs[$name]))
438 return $this->_prefs[$name];
439 if (!($pref = $this->_getPref($name)))
441 return $pref->default_value;
444 function set ($name, $value) {
445 if (!($pref = $this->_getPref($name)))
448 $newvalue = $pref->sanify($value);
449 $oldvalue = $this->get($name);
452 if ($newvalue != $oldvalue)
453 $pref->update($newvalue);
455 // don't set default values to save space (in cookies, db and
457 if ($value == $pref->default_value)
458 unset($this->_prefs[$name]);
460 $this->_prefs[$name] = $newvalue;
464 return $this->_prefs;
467 function pack($nonpacked) {
468 return serialize($nonpacked);
470 function unpack($packed) {
473 if (substr($packed, 0, 2) == "O:") {
474 // Looks like a serialized object
475 return unserialize($packed);
477 //trigger_error("DEBUG: Can't unpack bad UserPreferences",
483 return hash($this->_prefs);
488 // $Log: not supported by cvs2svn $
489 // Revision 1.1 2003/12/02 05:46:36 carstenklapp
490 // Complete rewrite of WikiUser.php.
492 // This should make it easier to hook in user permission groups etc. some
493 // time in the future. Most importantly, to finally get UserPreferences
494 // fully working properly for all classes of users: AnonUser, BogoUser,
495 // AdminUser; whether they have a NamesakePage (PersonalHomePage) or not,
496 // want a cookie or not, and to bring back optional AutoLogin with the
497 // UserName stored in a cookie--something that was lost after PhpWiki had
498 // dropped the default http auth login method.
500 // Added WikiUser classes which will (almost) work together with existing
501 // UserPreferences class. Other parts of PhpWiki need to be updated yet
502 // before this code can be hooked up.
509 // c-hanging-comment-ender-p: nil
510 // indent-tabs-mode: nil