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 user names who have the specified privileges 00223 # (array index is user IDs) 00224 function GetUsersWithPrivileges() 00225 { 00226 # start with query string that will return all users 00227 $QueryString = "SELECT DISTINCT APUsers.UserId, UserName FROM APUsers, APUserPrivileges"; 00228 00229 # for each specified privilege 00230 $Args = func_get_args(); 00231 foreach ($Args as $Index => $Arg) 00232 { 00233 # add condition to query string 00234 $QueryString .= ($Index == 0) ? " WHERE (" : " OR"; 00235 $QueryString .= " APUserPrivileges.Privilege = ".$Arg; 00236 } 00237 00238 # close privilege condition in query string and add user ID condition 00239 $QueryString.= count($Args) ? ") AND APUsers.UserId = APUserPrivileges.UserId" : ""; 00240 00241 # perform query 00242 $this->DB->Query($QueryString); 00243 00244 # copy query result into user info array 00245 $Users = $this->DB->FetchColumn("UserName", "UserId"); 00246 00247 # return array of users to caller 00248 return $Users; 00249 } 00250 00251 # return array of user objects who have values matching search string 00252 # (array indexes are user IDs) 00253 function FindUsers($SearchString, $FieldName = "UserName", 00254 $SortFieldName = "UserName", $Offset = 0, $Count = 9999999) 00255 { 00256 # retrieve matching user IDs 00257 $UserNames = $this->FindUserNames( 00258 $SearchString, $FieldName, $SortFieldName, $Offset, $Count); 00259 00260 # create user objects 00261 $Users = array(); 00262 foreach ($UserNames as $UserId => $UserName) 00263 { 00264 $Users[$UserId] = new User($this->DB, intval($UserId)); 00265 } 00266 00267 # return array of user objects to caller 00268 return $Users; 00269 } 00270 00271 # return array of user names/IDs who have values matching search string 00272 # (array indexes are user IDs, array values are user names) 00273 function FindUserNames($SearchString, $FieldName = "UserName", 00274 $SortFieldName = "UserName", $Offset = 0, $Count = 9999999) 00275 { 00276 # construct database query (massage search string to use AND logic) 00277 $QueryString = "SELECT UserId, UserName FROM APUsers WHERE"; 00278 $Words = preg_split("/[\s]+/", trim($SearchString)); 00279 $NewSearchString = ""; 00280 $InQuotedString = FALSE; 00281 foreach ($Words as $Word) 00282 { 00283 if ($InQuotedString == FALSE) { $NewSearchString .= "+"; } 00284 if (preg_match("/^\"/", $Word)) { $InQuotedString = TRUE; } 00285 if (preg_match("/\"$/", $Word)) { $InQuotedString = FALSE; } 00286 $NewSearchString .= $Word." "; 00287 } 00288 $QueryString .= " MATCH (".$FieldName.")" 00289 ." AGAINST ('".addslashes(trim($NewSearchString))."'" 00290 ." IN BOOLEAN MODE)"; 00291 $QueryString .= " ORDER BY ".$SortFieldName 00292 ." LIMIT ".$Offset.", ".$Count; 00293 00294 # retrieve matching user IDs 00295 $this->DB->Query($QueryString); 00296 $UserNames = $this->DB->FetchColumn("UserName", "UserId"); 00297 00298 # return names/IDs to caller 00299 return $UserNames; 00300 } 00301 00302 # return array of users who have values matching search string (in specific field if requested) 00303 # (search string respects POSIX-compatible regular expressions) 00304 # optimization: $SearchString = ".*." and $FieldName = NULL will return all 00305 # users ordered by $SortFieldName 00306 function GetMatchingUsers($SearchString, $FieldName = NULL, 00307 $SortFieldName = "UserName", 00308 $ResultsStartAt = 0, $ReturnNumber = NULL) 00309 { 00310 # start with empty array (to prevent array errors) 00311 $ReturnValue = array(); 00312 00313 # if search string supplied 00314 if (strlen(trim($SearchString)) > 0) 00315 { 00316 # build the sorting clause 00317 $QueryOrderBy = " ORDER BY $SortFieldName"; 00318 00319 if ($ReturnNumber) 00320 { 00321 $QueryLimit = " LIMIT "; 00322 if ($ResultsStartAt) 00323 { 00324 $QueryLimit .= "$ResultsStartAt, $ReturnNumber"; 00325 } 00326 else 00327 $QueryLimit .= $ReturnNumber; 00328 } 00329 else 00330 { 00331 $QueryLimit = ""; 00332 } 00333 00334 $Query = "SELECT * FROM APUsers"; 00335 00336 # the Criteria Query will be used to get the total number 00337 # of results without the limit clause 00338 $CriteriaQuery = $Query; 00339 00340 00341 # if specific field comparison requested 00342 if ($FieldName != NULL) 00343 { 00344 # append queries with criteria 00345 $Query .= " WHERE ".$FieldName." REGEXP '".addslashes($SearchString)."'"; 00346 00347 $CriteriaQuery = $Query; 00348 00349 # tack on ordering and limiting 00350 $Query .= $QueryOrderBy.$QueryLimit; 00351 00352 } 00353 # optimize for returning all users 00354 elseif (strcasecmp($SearchString, ".*.") == 0) 00355 { 00356 $Query .= $QueryOrderBy.$QueryLimit; 00357 00358 # set field name to username - this would be the first field 00359 # returned by a field to field search using the above RegExp 00360 $FieldName = "UserName"; 00361 } 00362 else 00363 { 00364 # search all fields - can't limit here, but we can order by 00365 $Query .= $QueryOrderBy; 00366 } 00367 00368 # execute query 00369 $this->DB->Query($Query); 00370 00371 # process query return 00372 while ($Record = $this->DB->FetchRow()) 00373 { 00374 00375 # if specific field or all users requested 00376 if ($FieldName != NULL) 00377 { 00378 # add user to return array 00379 $ReturnValue[$Record["UserId"]] = $Record; 00380 00381 # add matching search field to return array 00382 $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FieldName; 00383 } 00384 else 00385 { 00386 # for each user data field 00387 foreach ($Record as $FName => $FValue) 00388 { 00389 # if search string appears in data field 00390 if (ereg($SearchString, $Record[$FName])) 00391 { 00392 # add user to return array 00393 $ReturnValue[$Record["UserId"]] = $Record; 00394 00395 # add matching search field to return array 00396 $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FName; 00397 00398 # move on to next user 00399 continue; 00400 } 00401 } 00402 00403 # cut return array down to requested size 00404 if (isset($ReturnNumber)) 00405 { 00406 $ReturnValue = array_slice($ReturnValue, $ResultsStartAt, $ReturnNumber, true); 00407 } 00408 } 00409 } 00410 00411 if (!isset($this->MatchingUserCount)) 00412 { 00413 $this->DB->Query($CriteriaQuery); 00414 $this->MatchingUserCount = $this->DB->NumRowsSelected(); 00415 } 00416 00417 } 00418 00419 # return array of matching users to caller 00420 return $ReturnValue; 00421 } 00422 00423 # check whether user name currently exists 00424 function UserNameExists($UserName) 00425 { 00426 # normalize user name 00427 $UserName = User::NormalizeUserName($UserName); 00428 00429 # check whether user name is already in use 00430 $NameCount = $this->DB->Query( 00431 "SELECT COUNT(*) AS NameCount FROM APUsers" 00432 ." WHERE UserName = '".addslashes($UserName)."'", 00433 "NameCount"); 00434 00435 # report to caller whether name exists 00436 return ($NameCount > 0); 00437 } 00438 00439 # check whether e-mail address currently has account associated with it 00440 function EMailAddressIsInUse($Address) 00441 { 00442 # normalize address 00443 $UserName = User::NormalizeEMailAddress($Address); 00444 00445 # check whether address is already in use 00446 $AddressCount = $this->DB->Query( 00447 "SELECT COUNT(*) AS AddressCount FROM APUsers" 00448 ." WHERE EMail = '".addslashes($Address)."'", 00449 "AddressCount"); 00450 00451 # report to caller whether address is in use 00452 return ($AddressCount > 0); 00453 } 00454 00460 public function GetNewestUsers($Limit = 5) 00461 { 00462 # assume no users will be found 00463 $Users = array(); 00464 00465 # fetch the newest users 00466 $this->DB->Query("SELECT *" 00467 ." FROM APUsers" 00468 ." ORDER BY CreationDate DESC" 00469 ." LIMIT ".intval($Limit)); 00470 $UserIds = $this->DB->FetchColumn("UserId"); 00471 00472 # for each user id found 00473 foreach ($UserIds as $UserId) 00474 { 00475 $Users[$UserId] = new SPTUser($UserId); 00476 } 00477 00478 # return the newest users 00479 return $Users; 00480 } 00481 00482 # ---- PRIVATE INTERFACE ------------------------------------------------- 00483 00484 var $DB; 00485 var $Session; 00486 var $SortFieldName; 00487 var $MatchingUserCount; 00488 00489 # callback function for sorting users 00490 function CompareUsersForSort($UserA, $UserB) 00491 { 00492 return strcasecmp($UserA[$this->SortFieldName], $UserB[$this->SortFieldName]); 00493 } 00494 }; 00495 00496 00497 ?>