1
19

Creation of a user account

Create site18 by copying site17.

  1. /cms
    1. ...
    2. site17
    3. site18

In this chapter, we are going to program creating a new user account and sending by email a password in an attached cryptogram.

To test the result online, enter http://www.frasq.org/cms/site18 in the address bar of your navigator. Go to the identification page. Click on the link To create your personal account at the end of the page. Enter a connection name and a valid email address, check the confirmation box, type in the verification code and press Send. A password in an attached cryptogram has been emailed to the specified address. NOTE: In this demonstration version, the account isn't created.

Start by creating the action newuser by adding the file newuser.php in the folder actions with the following content:

  1. /cms/site18
    1. actions
      1. newuser.php
  1. function newuser($lang) {
  2.     head('title', translate('newuser:title', $lang));
  3.     head('description', false);
  4.     head('keywords', false);
  5.     head('robots', 'noindex, nofollow');
  6.  
  7.     $banner = build('banner', $lang);
  8.  
  9.     $register = build('register', $lang);
  10.  
  11.     $content = view('newuser', $lang, compact('register'));
  12.  
  13.     $output = layout('standard', compact('banner', 'content'));
  14.  
  15.     return $output;
  16. }

The newuser action returns a page with a simple banner and a form built by the register block.

To give access to the newuser action, add an alias for each language in the file includes/aliases.inc:

  1.         'nouvel-utilisateur'    => 'newuser',
  1.         'new-user'              => 'newuser',

Add the title for the page for sending a password in the file includes/strings.inc:

In English in the 'en' array:

  1.         'newuser:title'         => 'Registration',

In French in the 'fr' array:

  1.         'newuser:title'         => 'Inscription',

Add the view for the page for creating a new account in the folders views/en for the English version and views/fr for the version in French:

  1. /cms/site18
    1. views
      1. en
        1. newuser.phtml
      2. fr
        1. newuser.phtml
  1. <h3>New account</h3>
  2. <?php echo $register; ?>
  1. <h3>Création d'un compte</h3>
  2. <?php echo $register; ?>

The form for creating a new account is in a block. Start by writing the view, first in one language:

  1. /cms/site18
    1. views
      1. en
        1. newuser.phtml
        2. register.phtml
  1. <div class="form">
  2. <form action="" method="post">
  3. <input type="hidden" name="register_token" value="<?php echo $token; ?>" />
  4. <div class="fields">
  5. <?php if ($account_created): ?>
  6. <?php if (!empty($name)): ?>
  7. <p class="right"><img src="<?php echo $base_path; ?>/avatars/<?php echo $name; ?>.png" title="<?php echo $name; ?>" /></p>
  8. <?php endif; ?>
  9. <?php endif; ?>
  10. <p class="label">What connection name do you want?</p>
  11. <p class="input"><input type="text" name="register_name" id="register_name" size="20" maxlength="20" title="Identifier" onkeypress="return focusonenter(event, 'register_code')" value="<?php echo htmlspecialchars($name, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  12. <p class="info">Choose a pseudo with between 2 and 20 letters.</p>
  13. <p class="label">What is your email address?</p>
  14. <p class="input"><input type="text" name="register_mail" id="register_mail" size="50" maxlength="100" title="Email" onkeypress="return focusonenter(event, 'register_code')" value="<?php echo htmlspecialchars($mail, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  15. <p class="info">Your password will be sent at this address.</p>
  16. <p class="input"><input name="register_confirmed" id="register_confirmed" type="checkbox" title="Confirmation" <?php if ($confirmed) echo 'checked="checked"'; ?> />&nbsp;I wish to create an account</p>
  17. <?php if ($with_captcha): ?>
  18. <p class="input">
  19. <img src="<?php echo $base_path; ?>/captcha/register" alt="" title="Verification code" />
  20. &nbsp;:&nbsp;
  21. <input type="text" name="register_code" id="register_code" size="4" maxlength="4" title="4 letters" onkeypress="return submitonenter(event, 'register_register')" value="" />
  22. </p>
  23. <?php endif; ?>
  24. <p class="submit"><button type="submit" name="register_register" id="register_register">Send</button></p>
  25. </div>
  26. </form>

