CWIS Developer Documentation
Axis--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 
18 class UserFactory {
19 
20  # ---- PUBLIC INTERFACE --------------------------------------------------
21 
25  function UserFactory()
26  {
27  # create database connection
28  $this->DB = new Database();
29  }
30 
43  function CreateNewUser(
44  $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain,
45  $IgnoreErrorCodes = NULL)
46  {
47  # check incoming values
48  $ErrorCodes = $this->TestNewUserValues(
49  $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain);
50 
51  # discard any errors we are supposed to ignore
52  if ($IgnoreErrorCodes)
53  {
54  $ErrorCodes = array_diff($ErrorCodes, $IgnoreErrorCodes);
55  }
56 
57  # if error found in incoming values return error codes to caller
58  if (count($ErrorCodes)) { return $ErrorCodes; }
59 
60  # add user to database
61  $UserName = User::NormalizeUserName($UserName);
62  $this->DB->Query("INSERT INTO APUsers"
63  ." (UserName, CreationDate)"
64  ." VALUES ('".addslashes($UserName)."', NOW())");
65 
66  # create new user object
67  $UserId = $this->DB->LastInsertId("APUsers");
68  $User = new User($this->DB, (int)$UserId);
69 
70  # if new user object creation failed return error code to caller
71  if ($User->Status() != U_OKAY) { return array($User->Status()); }
72 
73  # set password and e-mail address
74  $User->SetPassword($Password);
75  $User->Set("EMail", $EMail);
76 
77  # return new user object to caller
78  return $User;
79  }
80 
81  # test new user creation values (returns array of error codes)
83  $UserName, $Password, $PasswordAgain, $EMail, $EMailAgain)
84  {
85  $ErrorCodes = array();
86  if (strlen(User::NormalizeUserName($UserName)) == 0)
87  { $ErrorCodes[] = U_EMPTYUSERNAME; }
88  elseif (!User::IsValidUserName($UserName))
89  { $ErrorCodes[] = U_ILLEGALUSERNAME; }
90  elseif ($this->UserNameExists($UserName))
91  { $ErrorCodes[] = U_DUPLICATEUSERNAME; }
92 
93  if ($this->EMailAddressIsInUse($EMail))
94  { $ErrorCodes[] = U_DUPLICATEEMAIL; }
95 
96  $FoundOtherPasswordError = FALSE;
97  if (strlen(User::NormalizePassword($Password)) == 0)
98  {
99  $ErrorCodes[] = U_EMPTYPASSWORD;
100  $FoundOtherPasswordError = TRUE;
101  }
102  elseif (!User::IsValidPassword($Password))
103  {
104  $ErrorCodes[] = U_ILLEGALPASSWORD;
105  $FoundOtherPasswordError = TRUE;
106  }
107 
108  if (strlen(User::NormalizePassword($PasswordAgain)) == 0)
109  {
110  $ErrorCodes[] = U_EMPTYPASSWORDAGAIN;
111  $FoundOtherPasswordError = TRUE;
112  }
113  elseif (!User::IsValidPassword($PasswordAgain))
114  {
115  $ErrorCodes[] = U_ILLEGALPASSWORDAGAIN;
116  $FoundOtherPasswordError = TRUE;
117  }
118 
119  if ($FoundOtherPasswordError == FALSE)
120  {
121  if (User::NormalizePassword($Password)
122  != User::NormalizePassword($PasswordAgain))
123  {
124  $ErrorCodes[] = U_PASSWORDSDONTMATCH;
125  }
126  }
127 
128  $FoundOtherEMailError = FALSE;
129  if (strlen(User::NormalizeEMailAddress($EMail)) == 0)
130  {
131  $ErrorCodes[] = U_EMPTYEMAIL;
132  $FoundOtherEMailError = TRUE;
133  }
134  elseif (!User::IsValidLookingEMailAddress($EMail))
135  {
136  $ErrorCodes[] = U_ILLEGALEMAIL;
137  $FoundOtherEMailError = TRUE;
138  }
139 
140  if (strlen(User::NormalizeEMailAddress($EMailAgain)) == 0)
141  {
142  $ErrorCodes[] = U_EMPTYEMAILAGAIN;
143  $FoundOtherEMailError = TRUE;
144  }
145  elseif (!User::IsValidLookingEMailAddress($EMailAgain))
146  {
147  $ErrorCodes[] = U_ILLEGALEMAILAGAIN;
148  $FoundOtherEMailError = TRUE;
149  }
150 
151  if ($FoundOtherEMailError == FALSE)
152  {
153  if (User::NormalizeEMailAddress($EMail)
154  != User::NormalizeEMailAddress($EMailAgain))
155  {
156  $ErrorCodes[] = U_EMAILSDONTMATCH;
157  }
158  }
159 
160  return $ErrorCodes;
161  }
162 
168  function GetUserCount($Condition = NULL)
169  {
170  return $this->DB->Query("SELECT COUNT(*) AS UserCount FROM APUsers"
171  .($Condition ? " WHERE ".$Condition : ""), "UserCount");
172  }
173 
174  # return total number of user that matched last GetMatchingUsers call
175  # before the return size was limited
177  {
179  }
180 
187  function GetLoggedInUsers($InactivityTimeout = 60)
188  {
189  # query IDs of logged-in users from database
190  $LoggedInCutoffTime = date("Y-m-d H:i:s",
191  time() - ($InactivityTimeout * 60));
192  $this->DB->Query("SELECT UserId FROM APUsers"
193  ." WHERE LastActiveDate > '".$LoggedInCutoffTime."'"
194  ." AND LoggedIn != '0'");
195  $UserIds = $this->DB->FetchColumn("UserId");
196 
197  # load array of logged in users
198  $ReturnValue = array();
199  foreach ($UserIds as $Id)
200  {
201  $ReturnValue[$Id] = new User(intval($Id));
202  }
203 
204  # return array of user data to caller
205  return $ReturnValue;
206  }
207 
208  # return array of users recently logged in. returns 10 users by default
209  function GetRecentlyLoggedInUsers($Since = NULL, $Limit = 10)
210  {
211  # get users recently logged in during the last 24 hours if no date given
212  if ($Since === NULL)
213  {
214  $Date = date("Y-m-d H:i:s", time() - (24 * 60 * 60));
215  }
216 
217  else
218  {
219  $Date = date("Y-m-d H:i:s", strtotime($Since));
220  }
221 
222  # query for the users who were logged in since the given date
223  $this->DB->Query("SELECT UserId FROM APUsers"
224  ." WHERE LastActiveDate > '".$Date."'"
225  ." AND LoggedIn != '1'"
226  ." ORDER BY LastActiveDate DESC"
227  ." LIMIT ".intval($Limit));
228  $UserIds = $this->DB->FetchColumn("UserId");
229 
230  $ReturnValue = array();
231  foreach ($UserIds as $Id)
232  {
233  $ReturnValue[$Id] = new User(intval($Id));
234  }
235 
236  # return array of user data to caller
237  return $ReturnValue;
238  }
239 
240  # return array of user names who have the specified privileges
241  # (array index is user IDs)
243  {
244  # start with query string that will return all users
245  $Args = func_get_args();
246  $QueryString = "SELECT DISTINCT APUsers.UserId, UserName FROM APUsers"
247  .(count($Args) ? ", APUserPrivileges" : "");
248 
249  # for each specified privilege
250  if (is_array(reset($Args))) { $Args = reset($Args); }
251  foreach ($Args as $Index => $Arg)
252  {
253  # add condition to query string
254  $QueryString .= ($Index == 0) ? " WHERE (" : " OR";
255  $QueryString .= " APUserPrivileges.Privilege = ".$Arg;
256  }
257 
258  # close privilege condition in query string and add user ID condition
259  $QueryString.= count($Args)
260  ? ") AND APUsers.UserId = APUserPrivileges.UserId" : "";
261 
262  # add sort by user name to query string
263  $QueryString .= " ORDER BY UserName ASC";
264 
265  # perform query
266  $this->DB->Query($QueryString);
267 
268  # copy query result into user info array
269  $Users = $this->DB->FetchColumn("UserName", "UserId");
270 
271  # return array of users to caller
272  return $Users;
273  }
274 
275  # return array of user objects who have values matching search string
276  # (array indexes are user IDs)
277  function FindUsers($SearchString, $FieldName = "UserName",
278  $SortFieldName = "UserName", $Offset = 0, $Count = 9999999)
279  {
280  # retrieve matching user IDs
281  $UserNames = $this->FindUserNames(
282  $SearchString, $FieldName, $SortFieldName, $Offset, $Count);
283 
284  # create user objects
285  $Users = array();
286  foreach ($UserNames as $UserId => $UserName)
287  {
288  $Users[$UserId] = new User($this->DB, intval($UserId));
289  }
290 
291  # return array of user objects to caller
292  return $Users;
293  }
294 
295  # return array of user names/IDs who have values matching search string
296  # (array indexes are user IDs, array values are user names)
297  function FindUserNames($SearchString, $FieldName = "UserName",
298  $SortFieldName = "UserName", $Offset = 0, $Count = 9999999)
299  {
300  # Construct a database query:
301  $QueryString = "SELECT UserId, UserName FROM APUsers WHERE";
302 
303  # If the search string is a valid username which is shorter than the
304  # minimum word length indexed by the FTS, just do a normal
305  # equality test instead of using the index.
306  # Otherwise, FTS away.
307  $MinWordLen = $this->DB->Query(
308  "SHOW VARIABLES WHERE variable_name='ft_min_word_len'", "Value");
309  if (User::IsValidUserName($SearchString) &&
310  strlen($SearchString) < $MinWordLen )
311  {
312  $QueryString .= " UserName='".addslashes($SearchString)."'";
313  }
314  else
315  {
316  # massage search string to use AND logic
317  $Words = preg_split("/[\s]+/", trim($SearchString));
318  $NewSearchString = "";
319  $InQuotedString = FALSE;
320  foreach ($Words as $Word)
321  {
322  if ($InQuotedString == FALSE) { $NewSearchString .= "+"; }
323  if (preg_match("/^\"/", $Word)) { $InQuotedString = TRUE; }
324  if (preg_match("/\"$/", $Word)) { $InQuotedString = FALSE; }
325  $NewSearchString .= $Word." ";
326  }
327  $QueryString .= " MATCH (".$FieldName.")"
328  ." AGAINST ('".addslashes(trim($NewSearchString))."'"
329  ." IN BOOLEAN MODE)";
330  }
331  $QueryString .= " ORDER BY ".$SortFieldName
332  ." LIMIT ".$Offset.", ".$Count;
333 
334  # retrieve matching user IDs
335  $this->DB->Query($QueryString);
336  $UserNames = $this->DB->FetchColumn("UserName", "UserId");
337 
338  # return names/IDs to caller
339  return $UserNames;
340  }
341 
342  # return array of users who have values matching search string (in specific field if requested)
343  # (search string respects POSIX-compatible regular expressions)
344  # optimization: $SearchString = ".*." and $FieldName = NULL will return all
345  # users ordered by $SortFieldName
346  function GetMatchingUsers($SearchString, $FieldName = NULL,
347  $SortFieldName = "UserName",
348  $ResultsStartAt = 0, $ReturnNumber = NULL)
349  {
350  # start with empty array (to prevent array errors)
351  $ReturnValue = array();
352 
353  # if empty search string supplied, return nothing
354  $TrimmedSearchString = trim($SearchString);
355  if (empty($TrimmedSearchString))
356  {
357  return $ReturnValue;
358  }
359 
360  # make sure ordering is done by user name if not specified
361  $SortFieldName = empty($SortFieldName) ? "UserName" : $SortFieldName;
362 
363  # begin constructing the query
364  $Query = "SELECT * FROM APUsers";
365  $QueryOrderBy = " ORDER BY $SortFieldName";
366  $QueryLimit = empty($ReturnNumber) ? "" : " LIMIT $ResultsStartAt, $ReturnNumber";
367 
368  # the Criteria Query will be used to get the total number of results without the
369  # limit clause
370  $CriteriaQuery = $Query;
371 
372  # if specific field comparison requested
373  if (!empty($FieldName))
374  {
375  # append queries with criteria
376  $Query .= " WHERE ".$FieldName." REGEXP '".addslashes($SearchString)."'";
377  $CriteriaQuery = $Query;
378  }
379 
380  # optimize for returning all users
381  else if ($SearchString == ".*.")
382  {
383  # set field name to username - this would be the first field
384  # returned by a field to field search using the above RegExp
385  $FieldName = "UserName";
386  }
387 
388  # add order by and limit to query for optimizing
389  $Query .= $QueryOrderBy.$QueryLimit;
390 
391  # execute query...
392  $this->DB->Query($Query);
393 
394  # ...and process query return
395  while ($Record = $this->DB->FetchRow())
396  {
397  # if specific field or all users requested
398  if (!empty($FieldName))
399  {
400  # add user to return array
401  $ReturnValue[$Record["UserId"]] = $Record;
402 
403  # add matching search field to return array
404  $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FieldName;
405  }
406 
407  else
408  {
409  # for each user data field
410  foreach ($Record as $FName => $FValue)
411  {
412  # if search string appears in data field
413  if (strpos($Record[$FName], $SearchString) !== FALSE)
414  {
415  # add user to return array
416  $ReturnValue[$Record["UserId"]] = $Record;
417 
418  # add matching search field to return array
419  $ReturnValue[$Record["UserId"]]["APMatchingField"] = $FName;
420  }
421  }
422  }
423  }
424 
425  # add matching user count
426  $this->DB->Query($CriteriaQuery);
427  $this->MatchingUserCount = $this->DB->NumRowsSelected();
428 
429  # return array of matching users to caller
430  return $ReturnValue;
431  }
432 
433  # check whether user name currently exists
434  function UserNameExists($UserName)
435  {
436  # normalize user name
437  $UserName = User::NormalizeUserName($UserName);
438 
439  # check whether user name is already in use
440  $NameCount = $this->DB->Query(
441  "SELECT COUNT(*) AS NameCount FROM APUsers"
442  ." WHERE UserName = '".addslashes($UserName)."'",
443  "NameCount");
444 
445  # report to caller whether name exists
446  return ($NameCount > 0);
447  }
448 
449  # check whether e-mail address currently has account associated with it
450  function EMailAddressIsInUse($Address)
451  {
452  # normalize address
453  $UserName = User::NormalizeEMailAddress($Address);
454 
455  # check whether address is already in use
456  $AddressCount = $this->DB->Query(
457  "SELECT COUNT(*) AS AddressCount FROM APUsers"
458  ." WHERE EMail = '".addslashes($Address)."'",
459  "AddressCount");
460 
461  # report to caller whether address is in use
462  return ($AddressCount > 0);
463  }
464 
470  public function GetNewestUsers($Limit = 5)
471  {
472  # assume no users will be found
473  $Users = array();
474 
475  # fetch the newest users
476  $this->DB->Query("SELECT *"
477  ." FROM APUsers"
478  ." ORDER BY CreationDate DESC"
479  ." LIMIT ".intval($Limit));
480  $UserIds = $this->DB->FetchColumn("UserId");
481 
482  # for each user id found
483  foreach ($UserIds as $UserId)
484  {
485  $Users[$UserId] = new SPTUser($UserId);
486  }
487 
488  # return the newest users
489  return $Users;
490  }
491 
492  # ---- PRIVATE INTERFACE -------------------------------------------------
493 
494  var $DB;
497 
498  # callback function for sorting users
499  function CompareUsersForSort($UserA, $UserB)
500  {
501  return strcasecmp($UserA[$this->SortFieldName], $UserB[$this->SortFieldName]);
502  }
503 
504 }