CWIS Developer Documentation
Axis--User.php
Go to the documentation of this file.
1 <?PHP
2 
3 #
4 # Axis--User.php
5 # An Object for Handling User Information
6 #
7 # Copyright 1999-2001 Axis Data
8 # This code is free software that can be used or redistributed under the
9 # terms of Version 2 of the GNU General Public License, as published by the
10 # Free Software Foundation (http://www.fsf.org).
11 #
12 # Author: Edward Almasy (almasy@axisdata.com)
13 #
14 # Part of the AxisPHP library v1.2.4
15 # For more information see http://www.axisdata.com/AxisPHP/
16 #
17 
18 # status values (error codes)
19 define("U_OKAY", 0);
20 define("U_ERROR", 1);
21 define("U_BADPASSWORD", 2);
22 define("U_NOSUCHUSER", 3);
23 define("U_PASSWORDSDONTMATCH", 4);
24 define("U_EMAILSDONTMATCH", 5);
25 define("U_DUPLICATEUSERNAME", 6);
26 define("U_ILLEGALUSERNAME", 7);
27 define("U_EMPTYUSERNAME", 8);
28 define("U_ILLEGALPASSWORD", 9);
29 define("U_ILLEGALPASSWORDAGAIN",10);
30 define("U_EMPTYPASSWORD", 11);
31 define("U_EMPTYPASSWORDAGAIN", 12);
32 define("U_ILLEGALEMAIL", 13);
33 define("U_ILLEGALEMAILAGAIN", 14);
34 define("U_EMPTYEMAIL", 15);
35 define("U_EMPTYEMAILAGAIN", 16);
36 define("U_NOTLOGGEDIN", 17);
37 define("U_MAILINGERROR", 18);
38 define("U_TEMPLATENOTFOUND", 19);
39 define("U_DUPLICATEEMAIL", 20);
40 
41 
42 class User {
43 
44  # ---- PUBLIC INTERFACE --------------------------------------------------
45 
46  function User($UserInfoOne = NULL, $UserInfoTwo = NULL)
47  {
48  # assume constructor will succeed and user is not logged in
49  $this->Result = U_OKAY;
50  $this->LoggedIn = FALSE;
51 
52  # create database connection
53  $this->DB = new Database();
54 
55  # if user info passed in
56  if (is_int($UserInfoOne) || is_string($UserInfoOne)
57  || is_int($UserInfoTwo) || is_string($UserInfoTwo))
58  {
59  # if user ID was passed in
60  if (is_int($UserInfoOne) || is_int($UserInfoTwo))
61  {
62  # save user ID
63  $this->UserId = is_int($UserInfoOne) ? $UserInfoOne : $UserInfoTwo;
64  }
65  else
66  {
67  # look up user ID in database
68  $UserInfoTwo = is_string($UserInfoOne) ? $UserInfoOne : $UserInfoTwo;
69  $this->DB->Query("SELECT UserId, LoggedIn FROM APUsers"
70  ." WHERE UserName='".addslashes($UserInfoTwo)."'");
71  $Record = $this->DB->FetchRow();
72  if ($Record)
73  {
74  $this->UserId = $Record["UserId"];
75  $this->LoggedIn = $Record["LoggedIn"];
76  }
77 
78  # if user ID was not found
79  if ($Record === FALSE)
80  {
81  # if name looks like it could actually be a user ID
82  if (preg_match("/^[-]*[0-9]+$/", $UserInfoTwo))
83  {
84  # assume name was user ID
85  $this->UserId = intval($UserInfoTwo);
86  }
87  else
88  {
89  # set code indicating no user found
90  $this->Result = U_NOSUCHUSER;
91  unset($this->UserId);
92  }
93  }
94  }
95  }
96  else
97  {
98  # if user ID is available from session
99  if (isset($_SESSION["APUserId"]))
100  {
101  # save user ID
102  $this->UserId = $_SESSION["APUserId"];
103 
104  # set flag indicating user is currently logged in
105  $this->LoggedIn = TRUE;
106  }
107  }
108  }
109 
110  function Status()
111  {
112  return $this->Result;
113  }
114 
115  # return text message corresponding to current (or specified) status code
116  function StatusMessage($StatusCode = NULL)
117  {
118  $APUserStatusMessages = array(
119  U_OKAY => "The operation was successful.",
120  U_ERROR => "There has been an error.",
121  U_BADPASSWORD => "The password you entered was"
122  ." incorrect.",
123  U_NOSUCHUSER => "No such user name was found.",
124  U_PASSWORDSDONTMATCH => "The new passwords you entered do"
125  ." not match.",
126  U_EMAILSDONTMATCH => "The e-mail addresses you entered"
127  ." do not match.",
128  U_DUPLICATEUSERNAME => "The user name you requested is"
129  ." already in use.",
130  U_ILLEGALUSERNAME => "The user name you requested is too"
131  ." short, too long, or contains"
132  ." illegal characters.",
133  U_ILLEGALPASSWORD => "The new password you requested is"
134  ." too short, too long, or"
135  ." contains illegal characters.",
136  U_ILLEGALEMAIL => "The e-mail address you entered"
137  ." appears to be invalid.",
138  U_NOTLOGGEDIN => "The user is not logged in.",
139  U_MAILINGERROR => "An error occurred while attempting"
140  ." to send e-mail. Please notify"
141  ." the system administrator.",
142  U_TEMPLATENOTFOUND => "An error occurred while attempting"
143  ." to generate e-mail. Please"
144  ." notify the system administrator.",
145  U_DUPLICATEEMAIL => "The e-mail address you supplied already"
146  ." has an account associated with it.",
147  );
148 
149  return ($StatusCode === NULL) ? $APUserStatusMessages[$this->Result]
150  : $APUserStatusMessages[$StatusCode];
151  }
152 
153  function Delete()
154  {
155  # clear priv list values
156  $this->DB->Query("DELETE FROM APUserPrivileges WHERE UserId = '".$this->UserId."'");
157 
158  # delete user record from database
159  $this->DB->Query("DELETE FROM APUsers WHERE UserId = '".$this->UserId."'");
160 
161  # report to caller that everything succeeded
162  $this->Result = U_OKAY;
163  return $this->Result;
164  }
165 
171  static function SetEmailFunction($NewValue)
172  {
173  if (is_callable($NewValue))
174  {
175  self::$EmailFunc = $NewValue;
176  }
177  }
178 
179 
180  # ---- Getting/Setting Values --------------------------------------------
181 
182  function Id()
183  {
184  return $this->UserId;
185  }
186  function Name()
187  {
188  return $this->Get("UserName");
189  }
190  function LastLocation($NewLocation = NULL)
191  {
192  if ($NewLocation)
193  {
194  $this->DB->Query("UPDATE APUsers SET"
195  ." LastLocation = '".addslashes($NewLocation)."',"
196  ." LastActiveDate = NOW(),"
197  ." LastIPAddress = '".$_SERVER["REMOTE_ADDR"]."'"
198  ." WHERE UserId = '".addslashes($this->UserId)."'");
199  if (isset($this->DBFields))
200  {
201  $this->DBFields["LastLocation"] = $NewLocation;
202  $this->DBFields["LastActiveDate"] = date("Y-m-d H:i:s");
203  }
204  }
205  return $this->Get("LastLocation");
206  }
207  function LastActiveDate()
208  {
209  return $this->Get("LastActiveDate");
210  }
211  function LastIPAddress()
212  {
213  return $this->Get("LastIPAddress");
214  }
215 
216  # get value from specified field
217  function Get($FieldName)
218  {
219  return $this->UpdateValue($FieldName);
220  }
221 
222  # get value (formatted as a date) from specified field
223  function GetDate($FieldName, $Format = "")
224  {
225  # retrieve specified value from database
226  if (strlen($Format) > 0)
227  {
228  $this->DB->Query("SELECT DATE_FORMAT(`".addslashes($FieldName)."`, '".addslashes($Format)."') AS `".addslashes($FieldName)."` FROM APUsers WHERE UserId='".$this->UserId."'");
229  }
230  else
231  {
232  $this->DB->Query("SELECT `".addslashes($FieldName)."` FROM APUsers WHERE UserId='".$this->UserId."'");
233  }
234  $Record = $this->DB->FetchRow();
235 
236  # return value to caller
237  return $Record[$FieldName];
238  }
239 
240  # set value in specified field
241  function Set($FieldName, $NewValue)
242  {
243  $this->UpdateValue($FieldName, $NewValue);
244  $this->Result = U_OKAY;
245  return $this->Result;
246  }
247 
248 
249  # ---- Login Functions ---------------------------------------------------
250 
251  function Login($UserName, $Password, $IgnorePassword = FALSE)
252  {
253  # if user not found in DB
254  $this->DB->Query("SELECT * FROM APUsers"
255  ." WHERE UserName = '"
256  .addslashes(self::NormalizeUserName($UserName))."'");
257  if ($this->DB->NumRowsSelected() < 1)
258  {
259  # result is no user by that name
260  $this->Result = U_NOSUCHUSER;
261  }
262  else
263  {
264  # grab password from DB
265  $Record = $this->DB->FetchRow();
266  $StoredPassword = $Record["UserPassword"];
267 
268  if (isset($Password[0]) && $Password[0] == " ")
269  {
270  $Challenge = md5(date("Ymd").$_SERVER["REMOTE_ADDR"]);
271  $StoredPassword = md5( $Challenge . $StoredPassword );
272 
273  $EncryptedPassword = trim($Password);
274  }
275  else
276  {
277  # if supplied password matches encrypted password
278  $EncryptedPassword = crypt($Password, $StoredPassword);
279  }
280 
281  if (($EncryptedPassword == $StoredPassword) || $IgnorePassword)
282  {
283  # result is success
284  $this->Result = U_OKAY;
285 
286  # store user ID for session
287  $this->UserId = $Record["UserId"];
288  $_SESSION["APUserId"] = $this->UserId;
289 
290  # update last login date
291  $this->DB->Query("UPDATE APUsers SET LastLoginDate = NOW(),"
292  ." LoggedIn = '1'"
293  ." WHERE UserId = '".$this->UserId."'");
294 
295  # Check for old format hashes, and rehash if possible
296  if ($EncryptedPassword === $StoredPassword &&
297  substr($StoredPassword,0,3) !== "$1$" &&
298  $Password[0] !== " " &&
299  CRYPT_MD5 )
300  {
301  $NewPassword = crypt($Password);
302  $this->DB->Query(
303  "UPDATE APUsers SET UserPassword='".addslashes($NewPassword)."' "
304  ."WHERE UserId='".$this->UserId."'");
305  }
306 
307  # since self::DBFields might already have been set to false if
308  # the user wasn't logged in when this is called, populate it
309  # with user data so that a call to self::UpdateValue will be
310  # able to properly fetch the data associated with the user
311  $this->DBFields = $Record;
312 
313  # set flag to indicate we are logged in
314  $this->LoggedIn = TRUE;
315  }
316  else
317  {
318  # result is bad password
319  $this->Result = U_BADPASSWORD;
320  }
321  }
322 
323  # return result to caller
324  return $this->Result;
325  }
326 
327  # log this user out
328  function Logout()
329  {
330  # clear user ID (if any) for session
331  unset($_SESSION["APUserId"]);
332 
333  # if user is marked as logged in
334  if ($this->LoggedIn)
335  {
336  # set flag to indicate user is no longer logged in
337  $this->LoggedIn = FALSE;
338 
339  # clear login flag in database
340  $this->DB->Query(
341  "UPDATE APUsers SET LoggedIn = '0' "
342  ."WHERE UserId='".$this->UserId."'");
343  }
344  }
345 
346  function GetPasswordSalt($UserName)
347  {
348  $this->DB->Query(
349  "SELECT * FROM APUsers WHERE UserName = '"
350  .addslashes(self::NormalizeUserName($UserName))."'");
351 
352  if ($this->DB->NumRowsSelected() < 1)
353  {
354  # result is no user by that name, generate a fake salt
355  # to discourage user enumeration. Make it be an old-format
356  # crypt() salt so that it's harder.
357  $SaltString = $_SERVER["SERVER_ADDR"].$UserName;
358  $Result = substr(base64_encode(md5($SaltString)),0,2);
359  }
360  else
361  {
362  # grab password from DB
363  # Assumes that we used php's crypt() for the passowrd
364  # management stuff, and will need to be changed if we
365  # go to something else.
366  $Record = $this->DB->FetchRow();
367  $StoredPassword = $Record["UserPassword"];
368 
369  if (substr($StoredPassword,0,3)==="$1$")
370  {
371  $Result = substr($StoredPassword, 0,12);
372  }
373  else
374  {
375  $Result = substr($StoredPassword, 0,2);
376  }
377  }
378 
379  return $Result;
380  }
381 
382  # report whether this user is or is not currently logged in
383  function IsLoggedIn() { return $this->LoggedIn; }
384  function IsNotLoggedIn() { return !$this->LoggedIn; }
385 
386 
387  # ---- Password Functions ------------------------------------------------
388 
389  # set new password (with checks against old password)
390  function ChangePassword($OldPassword, $NewPassword, $NewPasswordAgain)
391  {
392  # make sure a user is logged in
393  if ($this->IsLoggedIn() !== TRUE)
394  {
395  $this->Result = U_NOTLOGGEDIN;
396  return $this->Result;
397  }
398 
399  # if old password is not correct
400  $StoredPassword = $this->DB->Query("SELECT UserPassword FROM APUsers"
401  ." WHERE UserId='".$this->UserId."'", "UserPassword");
402  $EncryptedPassword = crypt($OldPassword, $StoredPassword);
403  if ($EncryptedPassword != $StoredPassword)
404  {
405  # set status to indicate error
406  $this->Result = U_BADPASSWORD;
407  }
408  # else if new password is not legal
409  elseif (!$this->IsValidPassword($NewPassword))
410  {
411  # set status to indicate error
412  $this->Result = U_ILLEGALPASSWORD;
413  }
414  # else if both instances of new password do not match
415  elseif (self::NormalizePassword($NewPassword)
416  != self::NormalizePassword($NewPasswordAgain))
417  {
418  # set status to indicate error
419  $this->Result = U_PASSWORDSDONTMATCH;
420  }
421  else
422  {
423  # set new password
424  $this->SetPassword($NewPassword);
425 
426  # set status to indicate password successfully changed
427  $this->Result = U_OKAY;
428  }
429 
430  # report to caller that everything succeeded
431  return $this->Result;
432  }
433 
434  # set new password
435  function SetPassword($NewPassword)
436  {
437  # generate encrypted password
438  $EncryptedPassword = crypt(self::NormalizePassword($NewPassword));
439 
440  # save encrypted password
441  $this->UpdateValue("UserPassword", $EncryptedPassword);
442  }
443 
445  $UserName, $EMail, $EMailAgain,
446  $TemplateFile = "Axis--User--EMailTemplate.txt")
447  {
449  $UserName, $EMail, $EMailAgain, $TemplateFile);
450  }
451 
453  $UserName, $EMail, $EMailAgain,
454  $TemplateFile = "Axis--User--EMailTemplate.txt")
455  {
456  # load e-mail template from file (first line is subject)
457  $Template = file($TemplateFile, 1);
458  $EMailSubject = array_shift($Template);
459  $EMailBody = join("", $Template);
460 
462  $UserName, $EMail, $EMailAgain, $EMailSubject, $EMailBody);
463  }
464 
466  $UserName, $EMail, $EMailAgain, $EMailSubject, $EMailBody)
467  {
468  # make sure e-mail addresses match
469  if ($EMail != $EMailAgain)
470  {
471  $this->Result = U_EMAILSDONTMATCH;
472  return $this->Result;
473  }
474 
475  # make sure e-mail address looks valid
476  if ($this->IsValidLookingEMailAddress($EMail) == FALSE)
477  {
478  $this->Result = U_ILLEGALEMAIL;
479  return $this->Result;
480  }
481 
482  # generate random password
483  $Password = $this->GetRandomPassword();
484 
485  # attempt to create new user with password
486  $Result = $this->CreateNewUser($UserName, $Password, $Password);
487 
488  # if user creation failed
489  if ($Result != U_OKAY)
490  {
491  # report error result to caller
492  return $Result;
493  }
494  # else
495  else
496  {
497  # set e-mail address in user record
498  $this->Set("EMail", $EMail);
499 
500  # plug appropriate values into subject and body of e-mail message
501  $EMailSubject = str_replace("X-USERNAME-X", $UserName, $EMailSubject);
502  $EMailBody = str_replace("X-USERNAME-X", $UserName, $EMailBody);
503  $EMailBody = str_replace("X-PASSWORD-X", $Password, $EMailBody);
504 
505  # send out e-mail message with new account info
506  if (is_Callable(self::$EmailFunc))
507  {
508  $Result = call_user_func(self::$EmailFunc,
509  $EMail, $EMailSubject, $EMailBody,
510  "Auto-Submitted: auto-generated");
511  }
512  else
513  {
514  $Result = mail($EMail, $EMailSubject, $EMailBody,
515  "Auto-Submitted: auto-generated");
516  }
517 
518  # if mailing attempt failed
519  if ($Result != TRUE)
520  {
521  # report error to caller
522  $this->Result = U_MAILINGERROR;
523  return $this->Result;
524  }
525  # else
526  else
527  {
528  # report success to caller
529  $this->Result = U_OKAY;
530  return $this->Result;
531  }
532  }
533  }
534 
535  # get code for user to submit to confirm registration
536  function GetActivationCode()
537  {
538  # code is MD5 sum based on user name and encrypted password
539  $ActivationCodeLength = 6;
540  return $this->GetUniqueCode("Activation", $ActivationCodeLength);
541  }
542 
543  # check whether confirmation code is valid
544  function IsActivationCodeGood($Code)
545  {
546  return (strtoupper(trim($Code)) == $this->GetActivationCode())
547  ? TRUE : FALSE;
548  }
549 
550  # get/set whether user registration has been confirmed
551  function IsActivated($NewValue = DB_NOVALUE)
552  {
553  return $this->UpdateValue("RegistrationConfirmed", $NewValue);
554  }
555 
556  # get code for user to submit to confirm password reset
557  function GetResetCode()
558  {
559  # code is MD5 sum based on user name and encrypted password
560  $ResetCodeLength = 10;
561  return $this->GetUniqueCode("Reset", $ResetCodeLength);
562  }
563 
564  # check whether password reset code is valid
565  function IsResetCodeGood($Code)
566  {
567  return (strtoupper(trim($Code)) == $this->GetResetCode())
568  ? TRUE : FALSE;
569  }
570 
571  # get code for user to submit to confirm mail change request
572  function GetMailChangeCode()
573  {
574  $ResetCodeLength = 10;
575 
576  return $this->GetUniqueCode("MailChange".$this->Get("EMail").$this->Get("NewEMail"),
577  $ResetCodeLength);
578  }
579 
580  function IsMailChangeCodeGood($Code)
581  {
582  return (strtoupper(trim($Code)) == $this->GetMailChangeCode())
583  ? TRUE : FALSE;
584  }
585 
586  # send e-mail to user (returns TRUE on success)
587  function SendEMail(
588  $TemplateTextOrFileName, $FromAddress = NULL, $MoreSubstitutions = NULL,
589  $ToAddress = NULL)
590  {
591  # if template is file name
592  if (@is_file($TemplateTextOrFileName))
593  {
594  # load in template from file
595  $Template = file($TemplateTextOrFileName, 1);
596 
597  # report error to caller if template load failed
598  if ($Template == FALSE)
599  {
600  $this->Status = U_TEMPLATENOTFOUND;
601  return $this->Status;
602  }
603 
604  # join into one text block
605  $TemplateTextOrFileName = join("", $Template);
606  }
607 
608  # split template into lines
609  $Template = explode("\n", $TemplateTextOrFileName);
610 
611  # strip any comments out of template
612  $FilteredTemplate = array();
613  foreach ($Template as $Line)
614  {
615  if (!preg_match("/^[\\s]*#/", $Line))
616  {
617  $FilteredTemplate[] = $Line;
618  }
619  }
620 
621  # split subject line out of template (first non-comment line in file)
622  $EMailSubject = array_shift($FilteredTemplate);
623  $EMailBody = join("\n", $FilteredTemplate);
624 
625  # set up our substitutions
626  $Substitutions = array(
627  "X-USERNAME-X" => $this->Get("UserName"),
628  "X-EMAILADDRESS-X" => $this->Get("EMail"),
629  "X-ACTIVATIONCODE-X" => $this->GetActivationCode(),
630  "X-RESETCODE-X" => $this->GetResetCode(),
631  "X-CHANGECODE-X" => $this->GetMailChangeCode(),
632  "X-IPADDRESS-X" => @$_SERVER["REMOTE_ADDR"],
633  );
634 
635  # if caller provided additional substitutions
636  if (is_array($MoreSubstitutions))
637  {
638  # add in entries from caller to substitution list
639  $Substitutions = array_merge(
640  $Substitutions, $MoreSubstitutions);
641  }
642 
643  # perform substitutions on subject and body of message
644  $EMailSubject = str_replace(array_keys($Substitutions),
645  array_values($Substitutions), $EMailSubject);
646  $EMailBody = str_replace(array_keys($Substitutions),
647  array_values($Substitutions), $EMailBody);
648 
649  $AdditionalHeaders = "Auto-Submitted: auto-generated";
650 
651  # if caller provided "From" address
652  if ($FromAddress)
653  {
654  # prepend "From" address onto message
655  $AdditionalHeaders .= "\r\nFrom: ".$FromAddress;
656  }
657 
658  # send out mail message
659  if (is_Callable(self::$EmailFunc))
660  {
661  $Result = call_user_func(self::$EmailFunc,
662  is_null($ToAddress)?$this->Get("EMail"):$ToAddress,
663  $EMailSubject, $EMailBody, $AdditionalHeaders);
664  }
665  else
666  {
667  $Result = mail(is_null($ToAddress)?$this->Get("EMail"):$ToAddress,
668  $EMailSubject,
669  $EMailBody, $AdditionalHeaders);
670  }
671 
672  # report result of mailing attempt to caller
673  $this->Status = ($Result == TRUE) ? U_OKAY : U_MAILINGERROR;
674  return ($this->Status == U_OKAY);
675  }
676 
677 
678  # ---- Privilege Functions -----------------------------------------------
679 
688  function HasPriv($Privilege, $Privileges = NULL)
689  {
690  # make sure a user is logged in (no privileges if not logged in)
691  if ($this->IsLoggedIn() == FALSE) { return FALSE; }
692 
693  # bail out if empty array of privileges passed in
694  if (is_array($Privilege) && !count($Privilege) && (func_num_args() < 2))
695  { return FALSE; }
696 
697  # set up beginning of database query
698  $Query = "SELECT COUNT(*) AS PrivCount FROM APUserPrivileges "
699  ."WHERE UserId='".$this->UserId."' AND (";
700 
701  # add first privilege(s) to query (first arg may be single value or array)
702  if (is_array($Privilege))
703  {
704  $Sep = "";
705  foreach ($Privilege as $Priv)
706  {
707  $Query .= $Sep."Privilege='".addslashes($Priv)."'";
708  $Sep = " OR ";
709  }
710  }
711  else
712  {
713  $Query .= "Privilege='".$Privilege."'";
714  $Sep = " OR ";
715  }
716 
717  # add any privileges from additional args to query
718  $Args = func_get_args();
719  array_shift($Args);
720  foreach ($Args as $Arg)
721  {
722  $Query .= $Sep."Privilege='".$Arg."'";
723  $Sep = " OR ";
724  }
725 
726  # close out query
727  $Query .= ")";
728 
729  # look for privilege in database
730  $PrivCount = $this->DB->Query($Query, "PrivCount");
731 
732  # return value to caller
733  return ($PrivCount > 0) ? TRUE : FALSE;
734  }
735 
744  static function GetSqlQueryForUsersWithPriv($Privilege, $Privileges = NULL)
745  {
746  # set up beginning of database query
747  $Query = "SELECT UserId FROM APUserPrivileges "
748  ."WHERE ";
749 
750  # add first privilege(s) to query (first arg may be single value or array)
751  if (is_array($Privilege))
752  {
753  $Sep = "";
754  foreach ($Privilege as $Priv)
755  {
756  $Query .= $Sep."Privilege='".addslashes($Priv)."'";
757  $Sep = " OR ";
758  }
759  }
760  else
761  {
762  $Query .= "Privilege='".$Privilege."'";
763  $Sep = " OR ";
764  }
765 
766  # add any privileges from additional args to query
767  $Args = func_get_args();
768  array_shift($Args);
769  foreach ($Args as $Arg)
770  {
771  $Query .= $Sep."Privilege='".$Arg."'";
772  $Sep = " OR ";
773  }
774 
775  # return query to caller
776  return $Query;
777  }
778 
779  function GrantPriv($Privilege)
780  {
781  # if privilege value is invalid
782  if (intval($Privilege) != trim($Privilege))
783  {
784  # set code to indicate error
785  $this->Result = U_ERROR;
786  }
787  else
788  {
789  # if user does not already have privilege
790  $PrivCount = $this->DB->Query("SELECT COUNT(*) AS PrivCount"
791  ." FROM APUserPrivileges"
792  ." WHERE UserId='".$this->UserId."'"
793  ." AND Privilege='".$Privilege."'",
794  "PrivCount");
795  if ($PrivCount == 0)
796  {
797  # add privilege for this user to database
798  $this->DB->Query("INSERT INTO APUserPrivileges"
799  ." (UserId, Privilege) VALUES"
800  ." ('".$this->UserId."', ".$Privilege.")");
801  }
802 
803  # set code to indicate success
804  $this->Result = U_OKAY;
805  }
806 
807  # report result to caller
808  return $this->Result;
809  }
810 
811  function RevokePriv($Privilege)
812  {
813  # remove privilege from database (if present)
814  $this->DB->Query("DELETE FROM APUserPrivileges"
815  ." WHERE UserId = '".$this->UserId."'"
816  ." AND Privilege = '".$Privilege."'");
817 
818  # report success to caller
819  $this->Result = U_OKAY;
820  return $this->Result;
821  }
822 
823  function GetPrivList()
824  {
825  # read privileges from database and return array to caller
826  $this->DB->Query("SELECT Privilege FROM APUserPrivileges"
827  ." WHERE UserId='".$this->UserId."'");
828  return $this->DB->FetchColumn("Privilege");
829  }
830 
831  function SetPrivList($NewPrivileges)
832  {
833  # clear old priv list values
834  $this->DB->Query("DELETE FROM APUserPrivileges"
835  ." WHERE UserId='".$this->UserId."'");
836 
837  # for each priv value passed in
838  foreach ($NewPrivileges as $Privilege)
839  {
840  # set priv for user
841  $this->GrantPriv($Privilege);
842  }
843  }
844 
845 
846  # ---- Miscellaneous Functions -------------------------------------------
847 
848  # get unique alphanumeric code for user
849  function GetUniqueCode($SeedString, $CodeLength)
850  {
851  return substr(strtoupper(md5(
852  $this->Get("UserName").$this->Get("UserPassword").$SeedString)),
853  0, $CodeLength);
854  }
855 
856 
857  # ---- PRIVATE INTERFACE -------------------------------------------------
858 
859  protected $DB; # handle to SQL database we use to store user information
860  private $UserId; # user ID number for reference into database
861  private $Result; # result of last operation
862  private $LoggedIn; # flag indicating whether user is logged in
863  private $DBFields; # used for caching user values
864 
865  # optional mail function to use instead of mail()
866  private static $EmailFunc = NULL;
867 
868  # check whether a user name is valid (alphanumeric string of 2-24 chars)
869  static function IsValidUserName($UserName)
870  {
871  if (preg_match("/^[a-zA-Z0-9]{2,24}$/", $UserName)) { return TRUE; } else { return FALSE; }
872  }
873 
874  # check whether a password is valid (at least 6 characters)
875  static function IsValidPassword($Password)
876  {
877  if (strlen(self::NormalizePassword($Password)) < 6)
878  { return FALSE; } else { return TRUE; }
879  }
880 
881  # check whether an e-mail address looks valid
882  static function IsValidLookingEMailAddress($EMail)
883  {
884  if (preg_match("/^[a-zA-Z0-9._\-]+@[a-zA-Z0-9._\-]+\.[a-zA-Z]{2,3}$/", $EMail)) { return TRUE; } else { return FALSE; }
885  }
886 
887  # get normalized version of e-mail address
888  static function NormalizeEMailAddress($EMailAddress)
889  {
890  return strtolower(trim($EMailAddress));
891  }
892 
893  # get normalized version of user name
894  static function NormalizeUserName($UserName)
895  {
896  return trim($UserName);
897  }
898 
899  # get normalized version of password
900  static function NormalizePassword($Password)
901  {
902  return trim($Password);
903  }
904 
905  # generate random password
906  function GetRandomPassword($PasswordMinLength = 6, $PasswordMaxLength = 8)
907  {
908  # seed random number generator
909  mt_srand((double)microtime() * 1000000);
910 
911  # generate password of requested length
912  return sprintf("%06d", mt_rand(pow(10, ($PasswordMinLength - 1)),
913  (pow(10, $PasswordMaxLength) - 1)));
914  }
915 
916  # convenience function to supply parameters to Database->UpdateValue()
917  function UpdateValue($FieldName, $NewValue = DB_NOVALUE)
918  {
919  return $this->DB->UpdateValue("APUsers", $FieldName, $NewValue,
920  "UserId = '".$this->UserId."'", $this->DBFields);
921  }
922 
923  # methods for backward compatibility with earlier versions of User
924  function GivePriv($Privilege) { $this->GrantPriv($Privilege); }
925 
926 }