The form has 4 input fields: identifier, email, confirmation and verification code. Apart from $token, 3 variables are necessary: $name, $mail and $confirmed. The parameter $with_captcha specifies if a captcha is displayed. All the field names are prefixed with register_. The form has only one button called register_register.

The rest of the view deals with the error and the information messages. The possible errors are $missing_code, $bad_code, $missing_name, $bad_name, $missing_mail, $bad_mail, $missing_confirmation, $duplicated_name, $duplicated_mail, $internal_error and $contact_page. If $account_created is true, the user is notified that his password has been sent to him at his email address and a link to the identification page $user_page is shown.

  1. <?php
  2. if ($errors):
  3. extract($errors);
  4. ?>
  5. <div class="error">
  6. <?php if ($missing_code): ?>
  7. <p>Enter the verification code displayed in the image.</p>
  8. <?php elseif ($bad_code): ?>
  9. <p>The verification code is incorrect.</p>
  10. <?php endif; ?>
  11. <?php if ($missing_name): ?>
  12. <p>You haven't typed your identifier.</p>
  13. <?php elseif ($bad_name): ?>
  14. <p>An identifier must contain between 2 and 20 letters.</p>
  15. <?php endif; ?>
  16. <?php if ($missing_mail): ?>
  17. <p>Don't forget your email address.</p>
  18. <?php elseif ($bad_mail): ?>
  19. <p>The email address is invalid.</p>
  20. <?php endif; ?>
  21. <?php if ($missing_confirmation): ?>
  22. <p>Check the confirmation box.</p>
  23. <?php endif; ?>
  24. <?php if ($duplicated_name): ?>
  25. <p>This identifier is already taken.</p>
  26. <?php endif; ?>
  27. <?php if ($duplicated_mail): ?>
  28. <p>This email address is already being used.</p>
  29. <?php endif; ?>
  30. <?php if ($internal_error): ?>
  31. <p>An internal error has occurred. If you can describe the problem, please <a href="<?php echo $contact_page; ?>">contact us</a>.</p>
  32. <?php endif; ?>
  33. </div>
  34. <?php endif; ?>
  35. <?php if ($infos):
  36. extract($infos);
  37. ?>
  38. <div class="infos">
  39. <?php if ($account_created): ?>
  40. <p>Your account has been created. Your password has been emailed to your address.<br />
  41. To identify yourself, <a href="<?php echo $user_page; ?>">click here</a>.</p>
  42. <?php endif; ?>
  43. </div>
  44. <?php endif; ?>
  45. </div>

To validate the view, write a first version of the function register which is limited to displaying the form:

  1. /cms/site18
    1. blocks
      1. register.php
  1. require_once 'tokenid.php';
  2.  
  3. function register($lang) {
  4.     $name=$mail=$confirmed=$code=$token=false;
  5.  
  6.     $missing_code=false;
  7.     $bad_code=false;
  8.  
  9.     $bad_token=false;
  10.  
  11.     $missing_name=false;
  12.     $bad_name=false;
  13.     $missing_mail=false;
  14.     $bad_mail=false;
  15.     $missing_confirmation=false;
  16.  
  17.     $duplicated_name=false;
  18.     $duplicated_mail=false;
  19.  
  20.     $account_created=false;
  21.     $user_page=false;
  22.  
  23.     $internal_error=false;
  24.     $contact_page=false;
  25.  
  26.     $with_captcha=true;
  27.  
  28.     $_SESSION['register_token'] = $token = token_id();
  29.  
  30.     $errors = compact('missing_name', 'bad_name', 'missing_mail', 'bad_mail', 'missing_confirmation', 'missing_code', 'bad_code', 'duplicated_name', 'duplicated_mail', 'internal_error', 'contact_page');
  31.     $infos = compact('user_page');
  32.  
  33.     $output = view('register', $lang, compact('token', 'with_captcha', 'name', 'mail', 'confirmed', 'account_created', 'errors', 'infos'));
  34.  
  35.     return $output;
  36. }

