CWIS Developer Documentation
UserFactory.php
Go to the documentation of this file.
1 <?PHP
2 
3 #
4 # Axis--UserFactory.php
5 # An Meta-Object for Handling User Information
6 #
7 # Copyright 2003-2012 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 (ealmasy@axisdata.com)
13 #
14 # Part of the AxisPHP library v1.2.4
15 # For more information see http://www.axisdata.com/AxisPHP/
16 #
17 
19 {
20 
21  # ---- PUBLIC INTERFACE --------------------------------------------------
22 
26  public function __construct()
27  {
28  # create database connection
29  $this->DB = new Database();
30 
31  # figure out user class name
32  $this->UserClassName = preg_replace(
33  '/Factory$/', '', get_called_class());
34  }
35 
48  public function CreateNewUser(
49  $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain,
50  $IgnoreErrorCodes = NULL)
51  {
52  # check incoming values
53  $ErrorCodes = $this->TestNewUserValues(
54  $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain);
55 
56  # discard any errors we are supposed to ignore
57  if ($IgnoreErrorCodes)
58  {
59  $ErrorCodes = array_diff($ErrorCodes, $IgnoreErrorCodes);
60  }
61 
62  # if error found in incoming values return error codes to caller
63  if (count($ErrorCodes)) { return $ErrorCodes; }
64 
65  # add user to database
66  $UserClass = $this->UserClassName;
67  $UserName = $UserClass::NormalizeUserName($UserName);
68  $this->DB->Query("INSERT INTO APUsers"
69  ." (UserName, CreationDate)"
70  ." VALUES ('".addslashes($UserName)."', NOW())");
71 
72  # create new user object
73  $UserId = $this->DB->LastInsertId();
74  $User = new User($this->DB, (int)$UserId);
75 
76  # if new user object creation failed return error code to caller
77  if ($User->Status() != U_OKAY) { return array($User->Status()); }
78 
79  # set password and e-mail address
80  $User->SetPassword($Password);
81  $User->Set("EMail", $EMail);
82 
83  # return new user object to caller
84  return $User;
85  }
86 
96  public function TestNewUserValues(
97  $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain)
98  {
99  $UserClass = $this->UserClassName;
100 
101  # normalize incoming values
102  $UserName = $UserClass::NormalizeUserName($UserName);
103  $Password = $UserClass::NormalizePassword($Password);
104  $PasswordAgain = $UserClass::NormalizePassword($PasswordAgain);
105  $EMail = $UserClass::NormalizeEMailAddress($EMail);
106  $EMailAgain = $UserClass::NormalizeEMailAddress($EMailAgain);
107 
108  # start off assuming success
109  $ErrorCodes = array();
110 
111  # check that provided username is valid
112  if (strlen($UserName) == 0)
113  {
114  $ErrorCodes[] = U_EMPTYUSERNAME;
115  }
116  elseif (!$UserClass::IsValidUserName($UserName))
117  {
118  $ErrorCodes[] = U_ILLEGALUSERNAME;
119  }
120  elseif ($this->UserNameExists($UserName))
121  {
122  $ErrorCodes[] = U_DUPLICATEUSERNAME;
123  }
124 
125  # check that email is not already in use
126  if ($this->EMailAddressIsInUse($EMail))
127  {
128  $ErrorCodes[] = U_DUPLICATEEMAIL;
129  }
130 
131  # check for password problems
132  $FoundOtherPasswordError = FALSE;
133  $PasswordErrors = $UserClass::CheckPasswordForErrors(
134  $Password, $UserName, $EMail);
135 
136  # if there were problems, merge those in to our error list
137  if (count($PasswordErrors))
138  {
139  $ErrorCodes = array_merge($ErrorCodes, $PasswordErrors);
140  $FoundOtherPasswordError = TRUE;
141  }
142 
143  # check that PasswordAgain was provided
144  if (strlen($PasswordAgain) == 0)
145  {
146  $ErrorCodes[]= U_EMPTYPASSWORDAGAIN;
147  $FoundOtherPasswordError = TRUE;
148  }
149  # and that PasswordAgain matches Password
150  elseif ($Password != $PasswordAgain)
151  {
152  $ErrorCodes[] = U_PASSWORDSDONTMATCH;
153  }
154 
155  # check that provided email is valid
156  $FoundOtherEMailError = FALSE;
157  if (strlen($EMail) == 0)
158  {
159  $ErrorCodes[] = U_EMPTYEMAIL;
160  $FoundOtherEMailError = TRUE;
161  }
162  elseif (!$UserClass::IsValidLookingEMailAddress($EMail))
163  {
164  $ErrorCodes[] = U_ILLEGALEMAIL;
165  $FoundOtherEMailError = TRUE;
166  }
167 
168  if (strlen($EMailAgain) == 0)
169  {
170  $ErrorCodes[] = U_EMPTYEMAILAGAIN;
171  $FoundOtherEMailError = TRUE;
172  }
173  elseif (!$UserClass::IsValidLookingEMailAddress($EMailAgain))
174  {
175  $ErrorCodes[] = U_ILLEGALEMAILAGAIN;
176  $FoundOtherEMailError = TRUE;
177  }
178 
179  if ($FoundOtherEMailError == FALSE &&
180  $EMail != $EMailAgain)
181  {
182  $ErrorCodes[] = U_EMAILSDONTMATCH;
183  }
184 
185  return $ErrorCodes;
186  }
187 
194  public function GetUserCount($Condition = NULL)
195  {
196  return $this->DB->Query("SELECT COUNT(*) AS UserCount FROM APUsers"
197  .($Condition ? " WHERE ".$Condition : ""), "UserCount");
198  }
199 
205  public function GetMatchingUserCount()
206  {
208  }
209 
214  public function GetUserIds()
215  {
216  $this->DB->Query("SELECT UserId FROM APUsers");
217  return $this->DB->FetchColumn("UserId");
218  }
219 
226  public function GetLoggedInUsers($InactivityTimeout = 60)
227  {
228  # query IDs of logged-in users from database
229  $LoggedInCutoffTime = date("Y-m-d H:i:s",
230  time() - ($InactivityTimeout * 60));
231  $this->DB->Query("SELECT UserId FROM APUsers"
232  ." WHERE LastActiveDate > '".$LoggedInCutoffTime."'"
233  ." AND LoggedIn != '0'");
234  $UserIds = $this->DB->FetchColumn("UserId");
235 
236  # load array of logged in users
237  $ReturnValue = array();
238  foreach ($UserIds as $Id)
239  {
240  $ReturnValue[$Id] = new User(intval($Id));
241  }
242 
243  # return array of user data to caller
244  return $ReturnValue;
245  }
246 
254  public function GetRecentlyLoggedInUsers($Since = NULL, $Limit = 10)
255  {
256  # get users recently logged in during the last 24 hours if no date given
257  if ($Since === NULL)
258  {
259  $Date = date("Y-m-d H:i:s", time() - (24 * 60 * 60));
260  }
261 
262  else
263  {
264  $Date = date("Y-m-d H:i:s", strtotime($Since));
265  }
266 
267  # query for the users who were logged in since the given date
268  $this->DB->Query("SELECT UserId FROM APUsers"
269  ." WHERE LastActiveDate > '".$Date."'"
270  ." AND LoggedIn != '1'"
271  ." ORDER BY LastActiveDate DESC"
272  ." LIMIT ".intval($Limit));
273  $UserIds = $this->DB->FetchColumn("UserId");
274 
275  $ReturnValue = array();
276  foreach ($UserIds as $Id)
277  {
278  $ReturnValue[$Id] = new User(intval($Id));
279  }
280 
281  # return array of user data to caller
282  return $ReturnValue;
283  }
284 
291  public function GetUsersWithPrivileges()
292  {
293  # retrieve privileges
294  $Args = func_get_args();
295  if (is_array(reset($Args))) { $Args = reset($Args); }
296  $Privs = array();
297  foreach ($Args as $Arg)
298  {
299  if (is_array($Args))
300  {
301  $Privs = array_merge($Privs, $Args);
302  }
303  else
304  {
305  $Privs[] = $Arg;
306  }
307  }
308 
309  # start with query string that will return all users
310  $QueryString = "SELECT DISTINCT APUsers.UserId, UserName FROM APUsers"
311  .(count($Privs) ? ", APUserPrivileges" : "");
312 
313  # for each specified privilege
314  foreach ($Privs as $Index => $Priv)
315  {
316  # add condition to query string
317  $QueryString .= ($Index == 0) ? " WHERE (" : " OR";
318  $QueryString .= " APUserPrivileges.Privilege = ".$Priv;
319  }
320 
321  # close privilege condition in query string and add user ID condition
322  $QueryString.= count($Privs)
323  ? ") AND APUsers.UserId = APUserPrivileges.UserId" : "";
324 
325  # add sort by user name to query string
326  $QueryString .= " ORDER BY UserName ASC";
327 
328  # perform query
329  $this->DB->Query($QueryString);
330 
331  # copy query result into user info array
332  $Users = $this->DB->FetchColumn("UserName", "UserId");
333 
334  # return array of users to caller
335  return $Users;
336  }
337 
350  public function FindUsers($SearchString, $FieldName = "UserName",
351  $SortFieldName = "UserName", $Offset = 0, $Count = 9999999)
352  {
353  # retrieve matching user IDs
354  $UserNames = $this->FindUserNames(
355  $SearchString, $FieldName, $SortFieldName, $Offset, $Count);
356 
357  # create user objects
358  $Users = array();
359  foreach ($UserNames as $UserId => $UserName)
360  {
361  $Users[$UserId] = new User($this->DB, intval($UserId));
362  }
363 
364  # return array of user objects to caller
365  return $Users;
366  }
367 
382  public function FindUserNames($SearchString, $FieldName = "UserName",
383  $SortFieldName = "UserName", $Offset = 0, $Count = 9999999,
384  $IdExclusions = array(), $ValueExclusions = array())
385  {
386  $UserClass = $this->UserClassName;
387 
388  # construct a database query
389  $QueryString = "SELECT UserId, UserName FROM APUsers WHERE";
390 
391  # If the search string is a valid username which is shorter than the
392  # minimum word length indexed by the FTS, just do a normal
393  # equality test instead of using the index.
394  # Otherwise, FTS away.
395  $MinWordLen = $this->DB->Query(
396  "SHOW VARIABLES WHERE variable_name='ft_min_word_len'", "Value");
397  if ($UserClass::IsValidUserName($SearchString) &&
398  strlen($SearchString) < $MinWordLen )
399  {
400  $QueryString .= " UserName='".addslashes($SearchString)."'";
401  }
402  else
403  {
404  # massage search string to use AND logic
405  $Words = preg_split("/[\s]+/", trim($SearchString));
406  $NewSearchString = "";
407  $InQuotedString = FALSE;
408  foreach ($Words as $Word)
409  {
410  if ($InQuotedString == FALSE) { $NewSearchString .= "+"; }
411  if (preg_match("/^\"/", $Word)) { $InQuotedString = TRUE; }
412  if (preg_match("/\"$/", $Word)) { $InQuotedString = FALSE; }
413  $NewSearchString .= $Word." ";
414  }
415  $QueryString .= " MATCH (".$FieldName.")"
416  ." AGAINST ('".addslashes(trim($NewSearchString))."'"
417  ." IN BOOLEAN MODE)";
418  }
419 
420  # add each ID exclusion
421  foreach ($IdExclusions as $IdExclusion)
422  {
423  $QueryString .= " AND ".$this->ItemIdFieldName." != '"
424  .addslashes($IdExclusion)."' ";
425  }
426 
427  # add each value exclusion
428  foreach ($ValueExclusions as $ValueExclusion)
429  {
430  $QueryString .= " AND ".$this->ItemNameFieldName." != '"
431  .addslashes($ValueExclusion)."' ";
432  }
433 
434  $QueryString .= " ORDER BY ".$SortFieldName
435  ." LIMIT ".$Offset.", ".$Count;
436 
437  # retrieve matching user IDs
438  $this->DB->Query($QueryString);
439  $UserNames = $this->DB->FetchColumn("UserName", "UserId");
440 
441  # return names/IDs to caller
442  return $UserNames;
443  }
444 
460  public function GetMatchingUsers($SearchString, $FieldName = NULL,
461  $SortFieldName = "UserName",
462  $ResultsStartAt = 0, $ReturnNumber = NULL)
463  {
464  # start with empty array (to prevent array errors)
465  $ReturnValue = array();
466 
467  # if empty search string supplied, return nothing
468  $TrimmedSearchString = trim($SearchString);
469  if (empty($TrimmedSearchString))
470  {
471  return $ReturnValue;
472  }
473 
474  # make sure ordering is done by user name if not specified
475  $SortFieldName = empty($SortFieldName) ? "UserName" : $SortFieldName;
476 
477  # begin constructing the query
478  $Query = "SELECT * FROM APUsers";
479  $QueryOrderBy = " ORDER BY $SortFieldName";
480  $QueryLimit = empty($ReturnNumber) ? "" : " LIMIT $ResultsStartAt, $ReturnNumber";
481 
482  # the Criteria Query will be used to get the total number of results without the
483  # limit clause
484  $CriteriaQuery = $Query;
485 
486  # if specific field comparison requested
487  if (!empty($FieldName))
488  {
489  # append queries with criteria
490  $Query .= " WHERE ".$FieldName." REGEXP '".addslashes($SearchString)."'";
491  $CriteriaQuery = $Query;
492  }
493 
494  # optimize for returning all users
495  else if ($SearchString == ".*.")
496  {
497  # set field name to username - this would be the first field
498  # returned by a field to field search using the above RegExp
499  $FieldName = "UserName";
500  }
501 
502  # add order by and limit to query for optimizing
503  $Query .= $QueryOrderBy.$QueryLimit;
504 
505  # execute query...
506  $this->DB->Query($Query);
507 
508  # ...and process query return
509  while ($Record = $this->DB->FetchRow())
510  {
511  # if specific field or all users requested
512  if (!empty($FieldName))
513  {
514  # add user to return array
515  $ReturnValue[$Record["UserId"]] = $Record;
516 
517  # add matching search field to return array
518  $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FieldName;
519  }
520 
521  else
522  {
523  # for each user data field
524  foreach ($Record as $FName => $FValue)
525  {
526  # if search string appears in data field
527  if (strpos($Record[$FName], $SearchString) !== FALSE)
528  {
529  # add user to return array
530  $ReturnValue[$Record["UserId"]] = $Record;
531 
532  # add matching search field to return array
533  $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FName;
534  }
535  }
536  }
537  }
538 
539  # add matching user count
540  $this->DB->Query($CriteriaQuery);
541  $this->MatchingUserCount = $this->DB->NumRowsSelected();
542 
543  # return array of matching users to caller
544  return $ReturnValue;
545  }
546 
552  public function UserNameExists($UserName)
553  {
554  # normalize user name
555  $UserClass = $this->UserClassName;
556  $UserName = $UserClass::NormalizeUserName($UserName);
557 
558  # check whether user name is already in use
559  $NameCount = $this->DB->Query(
560  "SELECT COUNT(*) AS NameCount FROM APUsers"
561  ." WHERE UserName = '".addslashes($UserName)."'",
562  "NameCount");
563 
564  # report to caller whether name exists
565  return ($NameCount > 0) ? TRUE : FALSE;
566  }
567 
573  public function EMailAddressIsInUse($Address)
574  {
575  # normalize address
576  $UserClass = $this->UserClassName;
577  $UserName = $UserClass::NormalizeEMailAddress($Address);
578 
579  # check whether address is already in use
580  $AddressCount = $this->DB->Query(
581  "SELECT COUNT(*) AS AddressCount FROM APUsers"
582  ." WHERE EMail = '".addslashes($Address)."'",
583  "AddressCount");
584 
585  # report to caller whether address is in use
586  return ($AddressCount > 0) ? TRUE : FALSE;
587  }
588 
594  public function GetNewestUsers($Limit = 5)
595  {
596  $UserClass = $this->UserClassName;
597 
598  # assume no users will be found
599  $Users = array();
600 
601  # fetch the newest users
602  $this->DB->Query("SELECT *"
603  ." FROM APUsers"
604  ." ORDER BY CreationDate DESC"
605  ." LIMIT ".intval($Limit));
606  $UserIds = $this->DB->FetchColumn("UserId");
607 
608  # for each user id found
609  foreach ($UserIds as $UserId)
610  {
611  $Users[$UserId] = new $UserClass($UserId);
612  }
613 
614  # return the newest users
615  return $Users;
616  }
617 
618  # ---- PRIVATE INTERFACE -------------------------------------------------
619 
620  protected $DB;
621  protected $SortFieldName;
623  private $UserClassName;
624 }
const U_EMPTYUSERNAME
Definition: User.php:26
const U_ILLEGALEMAILAGAIN
Definition: User.php:32
EMailAddressIsInUse($Address)
Check whether e-mail address currently has account associated with it.
SQL database abstraction object with smart query caching.
Definition: Database.php:22
CreateNewUser($UserName, $Password, $PasswordAgain, $EMail, $EMailAgain, $IgnoreErrorCodes=NULL)
Create new user.
Definition: UserFactory.php:48
const U_EMAILSDONTMATCH
Definition: User.php:23
UserNameExists($UserName)
Check whether user name currently exists.
GetUserIds()
Get IDs for all users.
GetRecentlyLoggedInUsers($Since=NULL, $Limit=10)
Get users recently logged in.
const U_ILLEGALEMAIL
Definition: User.php:31
Definition: User.php:48
const U_EMPTYPASSWORDAGAIN
Definition: User.php:30
GetUsersWithPrivileges()
Return array of user names who have the specified privileges.
GetNewestUsers($Limit=5)
Get the users sorted by when they signed up, starting with those who signed up most recently...
GetMatchingUsers($SearchString, $FieldName=NULL, $SortFieldName="UserName", $ResultsStartAt=0, $ReturnNumber=NULL)
Return array of users who have values matching search string (in specific field if requested)...
const U_EMPTYEMAIL
Definition: User.php:33
FindUsers($SearchString, $FieldName="UserName", $SortFieldName="UserName", $Offset=0, $Count=9999999)
Get users who have values matching specified string in specified field.
const U_DUPLICATEUSERNAME
Definition: User.php:24
const U_OKAY
Definition: User.php:18
const U_EMPTYEMAILAGAIN
Definition: User.php:34
TestNewUserValues($UserName, $Password, $PasswordAgain, $EMail, $EMailAgain)
Test new user values (usually used before creating new user).
Definition: UserFactory.php:96
const U_DUPLICATEEMAIL
Definition: User.php:38
GetUserCount($Condition=NULL)
Return number of users in the system.
GetLoggedInUsers($InactivityTimeout=60)
Get users who are currently logged in (i.e.
const U_ILLEGALUSERNAME
Definition: User.php:25
__construct()
Object constructor.
Definition: UserFactory.php:26
GetMatchingUserCount()
Get total number of user that matched last GetMatchingUsers() call.
FindUserNames($SearchString, $FieldName="UserName", $SortFieldName="UserName", $Offset=0, $Count=9999999, $IdExclusions=array(), $ValueExclusions=array())
Get users who have values matching specified string in specified field.
const U_PASSWORDSDONTMATCH
Definition: User.php:22