Sponsorenverwaltung - Team StarCraft e.V.
 All Data Structures Files Functions Variables
users.php
Go to the documentation of this file.
1 <?php
2  /**
3  * @file users.php
4  *
5  * @brief Handles most of the user-management tasks
6  *
7  * @details
8  * This file is under access-control!
9  *
10  * Simply calling users.php without any GET-parameters will display an overview
11  * of all the users currently known to the system. Assuming that there are users
12  * of all types (active, not yet activated and deleted) you will see three tables.
13  * One for each of the mentioned types.
14  *
15  * Given an GET-variable with name id followed by an number will display a view
16  * of the user with this id (if he exists). Therefore the script is taking the rank
17  * of the current user, the rank and the status of the selected user into account
18  * to present the appropriate view. For more details please consider reading the commented
19  * source code of this file and the source code of the four template files user_edit.tpl,
20  * user_readonly.tpl, user_selfinformation.tpl and users.tpl. You will see that it handles
21  * a number of POST-variables as well if they were set.
22  *
23  * This file depends on inc/common.php, inc/templates/users.tpl, inc/templates/user_readonly.tpl,
24  * inc/templates/user_edit.tpl and inc/templates/user_selfinformation.tpl.
25  *
26  * @copyright 2013, Team StarCraft e.V.
27  * @version 1.0.0
28  * @author Daniel Seichter
29  * @author Alexander Vorndran
30  * @date 02.07.2013
31  */
32 
33  /// @cond MAINPART
34  // include
35  include("inc/common.php");
36 
37 
38  // UserCake
39  if(!accessGranted($_SERVER['PHP_SELF'])) {
40  if (isUserLoggedIn()) {
41  exitWithErrorTemplate(array('Die angeforderte Seite ist gesperrt.'));
42  }
43  else {
44  exitWithErrorTemplateAndRedirect(array('Die angeforderte Seite ist gesperrt oder geschützt.'), 'login.php', 2);
45  }
46  }
47 
48  // present only a overview of the selected users information without any
49  // possibilities to edit any of these
50  if(isset($_GET['view']) && ctype_digit($_GET['view'])) {
51  $userId = $_GET['view'];
52  // only preceed if the user realy exists
53  if(userIdExists($userId)) {
54  // fetch the details of the user from the database
55  $userDetails = fetchUserDetails(NULL, NULL, $userId);
56 
57  // prepare the details for display
58  $details = array('userid' => $userDetails['id'],
59  'username' =>$userDetails['username'],
60  'firstname' => $userDetails['firstname'],
61  'lastname'=>$userDetails['lastname'],
62  'email' => $userDetails['email'],
63  'mobile'=>$userDetails['mobile'],
64  'title' =>$userDetails['title']
65  );
66 
67  // show the results
68  $smarty->assign('adminaccount', isAdministrator($userId));
69  $smarty->assign('active', $userDetails['active']);
70  $smarty->assign('currentUserRoot', isUserRoot());
71  $smarty->assign('currentUserAdministrator', isUserAdministrator());
72  $smarty->assign('details',$details);
73  displayTemplateWithErrorsAndSuccesses('Benutzerdetails', 'user_readonly.tpl');
74  } else {
75  // the user doesn't exist -> exit
76  exitWithErrorTemplate(array('Dieser Benutzer existiert nicht.'));
77  }
78  } else if(isset($_GET['id'])&& ctype_digit($_GET['id'])) {
79  // show details of the selected user
80  if(!userIdExists($_GET['id'])) {
81  // if the user doesn't exist redirect to the overview page
82  header("Location: users.php");
83  die();
84  }
85 
86  // the user exists extract the id
87  $userId = $_GET['id'];
88  $userdetails = fetchUserDetails(NULL, NULL, $userId);
89 
90  // check if the user wants to view his own profile or another one
91  $selfInformation = $userId == $loggedInUser->userId;
92 
93  // if the form was posted
94  if (!empty($_POST)) {
95 
96  // if the user should be deleted permanentaly
97  if(!empty($_POST['permanent'])&&($_POST['permanent']=='permanent')) {
98  // this action is only allowed for the user with the highest privileges
99  if(isUserRoot()) {
100  // the user should be deleted permanently
101  if(!empty($_POST['permanentDelete'])) {
102  // check if the user is already marked as deleted
103  if($userdetails['active']==-1) {
104  // get the userid of the user to delete
105  // it is stored into an array to be compatible with the delete-function
106  $deletions = $_POST['permanentDelete'];
107  // before the user gets deleted check if this operation is really allowed
109  // doesn't seem so
110  $errors[] = "Endgültiges Löschen derzeit deaktiviert.";
111  } else {
112  // the action is allowed
113  // try to delete the user
114  $deletionCount = deleteUsersPermanently($deletions);
115  if ($deletionCount > 0) {
116  // show a message according to the number of users deleted
117  if($deletionCount == 1) {
118  $deletionCount = "Ein";
119  }
120  $successes[] = lang("ACCOUNT_DELETIONS_SUCCESSFUL", array($deletionCount));
121  displayTemplateWithErrorsAndSuccesses('Löschen erfolgreich','nocontent.tpl');
122  header("Refresh: 3; users.php");
123  die();
124  } else {
125  if ($deletionCount === FALSE) {
126  // something went wrong with the query
127  $errors[] = lang("SQL_ERROR");
128  } else {
129  // everything is OK with the connection but this account mustn't be deleted
130  // either it's the root account or the user is still responsible for changes
131  $errors[] = "Dieses Benutzerkonto kann nicht gelöscht werden.";
132  }
133  }
134  }
135  } else {
136  $errors[] = "Nur \'gelöschte\' Benutzer können endgültig gelöscht werden.";
137  }
138  }
139  } else {
140  // The user hasn't got the sufficient privileges
141  $errors[] = "Keine Berechtigung";
142  exitWithErrorTemplateAndRedirect($errors, "users.php", 3);
143  }
144  } else {
145  // if the user should be marked as deleted
146  if (!empty($_POST['delete'])) {
147  // allow this only to the administrator
148  if (isUserAdministrator()) {
149  $deletions = $_POST['delete'];
150  // setting this to true will prevent deletion of any kind
151  if (false) {
152  $errors[] = "Löschen derzeit deaktiviert.";
153  } else {
154  $deletionCount = deleteUsers($deletions);
155  if ($deletionCount > 0) {
156  // one or principally more users were deleted successfully
157  if($deletionCount == 1) {
158  $deletionCount = "Ein";
159  }
160  $successes[] = lang("ACCOUNT_DELETIONS_SUCCESSFUL", array($deletionCount));
161  displayTemplateWithErrorsAndSuccesses('Löschen erfolgreich','nocontent.tpl');
162  header("Refresh: 3; users.php");
163  die();
164  } else {
165  if ($deletionCount === FALSE) {
166  $errors[] = lang("SQL_ERROR");
167  } else {
168  $errors[] = "Dieses Benutzerkonto kann nicht gelöscht werden.";
169  }
170  }
171  }
172  } else {
173  $errors[] = "Keine ausreichende Berechtigung für diese Aktion.";
174  }
175  }
176 
177  // Here is what happens when a user gets (un)locked or activated
178  if (isset($_POST['state'])) {
179  // this action is only allow for administrators
180  if (isUserAdministrator()) {
181  // the user should get locked
182  if ($_POST['state'] === "lock" && $userdetails['active'] <> 2) {
183  // only lock the user if it's not the root user
184  if ($userdetails['id'] <> DEFAULT_ADMIN_ACCOUNT) {
185  if (setUserLocked($userId)) {
186  $successes[] = lang("ACCOUNT_MANUALLY_LOCKED", array($userdetails['username']));
187  } else {
188  $errors[] = lang("SQL_ERROR");
189  }
190  } else {
191  // the root user cannot be locked
192  $errors[] = lang('ACCOUNT_MUSTNT_LOCK_ADMIN');
193  }
194  // the user should get unlocked
195  } else if ($_POST['state'] === "unlock" && $userdetails['active'] <> 1) {
196  if (setUserActive($userdetails['activation_token'])) {
197  // the user can log himself in again
198  $successes[] = lang("ACCOUNT_MANUALLY_UNLOCKED", array($userdetails['username']));
199  } else {
200  $errors[] = lang("SQL_ERROR");
201  }
202  // the user should get activated
203  } else if ($_POST['state'] === "activate") {
204  if (setUserActive($userdetails['activation_token'])) {
205  // the user can now login
206  $successes[] = lang("ACCOUNT_MANUALLY_ACTIVATED", array($userdetails['username']));
207  } else {
208  $errors[] = lang("SQL_ERROR");
209  }
210  }
211  } else {
212  $errors[] = "Keine ausreichende Berechtigung für diese Aktion.";
213  }
214  }
215 
216  // update username but only if it's not the main administrator
217  if(!empty($_POST['updateUsername']) && strcmp($_POST['updateUsername'], "update") == 0 && !$selfInformation) {
218  // only allow this action to users with the highest privileges
220  // check if a firstname and a lastname are given
221  if(!empty($_POST['firstname']) && !empty($_POST['lastname'])) {
222  $username = prepareNamesForUsername(prepareNameForDatabase($_POST['firstname'])).'.'.
223  prepareNamesForUsername(prepareNameForDatabase($_POST['lastname']));
224  if(!usernameExists($username)) {
225  // update only if the name doesn't match the old username
226  if(strcmp($username, $userdetails['username'])!=0) {
227  // check if the username is valid
228  if(isValidName($username)) {
229  // check if the username exists
230  if(usernameExists($username)) {
231  // if the username exists try to add 4 numbers to make him unique
232  $i = 0;
233  while(true) {
234  $i++;
235  // chose a random number between 1000 and 9999 and append it
236  $newUsername = $username.rand(1000,9999);
237  // check if the username is now unique
238  if(!usernameExists($newUsername)) {
239  // the name is unique assign the new name and return
240  $username = $newUsername;
241  break;
242  } else {
243  // the name still isn't unique
244  if($i < 50) {
245  // try again
246  continue;
247  } else {
248  // give up
249  break;
250  }
251  }
252  }
253  }
254  // Create new email-instance
255  $mail = new UserCakeMail();
256  $hooks = array(
257  "searchStrs" => array("#NEWUSERNAME#", "#OLDUSERNAME#"),
258  "subjectStrs" => array($username, $userdetails['username'])
259  );
260  // send the email only if the email is valid
261  if(hasValidMail($userdetails['id'])) {
262  // Build the template - Optional, you can just use the sendMail function instead to pass a message.
263  if (!$mail->newTemplateMsg("change-username.txt", $hooks)) {
264  $mail_failure = true;
265  } else {
266  //Send the mail. Specify users email here and subject.
267  //SendMail can have a third parementer for message if you do not wish to build a template.
268  if (!$mail->sendMail($userdetails['email'], 'Neuer Benutzername')) {
269  $mail_failure = true;
270  $errors[] = "Der Benutzer konnte nicht über die Änderung seines Benutzernames benachrichtig werden.";
271  $errors[] = "Der Benutzername wurde nicht geändert.";
272  } else {
273  if(updateUsername($userdetails['id'], $username)===FALSE) {
274  $errors[] = "Ändern des Benutzernamens fehlgeschlagen!";
275  } else {
276  $successes[] = 'Der Benutzername wurde aktualisiert.';
277  }
278  }
279  }
280  } else {
281  $errors[] = lang("ACCOUNT_INVALID_EMAIL");
282  }
283  }
284  }
285  }
286  }
287  }
288  } else {
289  // the email-address might only be changed if the username is not changed at the same time
290  if(!empty($_POST['email'])) {
291  //Update email
292  if(strcmp($userdetails['email'], $_POST['email']) != 0) {
293  $email = trim($_POST["email"]);
294 
295  //Validate email
296  if(!isValidEmail($email)) {
297  $errors[] = lang("ACCOUNT_INVALID_EMAIL");
298  }
299  else {
300  if(emailExists($email)) {
301  // there seems to be another user with the same mail-address
302  $errors[] = lang("ACCOUNT_EMAIL_IN_USE",array($email));
303  }
304  else {
305 
306  // Create new email-instance
307  $mail = new UserCakeMail();
308 
309  //Construct a unique activation token
310  $activation_token = generateActivationToken();
311 
312  // succeed only if the new token could be set
313  if(updateMailConfirmationToken($activation_token, $userdetails['username'])) {
314  //Build the activation message
315  $activation_message = lang("ACCOUNT_CHANGE_MAIL", array($websiteUrl, $activation_token));
316 
317  //Define more if you want to build larger structures
318  $hooks = array(
319  "searchStrs" => array("#CHANGE-MESSAGE#", "#ACTIVATION-KEY", "#USERNAME#"),
320  "subjectStrs" => array($activation_message, $activation_token, $userdetails['username'])
321  );
322  $mail_failure = false;
323 
324  /* Build the template - Optional, you can just use the sendMail function
325  Instead to pass a message. */
326  if (!$mail->newTemplateMsg("change-email.txt", $hooks)) {
327  $mail_failure = true;
328  } else {
329  //Send the mail. Specify users email here and subject.
330  //SendMail can have a third parementer for message if you do not wish to build a template.
331  if (!$mail->sendMail($email, 'Bestätigung der neuen E-Mail-Adresse')) {
332  $mail_failure = true;
333  $errors[] = "Die Bestätigungs-E-Mail konnte nicht versendet werden.";
334  }
335  }
336  if(!$mail_failure) {
337  if(updateEmail($userId, $email)) {
338  $successes[] = "Die E-Mail-Adresse wurde geändert. Es wurde eine Validierungs-E-Mail versand.";
339  resetValidMail($activation_token);
340  } else {
341  $errors[] = lang("SQL_ERROR");
342  setValidMail($activation_token);
343  }
344  }
345  } else {
346  $errors[] = lang('SQL_ERROR');
347  }
348  }
349  }
350  }
351  }
352  }
353 
354  if(!empty($_POST['firstname'])) {
355  // Update firstname
356  $firstname = prepareNameForDatabase($_POST['firstname']);
357  if(strcmp($userdetails['firstname'], $firstname) != 0) {
358  if (!isValidName($firstname)) {
359  $errors[] = lang('ACCOUNT_FIRST_INVALID_CHARACTERS');
360  } else {
361  if(updateFirstname($userdetails['id'], $firstname)<>FALSE) {
362  $successes[] = "Vorname wurde geändert";
363  } else {
364  $errors[] = lang('SQL_ERROR');
365  }
366  }
367  }
368  }
369 
370  if(!empty($_POST['lastname'])) {
371  // Update lastname
372  $lastname = prepareNameForDatabase($_POST['lastname']);
373  if(strcmp($userdetails['lastname'], $lastname) != 0) {
374  if (!isValidName($lastname)) {
375  $errors[] = lang('ACCOUNT_LAST_INVALID_CHARACTERS');
376  } else {
377  if(!(updateLastname($userdetails['id'], $lastname)===FALSE)) {
378  $successes[] = "Nachname wurde geändert";
379  } else {
380  $errors[] = lang('SQL_ERROR');
381  }
382  }
383  }
384  }
385 
386 
387 
388  if(!empty($_POST['mobile'])) {
389  // update the user's mobile
390  $mobile = str_replace(array('/', ' ','-'), '', trim($_POST["mobile"]));
391  if(strcmp($userdetails['mobile'], $mobile) != 0) {
392  //Validate mobile
393  if(!isValidMobile($mobile)) {
394  $errors[] = lang("ACCOUNT_INVALID_MOBILE");
395  }
396  else {
397  if(mobileExists($mobile)) {
398  $errors[] = lang("ACCOUNT_MOBILE_IN_USE",array($mobile));
399  }
400  else {
401  if(updateMobile($userId, $mobile)) {
402  $successes[] = "Handynummer wurde geändert.";
403  }
404  else {
405  $errors[] = lang("SQL_ERROR");
406  }
407  }
408  }
409  }
410  }
411 
412 
413  if(!empty($_POST['title'])) {
414  // update the title of the user
415  // replace unwanted characters and trim the input
416  $title = trim(preg_replace("|[^A-Za-z_\-\&üÜäÄöÖß/0-9\(\)\s]{1,}|", "", $_POST['title']));
417  $title = preg_replace("/\s{1,}/", " ", $title);
418  if(strcmp($title, $userdetails['title'])!=0) {
419  // encode HTML-special characters
420  $title = htmlspecialchars($title);
421  if(updateTitle($userId, $title)<>FALSE) {
422  $successes[] = "Aufgabenbereich aktualisiert";
423  } else {
424  $errors[] = lang("SQL_ERROR");
425  }
426  }
427  }
428 
429  // change the password
430  if($selfInformation&&!empty($_POST['newPassword'])) {
431  $password = trim($_POST["password"]);
432  // if no password was entered print error message
433  if(empty($password)) {
434  $errors[] = "Zum Ändern des Passwortes bitte auch das alte Passwort angeben.";
435  } else {
436  // changing the password is only allowed if the user enters his old password correctly
437  if(generateImprovedHash($password, $loggedInUser->passwordHash)==$loggedInUser->passwordHash) {
438  $password_new = $_POST["newPassword"];
439  $password_confirm = $_POST["confirmPassword"];
440  $pwdErrors = array();
441  if($password_new != "" OR $password_confirm != "") {
442  if(trim($password_new) == "") {
443  $pwdErrors[] = lang("ACCOUNT_SPECIFY_NEW_PASSWORD");
444  }
445  else if(trim($password_confirm) == "") {
446  $pwdErrors[] = lang("ACCOUNT_SPECIFY_CONFIRM_PASSWORD");
447  }
448  else if(minMaxRange(8,50,$password_new)) {
449  $pwdErrors[] = lang("ACCOUNT_NEW_PASSWORD_LENGTH",array(8,50));
450  }
451  else if($password_new != $password_confirm) {
452  $pwdErrors[] = lang("ACCOUNT_PASS_MISMATCH");
453  }
454 
455  //End data validation
456  if(count($pwdErrors) == 0) {
457  $loggedInUser->updatePassword($password_new);
458  $successes[] = lang("ACCOUNT_PASSWORD_UPDATED");
459  flagPassword($userdetails["id"], 0);
460  $smarty->assign('changePassword', false);
461  } else {
462  $errors = array_merge($pwdErrors, $errors);
463  }
464  }
465  } else {
466  $errors[] = "Das angegebene Passwort war nicht korrekt.";
467  }
468  }
469 
470  }
471 
472  // Here is what happens when the rank of a user is changed
473  if(!empty($_POST['rank'])) {
474  if($_POST['rank']==='administrator') {
475  if(!isAdministrator($userId)) {
476  // change userrank to administrator if the user isn't an admin already
477  $add = ADMIN_PERMISSION;
478  if (!(addPermission($add, $userId)>0)){
479  $errors[] = lang("SQL_ERROR");
480  } else {
481  $remove = STANDARD_PERMISSION;
482  if (!(removePermission($remove, $userId)>0)){
483  $errors[] = lang("SQL_ERROR");
484  } else {
485  $successes[] = str_replace("#username#", $userdetails['username'], "#username# ist jetzt \"Administrator\".");
486  }
487  }
488  }
489 
490  // the new rank of the user should be administrator
491  } else if($_POST['rank']==='user') {
492  if(isAdministrator($userId)) {
493  $add = STANDARD_PERMISSION;
494  if (!(addPermission($add, $userId)>0)){
495  $errors[] = lang("SQL_ERROR");
496  } else {
497  $remove = ADMIN_PERMISSION;
498  if (!(removePermission($remove, $userId)>0)){
499  $errors[] = lang("SQL_ERROR");
500  } else {
501  $successes[] = str_replace("#username#", $userdetails['username'], "#username# ist jetzt \"Benutzer\".");
502  }
503  }
504  }
505  }
506  }
507  }
508 
509  }
510 
511  // fetch userdetails
512  $userDetails = fetchUserDetails(NULL, NULL, $userId);
513 
514  $postf = ($userDetails['valid_email']==1)?' (validiert)':($userDetails['active'] == -1?'':' (nicht validiert)');
515  $userHasValidMail = ($userDetails['valid_email']==1);
516 
517  // prepare the details for display
518  $details = array('userid' => $userDetails['id'],
519  'username' =>$userDetails['username'],
520  'firstname' => $userDetails['firstname'],
521  'lastname'=>$userDetails['lastname'],
522  'email' => $userDetails['email'],
523  'validated' => $postf,
524  'mobile'=>$userDetails['mobile'],
525  'title' =>$userDetails['title']
526  );
527 
528  // show the results
529  $smarty->assign('currentUser',$userDetails['username']);
530  $smarty->assign('adminaccount', isAdministrator($userId));
531  $smarty->assign('active', $userDetails['active']);
532  $smarty->assign('validMail',$userHasValidMail);
533  $smarty->assign('currentUserRoot', isUserRoot());
534  $smarty->assign('currentUserAdministrator', isUserAdministrator());
535  $smarty->assign('details',$details);
536 
537  // the user wants to see his own data
538  if($selfInformation===TRUE) {
539  displayTemplateWithErrorsAndSuccesses('Eigene Benutzerdaten', 'user_selfinformation.tpl');
540  } else if(($userId==DEFAULT_ADMIN_ACCOUNT
541  || (isAdministrator($userId) && !isUserRoot())
542  || !isUserAdministrator())||($userDetails['active'] == -1)) {
543  // this will present the information but not changable
544  displayTemplateWithErrorsAndSuccesses('Benutzerdetails', 'user_readonly.tpl');
545  } else {
546  // the user wants to edit someone with lower privileges
547  displayTemplateWithErrorsAndSuccesses('Benutzerdetails', 'user_edit.tpl');
548  }
549 
550 
551  } else {
552  // show an overview over all users
553  // fetch the data of all users in the database
554  $userData = fetchAllUsers();
555 
556  // the information that are displayed get saved in here
557  $activeUsers = array();
558  $deletedUsers = array();
559  $newUsers = array();
560 
561  // determine if the current user is an administrator
562  $isUserAdministrator = isUserAdministrator();
563 
564  // process the list of all users for display
565  foreach ($userData as $user) {
566  // find a description for the users rank
567  $rank = (isAdministrator($user['id'])) ? (isRoot($user['id'])?'Haupt-Administrator':'Administrator') : 'Benutzer';
568 
569  // evaluate the timestamp of the last activity
570  $lastActivity = ($user['lastSignInStamp'] == 0) ? NULL : $user['lastSignInStamp'];
571 
572  // prepare the data according to the users rank
573  // split it into three different arrays
574  if($user['active']==-1) {
575  $deletedUsers[] = array('id' => $user['id'],
576  'username' => $user['username'],
577  'name' => $user['firstname'].' '.$user['lastname'],
578  'rank' => $rank,
579  'lastActivity'=> $lastActivity,
580  'status'=> 'gelöscht');
581  } else if ($user['active']==0) {
582  $newUsers[] = array('id' => $user['id'],
583  'username'=>$user['username'],
584  'name'=>$user['firstname'].' '.$user['lastname'],
585  'rank' => $rank,
586  'lastActivity'=> $user['signUpStamp'],
587  'status'=> 'nicht freigeschaltet');
588  } else {
589  $activeUsers[] = array('id' => $user['id'],
590  'username'=>$user['username'],
591  'name'=>$user['firstname'].' '.$user['lastname'],
592  'rank' => $rank,
593  'lastActivity'=> $lastActivity,
594  'status'=> ($user['active'] == 0) ? 'nicht aktiviert' : (($user['active'] == 1) ? (hasSessionTimedOut($user['id'])?'freigeschaltet':'online'): (($user['active'] == -1) ? 'gelöscht' :'gesperrt')));
595  }
596 
597  }
598 
599  // sort
600  if(isset($_GET['sort']) && ctype_digit($_GET['sort'])) {
601  $columnIdx = $_GET['sort'];
602  if(isset($_GET['dir']) && ctype_digit($_GET['dir'])) {
603  $direction = ($_GET['dir'] == 0) ? SORT_ASC : SORT_DESC;
604  kdsort($activeUsers, $columnIdx, $direction);
605  $smarty->assign('sort', array('colIdx' => $columnIdx,
606  'direction' => $_GET['dir']));
607  }
608  }
609 
610  // assign the information and display the template
611  $smarty->assign('isUserAdministrator', $isUserAdministrator);
612  $smarty->assign('users',$activeUsers);
613  $smarty->assign('deletedUsers',$deletedUsers);
614  $smarty->assign('newUsers',$newUsers);
615  displayTemplateWithErrorsAndSuccesses('Benutzerübersicht','users.tpl');
616  }
617 
618  /// @endcond
619 ?>