Enter http://localhost/cms/site18/en/new-user in the address bar of your navigator. Edit the remindme function. Assign values to all the input field variables. Set all the error variables to true. Check the links to the contact page and to the identification page.

Add the view in French:

  1. /cms/site18
    1. views
      1. fr
        1. newuser.phtml
        2. register.phtml
  1. <div class="form">
  2. <form action="" method="post">
  3. <input type="hidden" name="register_token" value="<?php echo $token; ?>" />
  4. <div class="fields">
  5. <?php if ($account_created): ?>
  6. <?php if (!empty($name)): ?>
  7. <p class="right"><img src="<?php echo $base_path; ?>/avatars/<?php echo $name; ?>.png" title="<?php echo $name; ?>" /></p>
  8. <?php endif; ?>
  9. <?php endif; ?>
  10. <p class="label">Quel nom de connexion voulez-vous ?</p>
  11. <p class="input"><input type="text" name="register_name" id="register_name" size="20" maxlength="20" title="Identifiant" onkeypress="return focusonenter(event, 'register_mail')" value="<?php echo htmlspecialchars($name, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  12. <p class="info">Choisissez un pseudo de 2 à 20 lettres.</p>
  13. <p class="label">Quelle est votre adresse d'email ?</p>
  14. <p class="input"><input type="text" name="register_mail" id="register_mail" size="50" maxlength="100" title="Email" onkeypress="return focusonenter(event, 'register_code')" value="<?php echo htmlspecialchars($mail, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  15. <p class="info">Votre mot de passe sera envoyé à cette adresse.</p>
  16. <p class="label"><input type="checkbox" name="register_confirmed" id="register_confirmed" title="Confirmation" <?php if ($confirmed) echo 'checked="checked"'; ?> onkeypress="return focusonenter(event, 'register_code')"/>&nbsp;Je souhaite créer un compte</p>
  17. <?php if ($with_captcha): ?>
  18. <p class="input">
  19. <img src="<?php echo $base_path; ?>/captcha/register" alt="" title="Code de vérification" />
  20. &nbsp;:&nbsp;
  21. <input type="text" name="register_code" id="register_code" size="4" maxlength="4" title="4 lettres" onkeypress="return submitonenter(event, 'register_register')" value="" />
  22. </p>
  23. <?php endif; ?>
  24. <p class="submit"><button type="submit" name="register_register" id="register_register">Envoyer</button></p>
  25. </div>
  26. </form>
  27. <?php
  28. if ($errors):
  29. extract($errors);
  30. ?>
  31. <div class="errors">
  32. <?php if ($missing_code): ?>
  33. <p>Entrez le code de vérification affiché dans l'image.</p>
  34. <?php elseif ($bad_code): ?>
  35. <p>Le code de vérification est incorrect.</p>
  36. <?php endif; ?>
  37. <?php if ($missing_name): ?>
  38. <p>Vous n'avez pas saisi votre identifiant.</p>
  39. <?php elseif ($bad_name): ?>
  40. <p>Un identifiant doit comporter entre 2 et 20 lettres.</p>
  41. <?php endif; ?>
  42. <?php if ($missing_mail): ?>
  43. <p>N'oubliez pas votre adresse d'email.</p>
  44. <?php elseif ($bad_mail): ?>
  45. <p>L'adresse d'email est invalide.</p>
  46. <?php endif; ?>
  47. <?php if ($missing_confirmation): ?>
  48. <p>Cochez la case de confirmation.</p>
  49. <?php endif; ?>
  50. <?php if ($duplicated_name): ?>
  51. <p>Cet identifiant est déjà pris.</p>
  52. <?php endif; ?>
  53. <?php if ($duplicated_mail): ?>
  54. <p>Cette adresse d'email est déjà utilisée.</p>
  55. <?php endif; ?>
  56. <?php if ($internal_error): ?>
  57. <p>Une erreur interne s'est produite. Si vous pouvez décrire le problème, merci de <a href="<?php echo $contact_page; ?>">nous contacter</a>.
  58. <?php endif; ?>
  59. </div>
  60. <?php endif; ?>
  61. <?php if ($infos):
  62. extract($infos);
  63. ?>
  64. <div class="infos">
  65. <?php if ($account_created): ?>
  66. <p>Votre compte a bien été créé. Le mot de passe a été envoyé par email à votre adresse.<br />
  67. Pour vous identifier, <a href="<?php echo $user_page; ?>">cliquez ici</a>.</p>
  68. <?php endif; ?>
  69. </div>
  70. <?php endif; ?>
  71. </div>

