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 database query (massage search string to use AND logic) 00326 $QueryString = "SELECT UserId, UserName FROM APUsers WHERE"; 00327 $Words = preg_split("/[\s]+/", trim($SearchString)); 00328 $NewSearchString = ""; 00329 $InQuotedString = FALSE; 00330 foreach ($Words as $Word) 00331 { 00332 if ($InQuotedString == FALSE) { $NewSearchString .= "+"; } 00333 if (preg_match("/^\"/", $Word)) { $InQuotedString = TRUE; } 00334 if (preg_match("/\"$/", $Word)) { $InQuotedString = FALSE; } 00335 $NewSearchString .= $Word." "; 00336 } 00337 $QueryString .= " MATCH (".$FieldName.")" 00338 ." AGAINST ('".addslashes(trim($NewSearchString))."'" 00339 ." IN BOOLEAN MODE)"; 00340 $QueryString .= " ORDER BY ".$SortFieldName 00341 ." LIMIT ".$Offset.", ".$Count; 00342 00343 # retrieve matching user IDs 00344 $this->DB->Query($QueryString); 00345 $UserNames = $this->DB->FetchColumn("UserName", "UserId"); 00346 00347 # return names/IDs to caller 00348 return $UserNames; 00349 } 00350 00351 # return array of users who have values matching search string (in specific field if requested) 00352 # (search string respects POSIX-compatible regular expressions) 00353 # optimization: $SearchString = ".*." and $FieldName = NULL will return all 00354 # users ordered by $SortFieldName 00355 function GetMatchingUsers($SearchString, $FieldName = NULL, 00356 $SortFieldName = "UserName", 00357 $ResultsStartAt = 0, $ReturnNumber = NULL) 00358 { 00359 # start with empty array (to prevent array errors) 00360 $ReturnValue = array(); 00361 00362 # if search string supplied 00363 if (strlen(trim($SearchString)) > 0) 00364 { 00365 # build the sorting clause 00366 $QueryOrderBy = " ORDER BY $SortFieldName"; 00367 00368 if ($ReturnNumber) 00369 { 00370 $QueryLimit = " LIMIT "; 00371 if ($ResultsStartAt) 00372 { 00373 $QueryLimit .= "$ResultsStartAt, $ReturnNumber"; 00374 } 00375 else 00376 $QueryLimit .= $ReturnNumber; 00377 } 00378 else 00379 { 00380 $QueryLimit = ""; 00381 } 00382 00383 $Query = "SELECT * FROM APUsers"; 00384 00385 # the Criteria Query will be used to get the total number 00386 # of results without the limit clause 00387 $CriteriaQuery = $Query; 00388 00389 00390 # if specific field comparison requested 00391 if ($FieldName != NULL) 00392 { 00393 # append queries with criteria 00394 $Query .= " WHERE ".$FieldName." REGEXP '".addslashes($SearchString)."'"; 00395 00396 $CriteriaQuery = $Query; 00397 00398 # tack on ordering and limiting 00399 $Query .= $QueryOrderBy.$QueryLimit; 00400 00401 } 00402 # optimize for returning all users 00403 elseif (strcasecmp($SearchString, ".*.") == 0) 00404 { 00405 $Query .= $QueryOrderBy.$QueryLimit; 00406 00407 # set field name to username - this would be the first field 00408 # returned by a field to field search using the above RegExp 00409 $FieldName = "UserName"; 00410 } 00411 else 00412 { 00413 # search all fields - can't limit here, but we can order by 00414 $Query .= $QueryOrderBy; 00415 } 00416 00417 # execute query 00418 $this->DB->Query($Query); 00419 00420 # process query return 00421 while ($Record = $this->DB->FetchRow()) 00422 { 00423 00424 # if specific field or all users requested 00425 if ($FieldName != NULL) 00426 { 00427 # add user to return array 00428 $ReturnValue[$Record["UserId"]] = $Record; 00429 00430 # add matching search field to return array 00431 $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FieldName; 00432 } 00433 else 00434 { 00435 # for each user data field 00436 foreach ($Record as $FName => $FValue) 00437 { 00438 # if search string appears in data field 00439 if (ereg($SearchString, $Record[$FName])) 00440 { 00441 # add user to return array 00442 $ReturnValue[$Record["UserId"]] = $Record; 00443 00444 # add matching search field to return array 00445 $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FName; 00446 00447 # move on to next user 00448 continue; 00449 } 00450 } 00451 00452 # cut return array down to requested size 00453 if (isset($ReturnNumber)) 00454 { 00455 $ReturnValue = array_slice($ReturnValue, $ResultsStartAt, $ReturnNumber, true); 00456 } 00457 } 00458 } 00459 00460 if (!isset($this->MatchingUserCount)) 00461 { 00462 $this->DB->Query($CriteriaQuery); 00463 $this->MatchingUserCount = $this->DB->NumRowsSelected(); 00464 } 00465 00466 } 00467 00468 # return array of matching users to caller 00469 return $ReturnValue; 00470 } 00471 00472 # check whether user name currently exists 00473 function UserNameExists($UserName) 00474 { 00475 # normalize user name 00476 $UserName = User::NormalizeUserName($UserName); 00477 00478 # check whether user name is already in use 00479 $NameCount = $this->DB->Query( 00480 "SELECT COUNT(*) AS NameCount FROM APUsers" 00481 ." WHERE UserName = '".addslashes($UserName)."'", 00482 "NameCount"); 00483 00484 # report to caller whether name exists 00485 return ($NameCount > 0); 00486 } 00487 00488 # check whether e-mail address currently has account associated with it 00489 function EMailAddressIsInUse($Address) 00490 { 00491 # normalize address 00492 $UserName = User::NormalizeEMailAddress($Address); 00493 00494 # check whether address is already in use 00495 $AddressCount = $this->DB->Query( 00496 "SELECT COUNT(*) AS AddressCount FROM APUsers" 00497 ." WHERE EMail = '".addslashes($Address)."'", 00498 "AddressCount"); 00499 00500 # report to caller whether address is in use 00501 return ($AddressCount > 0); 00502 } 00503 00509 public function GetNewestUsers($Limit = 5) 00510 { 00511 # assume no users will be found 00512 $Users = array(); 00513 00514 # fetch the newest users 00515 $this->DB->Query("SELECT *" 00516 ." FROM APUsers" 00517 ." ORDER BY CreationDate DESC" 00518 ." LIMIT ".intval($Limit)); 00519 $UserIds = $this->DB->FetchColumn("UserId"); 00520 00521 # for each user id found 00522 foreach ($UserIds as $UserId) 00523 { 00524 $Users[$UserId] = new SPTUser($UserId); 00525 } 00526 00527 # return the newest users 00528 return $Users; 00529 } 00530 00531 # ---- PRIVATE INTERFACE ------------------------------------------------- 00532 00533 var $DB; 00534 var $Session; 00535 var $SortFieldName; 00536 var $MatchingUserCount; 00537 00538 # callback function for sorting users 00539 function CompareUsersForSort($UserA, $UserB) 00540 { 00541 return strcasecmp($UserA[$this->SortFieldName], $UserB[$this->SortFieldName]); 00542 } 00543 }; 00544 00545 00546 ?>