Axis--UserFactory.php

Go to the documentation of this file.
00001 <?PHP
00002 
00003 #
00004 #   Axis--UserFactory.php
00005 #   An Meta-Object for Handling User Information
00006 #
00007 #   Copyright 2003 Axis Data
00008 #   This code is free software that can be used or redistributed under the
00009 #   terms of Version 2 of the GNU General Public License, as published by the
00010 #   Free Software Foundation (http://www.fsf.org).
00011 #
00012 #   Author:  Edward Almasy (almasy@axisdata.com)
00013 #
00014 #   Part of the AxisPHP library v1.2.4
00015 #   For more information see http://www.axisdata.com/AxisPHP/
00016 #
00017 
00018 class UserFactory {
00019 
00020     # ---- PUBLIC INTERFACE --------------------------------------------------
00021 
00022     # object constructor
00023     function UserFactory($SessionOrDb)
00024     {
00025         # if a session was passed in
00026         if (is_object($SessionOrDb) && method_exists($SessionOrDb, "Session"))
00027         {
00028             # swipe database handle from session
00029             $this->DB = $SessionOrDb->DB;
00030 
00031             # save session
00032             $this->Session = $SessionOrDb;
00033         }
00034         # else if database handle was passed in
00035         elseif (is_object($SessionOrDb) && method_exists($SessionOrDb, "Database"))
00036         {
00037             # save database handle
00038             $this->DB = $SessionOrDb;
00039 
00040             # create session
00041             $this->Session = new Session($this->DB);
00042         }
00043         else
00044         {
00045             # error out
00046             $this->Result = U_ERROR;
00047             exit(1);
00048         }
00049     }
00050 
00063     function CreateNewUser(
00064             $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain,
00065             $IgnoreErrorCodes = NULL)
00066     {
00067         # check incoming values
00068         $ErrorCodes = $this->TestNewUserValues(
00069             $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain);
00070 
00071         # discard any errors we are supposed to ignore
00072         if ($IgnoreErrorCodes)
00073         {
00074             $ErrorCodes = array_diff($ErrorCodes, $IgnoreErrorCodes);
00075         }
00076 
00077         # if error found in incoming values return error codes to caller
00078         if (count($ErrorCodes)) {  return $ErrorCodes;  }
00079 
00080         # add user to database
00081         $UserName = User::NormalizeUserName($UserName);
00082         $this->DB->Query("INSERT INTO APUsers"
00083                 ." (UserName, CreationDate)"
00084                 ." VALUES ('".addslashes($UserName)."', NOW())");
00085 
00086         # create new user object
00087         $UserId = $this->DB->LastInsertId("APUsers");
00088         $User = new User($this->DB, (int)$UserId);
00089 
00090         # if new user object creation failed return error code to caller
00091         if ($User->Status() != U_OKAY) {  return array($User->Status());  }
00092 
00093         # set password and e-mail address
00094         $User->SetPassword($Password);
00095         $User->Set("EMail", $EMail);
00096 
00097         # return new user object to caller
00098         return $User;
00099     }
00100 
00101     # test new user creation values (returns array of error codes)
00102     function TestNewUserValues(
00103             $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain)
00104     {
00105         $ErrorCodes = array();
00106         if (strlen(User::NormalizeUserName($UserName)) == 0)
00107             {  $ErrorCodes[] = U_EMPTYUSERNAME;  }
00108         elseif (!User::IsValidUserName($UserName))
00109             {  $ErrorCodes[] = U_ILLEGALUSERNAME;  }
00110         elseif ($this->UserNameExists($UserName))
00111             {  $ErrorCodes[] = U_DUPLICATEUSERNAME;  }
00112 
00113         if ($this->EMailAddressIsInUse($EMail))
00114             {  $ErrorCodes[] = U_DUPLICATEEMAIL;  }
00115 
00116         $FoundOtherPasswordError = FALSE;
00117         if (strlen(User::NormalizePassword($Password)) == 0)
00118         {
00119             $ErrorCodes[] = U_EMPTYPASSWORD;
00120             $FoundOtherPasswordError = TRUE;
00121         }
00122         elseif (!User::IsValidPassword($Password))
00123         {
00124             $ErrorCodes[] = U_ILLEGALPASSWORD;
00125             $FoundOtherPasswordError = TRUE;
00126         }
00127 
00128         if (strlen(User::NormalizePassword($PasswordAgain)) == 0)
00129         {
00130             $ErrorCodes[] = U_EMPTYPASSWORDAGAIN;
00131             $FoundOtherPasswordError = TRUE;
00132         }
00133         elseif (!User::IsValidPassword($PasswordAgain))
00134         {
00135             $ErrorCodes[] = U_ILLEGALPASSWORDAGAIN;
00136             $FoundOtherPasswordError = TRUE;
00137         }
00138 
00139         if ($FoundOtherPasswordError == FALSE)
00140         {
00141             if (User::NormalizePassword($Password)
00142                     != User::NormalizePassword($PasswordAgain))
00143             {
00144                 $ErrorCodes[] = U_PASSWORDSDONTMATCH;
00145             }
00146         }
00147 
00148         $FoundOtherEMailError = FALSE;
00149         if (strlen(User::NormalizeEMailAddress($EMail)) == 0)
00150         {
00151             $ErrorCodes[] = U_EMPTYEMAIL;
00152             $FoundOtherEMailError = TRUE;
00153         }
00154         elseif (!User::IsValidLookingEMailAddress($EMail))
00155         {
00156             $ErrorCodes[] = U_ILLEGALEMAIL;
00157             $FoundOtherEMailError = TRUE;
00158         }
00159 
00160         if (strlen(User::NormalizeEMailAddress($EMailAgain)) == 0)
00161         {
00162             $ErrorCodes[] = U_EMPTYEMAILAGAIN;
00163             $FoundOtherEMailError = TRUE;
00164         }
00165         elseif (!User::IsValidLookingEMailAddress($EMailAgain))
00166         {
00167             $ErrorCodes[] = U_ILLEGALEMAILAGAIN;
00168             $FoundOtherEMailError = TRUE;
00169         }
00170 
00171         if ($FoundOtherEMailError == FALSE)
00172         {
00173             if (User::NormalizeEMailAddress($EMail)
00174                     != User::NormalizeEMailAddress($EMailAgain))
00175             {
00176                 $ErrorCodes[] = U_EMAILSDONTMATCH;
00177             }
00178         }
00179 
00180         return $ErrorCodes;
00181     }
00182 
00188     function GetUserCount($Condition = NULL)
00189     {
00190         return $this->DB->Query("SELECT COUNT(*) AS UserCount FROM APUsers"
00191                 .($Condition ? " WHERE ".$Condition : ""), "UserCount");
00192     }
00193 
00194     # return total number of user that matched last GetMatchingUsers call
00195     # before the return size was limited
00196     function GetMatchingUserCount()
00197     {
00198         return $this->MatchingUserCount;
00199     }
00200 
00201     # return array of users currently logged in
00202     function GetLoggedInUsers()
00203     {
00204         # start with empty array (to prevent array errors)
00205         $ReturnValue = array();
00206 
00207         # load array of logged in user
00208         $UserIds = $this->Session->GetFromAllSessions("APUserId");
00209 
00210         # for each logged in user
00211         foreach ($UserIds as $UserId)
00212         {
00213             # load all data values for user
00214             $this->DB->Query("SELECT * FROM APUsers WHERE UserId = '".$UserId."'");
00215             $ReturnValue[$UserId] = $this->DB->FetchRow();
00216         }
00217 
00218         # return array of user data to caller
00219         return $ReturnValue;
00220     }
00221 
00222     # return array of users recently logged in. returns 10 users by default
00223     function GetRecentlyLoggedInUsers($Since = NULL, $Limit = 10)
00224     {
00225         # start with empty array (to prevent array errors)
00226         $ReturnValue = array();
00227 
00228         # get users recently logged in during the last 24 hours if no date given
00229         if (is_null($Since))
00230         {
00231             $Date = date("Y-m-d H:i:s", time()-86400);
00232         }
00233 
00234         else
00235         {
00236             $Date = date("Y-m-d H:i:s", strtotime($Since));
00237         }
00238 
00239         # query for the users who were logged in since the given date
00240         $this->DB->Query("
00241             SELECT U.*
00242             FROM APUsers U
00243             LEFT JOIN
00244             -- the dummy table is an optimization. see the comment by Vimal
00245             -- Gupta in the MySQL docs:
00246             -- http://dev.mysql.com/doc/refman/5.0/en/in-subquery-optimization.html
00247             (SELECT DataValue
00248              FROM APSessionData
00249              WHERE DataName = 'APUserId'
00250              -- allows fetching distinct DataValue values but with GROUP BY
00251              -- optimizations
00252              GROUP BY DataValue) as Dummy
00253             -- using this convoluted method because DataValue is an integer
00254             -- (UserId) serialized by PHP to a string
00255             ON CONCAT('s:', CHAR_LENGTH(CAST(U.UserId AS CHAR)),
00256             ':\"', U.UserId,'\";') = Dummy.DataValue
00257             WHERE U.LastActiveDate >= '".$Date."'
00258             AND Dummy.DataValue IS NULL
00259             ORDER BY U.LastActiveDate DESC
00260             LIMIT ".intval($Limit));
00261 
00262         while (FALSE !== ($Row = $this->DB->FetchRow()))
00263         {
00264             $ReturnValue[$Row["UserId"]] = $Row;
00265         }
00266 
00267         # return array of user data to caller
00268         return $ReturnValue;
00269     }
00270 
00271     # return array of user names who have the specified privileges
00272     # (array index is user IDs)
00273     function GetUsersWithPrivileges()
00274     {
00275         # start with query string that will return all users
00276         $QueryString = "SELECT DISTINCT APUsers.UserId, UserName FROM APUsers, APUserPrivileges";
00277 
00278         # for each specified privilege
00279         $Args = func_get_args();
00280         foreach ($Args as $Index => $Arg)
00281         {
00282             # add condition to query string
00283             $QueryString .= ($Index == 0) ? " WHERE (" : " OR";
00284             $QueryString .= " APUserPrivileges.Privilege = ".$Arg;
00285         }
00286 
00287         # close privilege condition in query string and add user ID condition
00288         $QueryString.= count($Args) ? ") AND APUsers.UserId = APUserPrivileges.UserId" : "";
00289 
00290         # perform query
00291         $this->DB->Query($QueryString);
00292 
00293         # copy query result into user info array
00294         $Users = $this->DB->FetchColumn("UserName", "UserId");
00295 
00296         # return array of users to caller
00297         return $Users;
00298     }
00299 
00300     # return array of user objects who have values matching search string
00301     # (array indexes are user IDs)
00302     function FindUsers($SearchString, $FieldName = "UserName",
00303             $SortFieldName = "UserName", $Offset = 0, $Count = 9999999)
00304     {
00305         # retrieve matching user IDs
00306         $UserNames = $this->FindUserNames(
00307                 $SearchString, $FieldName, $SortFieldName, $Offset, $Count);
00308 
00309         # create user objects
00310         $Users = array();
00311         foreach ($UserNames as $UserId => $UserName)
00312         {
00313             $Users[$UserId] = new User($this->DB, intval($UserId));
00314         }
00315 
00316         # return array of user objects to caller
00317         return $Users;
00318     }
00319 
00320     # return array of user names/IDs who have values matching search string
00321     # (array indexes are user IDs, array values are user names)
00322     function FindUserNames($SearchString, $FieldName = "UserName",
00323             $SortFieldName = "UserName", $Offset = 0, $Count = 9999999)
00324     {
00325         # Construct a database query:
00326         $QueryString = "SELECT UserId, UserName FROM APUsers WHERE";
00327 
00328         # If the search string is a valid username which is shorter than the
00329         # minimum word length indexed by the FTS, just do a normal
00330         # equality test instead of using the index.
00331         # Otherwise, FTS away.
00332         $MinWordLen = $this->DB->Query(
00333             "SHOW VARIABLES WHERE variable_name='ft_min_word_len'", "Value");
00334         if (User::IsValidUserName($SearchString) &&
00335             strlen($SearchString) < $MinWordLen )
00336         {
00337             $QueryString .= " UserName='".addslashes($SearchString)."'";
00338         }
00339         else
00340         {
00341             # massage search string to use AND logic
00342             $Words = preg_split("/[\s]+/", trim($SearchString));
00343             $NewSearchString = "";
00344             $InQuotedString = FALSE;
00345             foreach ($Words as $Word)
00346             {
00347                 if ($InQuotedString == FALSE) {  $NewSearchString .= "+";  }
00348                 if (preg_match("/^\"/", $Word)) {  $InQuotedString = TRUE;  }
00349                 if (preg_match("/\"$/", $Word)) {  $InQuotedString = FALSE;  }
00350                 $NewSearchString .= $Word." ";
00351             }
00352             $QueryString .= " MATCH (".$FieldName.")"
00353                 ." AGAINST ('".addslashes(trim($NewSearchString))."'"
00354                 ." IN BOOLEAN MODE)";
00355         }
00356         $QueryString .= " ORDER BY ".$SortFieldName
00357             ." LIMIT ".$Offset.", ".$Count;
00358 
00359         # retrieve matching user IDs
00360         $this->DB->Query($QueryString);
00361         $UserNames = $this->DB->FetchColumn("UserName", "UserId");
00362 
00363         # return names/IDs to caller
00364         return $UserNames;
00365     }
00366 
00367     # return array of users who have values matching search string (in specific field if requested)
00368     # (search string respects POSIX-compatible regular expressions)
00369     # optimization: $SearchString = ".*." and $FieldName = NULL will return all
00370     #   users ordered by $SortFieldName
00371     function GetMatchingUsers($SearchString, $FieldName = NULL,
00372                               $SortFieldName = "UserName",
00373                               $ResultsStartAt = 0, $ReturnNumber = NULL)
00374     {
00375         # start with empty array (to prevent array errors)
00376         $ReturnValue = array();
00377 
00378         # if search string supplied
00379         if (strlen(trim($SearchString)) > 0)
00380         {
00381             # build the sorting clause
00382             $QueryOrderBy = " ORDER BY $SortFieldName";
00383 
00384             if ($ReturnNumber)
00385             {
00386                 $QueryLimit = " LIMIT ";
00387                 if ($ResultsStartAt)
00388                 {
00389                     $QueryLimit .= "$ResultsStartAt, $ReturnNumber";
00390                 }
00391                 else
00392                     $QueryLimit .= $ReturnNumber;
00393             }
00394             else
00395             {
00396                 $QueryLimit = "";
00397             }
00398 
00399             $Query = "SELECT * FROM APUsers";
00400 
00401             # the Criteria Query will be used to get the total number
00402             # of results without the limit clause
00403             $CriteriaQuery = $Query;
00404 
00405 
00406             # if specific field comparison requested
00407             if ($FieldName != NULL)
00408             {
00409                 # append queries with criteria
00410                 $Query .= " WHERE ".$FieldName." REGEXP '".addslashes($SearchString)."'";
00411 
00412                 $CriteriaQuery = $Query;
00413 
00414                 # tack on ordering and limiting
00415                 $Query .= $QueryOrderBy.$QueryLimit;
00416 
00417             }
00418             # optimize for returning all users
00419             elseif (strcasecmp($SearchString, ".*.") == 0)
00420             {
00421                 $Query .= $QueryOrderBy.$QueryLimit;
00422 
00423                 # set field name to username - this would be the first field
00424                 # returned by a field to field search using the above RegExp
00425                 $FieldName = "UserName";
00426             }
00427             else
00428             {
00429                 # search all fields - can't limit here, but we can order by
00430                 $Query .= $QueryOrderBy;
00431             }
00432 
00433             # execute query
00434             $this->DB->Query($Query);
00435 
00436             # process query return
00437             while ($Record = $this->DB->FetchRow())
00438             {
00439 
00440                 # if specific field or all users requested
00441                 if ($FieldName != NULL)
00442                 {
00443                     # add user to return array
00444                     $ReturnValue[$Record["UserId"]] = $Record;
00445 
00446                     # add matching search field to return array
00447                     $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FieldName;
00448                 }
00449                 else
00450                 {
00451                     # for each user data field
00452                     foreach ($Record as $FName => $FValue)
00453                     {
00454                         # if search string appears in data field
00455                         if (ereg($SearchString, $Record[$FName]))
00456                         {
00457                             # add user to return array
00458                             $ReturnValue[$Record["UserId"]] = $Record;
00459 
00460                             # add matching search field to return array
00461                             $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FName;
00462 
00463                             # move on to next user
00464                             continue;
00465                         }
00466                     }
00467 
00468                     # cut return array down to requested size
00469                     if (isset($ReturnNumber))
00470                     {
00471                         $ReturnValue = array_slice($ReturnValue, $ResultsStartAt, $ReturnNumber, true);
00472                     }
00473                 }
00474             }
00475 
00476             if (!isset($this->MatchingUserCount))
00477             {
00478                 $this->DB->Query($CriteriaQuery);
00479                 $this->MatchingUserCount = $this->DB->NumRowsSelected();
00480             }
00481 
00482         }
00483 
00484         # return array of matching users to caller
00485         return $ReturnValue;
00486     }
00487 
00488     # check whether user name currently exists
00489     function UserNameExists($UserName)
00490     {
00491         # normalize user name
00492         $UserName = User::NormalizeUserName($UserName);
00493 
00494         # check whether user name is already in use
00495         $NameCount = $this->DB->Query(
00496                 "SELECT COUNT(*) AS NameCount FROM APUsers"
00497                     ." WHERE UserName = '".addslashes($UserName)."'",
00498                 "NameCount");
00499 
00500         # report to caller whether name exists
00501         return ($NameCount > 0);
00502     }
00503 
00504     # check whether e-mail address currently has account associated with it
00505     function EMailAddressIsInUse($Address)
00506     {
00507         # normalize address
00508         $UserName = User::NormalizeEMailAddress($Address);
00509 
00510         # check whether address is already in use
00511         $AddressCount = $this->DB->Query(
00512                 "SELECT COUNT(*) AS AddressCount FROM APUsers"
00513                     ." WHERE EMail = '".addslashes($Address)."'",
00514                 "AddressCount");
00515 
00516         # report to caller whether address is in use
00517         return ($AddressCount > 0);
00518     }
00519 
00525     public function GetNewestUsers($Limit = 5)
00526     {
00527         # assume no users will be found
00528         $Users = array();
00529 
00530         # fetch the newest users
00531         $this->DB->Query("SELECT *"
00532                 ." FROM APUsers"
00533                 ." ORDER BY CreationDate DESC"
00534                 ." LIMIT ".intval($Limit));
00535         $UserIds = $this->DB->FetchColumn("UserId");
00536 
00537         # for each user id found
00538         foreach ($UserIds as $UserId)
00539         {
00540             $Users[$UserId] = new SPTUser($UserId);
00541         }
00542 
00543         # return the newest users
00544         return $Users;
00545     }
00546 
00547     # ---- PRIVATE INTERFACE -------------------------------------------------
00548 
00549     var $DB;
00550     var $Session;
00551     var $SortFieldName;
00552     var $MatchingUserCount;
00553 
00554     # callback function for sorting users
00555     function CompareUsersForSort($UserA, $UserB)
00556     {
00557         return strcasecmp($UserA[$this->SortFieldName], $UserB[$this->SortFieldName]);
00558     }
00559 };
00560 
00561 
00562 ?>