Enter http://localhost/cms/site18/fr/nouvel-utilisateur in the address bar of your navigator to validate the French version.

Once the views are tuned, complete register with the following code:

  1. require_once 'readarg.php';
  2. require_once 'strflat.php';
  3. require_once 'validateusername.php';
  4. require_once 'validatemail.php';
  5. require_once 'isusernameallowed.php';
  6. require_once 'ismailallowed.php';
  7. require_once 'tokenid.php';

Loads the functions readarg, strflat, validate_user_name, validate_mail, is_user_name_allowed, is_mail_allowed and token_id.

  1. function register($lang) {
  2.     $action='init';
  3.     if (isset($_POST['register_register'])) {
  4.         $action='register';
  5.     }
  6.  
  7.     $name=$mail=$confirmed=$code=$token=false;
  8.  
  9.     switch($action) {
  10.         case 'register':
  11.             if (isset($_POST['register_name'])) {
  12.                 $name=strtolower(strflat(readarg($_POST['register_name'], true)));
  13.             }
  14.             if (isset($_POST['register_mail'])) {
  15.                 $mail=strtolower(strflat(readarg($_POST['register_mail'], true)));
  16.             }
  17.             if (isset($_POST['register_confirmed'])) {
  18.                 $confirmed=$_POST['register_confirmed'] ? true : false;
  19.             }
  20.             if (isset($_POST['register_code'])) {
  21.                 $code=readarg($_POST['register_code'], true);
  22.             }
  23.             if (isset($_POST['register_token'])) {
  24.                 $token=readarg($_POST['register_token']);
  25.             }
  26.             break;
  27.         default:
  28.             break;
  29.     }

Reads the form.

  1.     $missing_code=false;
  2.     $bad_code=false;
  3.  
  4.     $bad_token=false;
  5.  
  6.     $missing_name=false;
  7.     $bad_name=false;
  8.     $missing_mail=false;
  9.     $bad_mail=false;
  10.     $missing_confirmation=false;
  11.  
  12.     $duplicated_name=false;
  13.     $duplicated_mail=false;
  14.  
  15.     $account_created=false;
  16.     $user_page=false;
  17.  
  18.     $internal_error=false;
  19.     $contact_page=false;
  20.  
  21.     $with_captcha=true;
  22.  
  23.     switch($action) {
  24.         case 'register':
  25.             if (!isset($_SESSION['register_token']) or $token != $_SESSION['register_token']) {
  26.                 $bad_token=true;
  27.                 break;
  28.             }
  29.  
  30.             if ($with_captcha) {
  31.                 if (!$code) {
  32.                     $missing_code=true;
  33.                     break;
  34.                 }
  35.                 $captcha=isset($_SESSION['captcha']) ? $_SESSION['captcha'] : false;
  36.                 if (!$captcha or $captcha != strtoupper($code)) {
  37.                     $bad_code=true;
  38.                     break;
  39.                 }
  40.             }
  41.  
  42.             if (!$name) {
  43.                 $missing_name=true;
  44.             }
  45.             else if (!validate_user_name($name) or !is_user_name_allowed($name)) {
  46.                 $bad_name=true;
  47.             }
  48.             if (!$mail) {
  49.                 $missing_mail=true;
  50.             }
  51.             else if (!validate_mail($mail) or !is_mail_allowed($mail)) {
  52.                 $bad_mail=true;
  53.             }
  54.             if (!$confirmed) {
  55.                 $missing_confirmation=true;
  56.             }
  57.  
  58.             break;
  59.         default:
  60.             break;
  61.     }

Controls all the input data, particularly if the connection name and the mail address are valid and allowed. Verifies if the confirmation box is checked.

  1.     switch($action) {
  2.         case 'register':
  3.             if ($bad_token or $missing_code or $bad_code or $missing_name or $bad_name or $missing_mail or $bad_mail or $missing_confirmation) {
  4.                 break;
  5.             }
  6.  
  7.             require_once 'newpassword.php';
  8.  
  9.             $password=newpassword();
  10.  
  11.             require_once 'models/user.inc';
  12.  
  13.             $r = user_check_name($name);
  14.  
  15.             if (!$r) {
  16.                 $duplicated_name=true;
  17.                 break;
  18.             }
  19.  
  20.             $r = user_check_mail($mail);
  21.  
  22.             if (!$r) {
  23.                 $duplicated_mail=true;
  24.                 break;
  25.             }
  26.  
  27.             $r = user_create($name, $password, $mail);
  28.  
  29.             if (!$r) {
  30.                 $contact_page=url('contact', $lang);
  31.                 $internal_error=true;
  32.                 break;
  33.             }
  34.  
  35.             require_once 'emailcrypto.php';
  36.  
  37.             global $sitename, $webmaster;
  38.  
  39.             $to=$mail;
  40.  
  41.             $subject = translate('email:new_user_subject', $lang);
  42.             $msg = translate('email:new_user_text', $lang) . "\n\n" . translate('email:salutations', $lang);
  43.             if (!emailcrypto($msg, $password, $to, $subject, $webmaster)) {
  44.                 $contact_page=url('contact', $lang);
  45.                 $internal_error=true;
  46.                 break;
  47.             }
  48.  
  49.             require_once 'emailme.php';
  50.  
  51.             $timestamp=strftime('%d-%m-%Y %H:%M:%S', time());
  52.             $subject = 'frasq.org:new_account.';
  53.             $msg = $timestamp . ' ' . $lang . ' ' . $name . ' ' . $mail;
  54.             emailme($subject, $msg);
  55.  
  56.             $account_created=true;
  57.             $confirmed=false;
  58.  
  59.             break;
  60.         default:
  61.             break;
  62.     }

Checks if an error has been detected, generates a new password with newpassword, loads the model user.inc and checks that the name and the email address are not already taken with user_check_name and user_check_mail. After the account is created, an email is sent with emailcrypto to the new user with his password attached in a cryptogram. Finally, the information about the account creation is notified by email to the webmaster with emailme.

  1.     if ($internal_error) {
  2.         $contact_page=url('contact', $lang);
  3.     }
  4.     else if ($account_created) {
  5.         $user_page=url('user', $lang);
  6.     }
  7.  
  8.     $_SESSION['register_token'] = $token = token_id();
  9.  
  10.     $errors = compact('missing_name', 'bad_name', 'missing_mail', 'bad_mail', 'missing_confirmation', 'missing_code', 'bad_code', 'duplicated_name', 'duplicated_mail', 'internal_error', 'contact_page');
  11.     $infos = compact('user_page');
  12.  
  13.     $output = view('register', $lang, compact('token', 'with_captcha', 'name', 'mail', 'confirmed', 'account_created', 'errors', 'infos'));
  14.  
  15.     return $output;
  16. }

The rest of the code prepares all the parameters of the view, including the token which is memorized in the session variable $_SESSION['register_token'], generates it and returns its content.

Define the subject and the text of the email by adding the parameters email:new_user_subject and email:new_user_text in the file includes/strings.inc, in English and in French:

  1.         'email:new_user_subject'        => 'frasq.org : Your account.',
  2.         'email:new_user_text'           => "Welcome!\n\nYour password is in the attached cryptogram.",
  1.         'email:new_user_subject'        => 'frasq.org : Votre compte.',
  2.         'email:new_user_text'           => "Bienvenue !\n\nVotre mot de passe est dans le cryptogramme en pièce jointe.",

Edit the file user.inc in the folder models and add the following functions:

  1. function user_check_name($name) {
  2.     $sqlname=db_sql_arg($name, true);
  3.  
  4.     $tabuser=db_prefix_table('user');
  5.  
  6.     $sql="SELECT user_id FROM $tabuser WHERE name=$sqlname LIMIT 1";
  7.  
  8.     $r = db_query($sql);
  9.  
  10.     return $r ? false : true;
  11. }

user_check_name returns false if $name is a connection name which is already taken, true if $name is available.

  1. function user_check_mail($mail) {
  2.     $sqlmail=db_sql_arg($mail, true);
  3.  
  4.     $tabuser=db_prefix_table('user');
  5.  
  6.     $sql="SELECT user_id FROM $tabuser WHERE mail=$sqlmail LIMIT 1";
  7.  
  8.     $r = db_query($sql);
  9.  
  10.     return $r ? false : true;
  11. }

user_check_mail returns false if $mail is an email address which is already being used, true if $mail is free.

  1. define('AVATAR_SIZE', 40);
  2. define('AVATARS_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'avatars');
  3.  
  4. function user_create_avatar($name) {
  5.     require_once 'identicon.php';
  6.  
  7.     $img=identicon($name, AVATAR_SIZE);
  8.  
  9.     $r = imagepng($img, AVATARS_DIR . DIRECTORY_SEPARATOR . $name . '.png');
  10.  
  11.     return $r;
  12. }
  13.  
  14. function user_delete_avatar($name) {
  15.     @unlink(AVATARS_DIR . DIRECTORY_SEPARATOR . $name . '.png');
  16. }

user_create_avatar creates an icon of AVATAR_SIZE pixels for the connection name $name and places it in the folder AVATAR_DIR at the root of the site.

user_delete_avatar deletes the file $name in the folder AVATAR_DIR at the root of the site.

  1. function user_create($name, $password, $mail, $locale='fr') {
  2.     $sqlname=db_sql_arg($name, true);
  3.     $sqlmail=db_sql_arg($mail, true);
  4.     $sqllocale=db_sql_arg($locale);
  5.  
  6.     $sqlpassword=$password ? '\'' . md5($password) . '\'' : NULL;
  7.  
  8.     $tabuser=db_prefix_table('user');
  9.  
  10.     $sql="INSERT IGNORE $tabuser (name, password, mail, created, locale) VALUES ($sqlname, $sqlpassword, $sqlmail, NOW(), $sqllocale)";
  11.  
  12.     $r = db_insert($sql);
  13.  
  14.     if (!$r) {
  15.         return false;
  16.     }
  17.  
  18.     $user_id = db_insert_id();
  19.  
  20.     user_create_avatar($name);
  21.  
  22.     return $user_id;
  23. }

user_create creates the user $name with the password $password, the email address $mail and the language $locale, then its avatar. user_create returns the user number or false in case of error.

Add a link to the page for creating a new account in the view of the identification page:

  1. <p class="info link">To create your personal account, <a href="<?php echo $newuser_page; ?>">click here</a>.</p>
  1. <p class="info link">Pour créer votre compte personnel, <a href="<?php echo $newuser_page; ?>">cliquez ici</a>.</p>

Assign the URL of the page for creating a new account to the variable $newuser_page of the views in the login function:

  1.     $newuser_page=url('newuser', $lang);
  2.  
  3.     $output = view('login', $lang, compact('token', 'with_captcha', 'password_page', 'newuser_page', 'login', 'errors'));

Enter http://localhost/cms/site18 in the address bar of your navigator. Go to the identification page. Click on the link To create your personal account. Enter a connection name and your email address, check the confirmation box, type the verification code and press Send. Read your email. Identify yourself with your connection name and the attached password.

Comments

To add a comment, click here.