2
211

Identification des utilisateurs

Créez site14 en copiant site13.

  1. /cms
    1. ...
    2. site13
    3. site14

Dans ce chapitre, nous allons ajouter un formulaire permettant d'authentifier les utilisateurs.

Pour tester le résultat en ligne, entrez http://www.frasq.org/cms/site14 dans la barre d'adresse de votre navigateur. Dans le bandeau de la page d'accueil, cliquez sur l'icône qui montre un couple d'utilisateurs. Remplissez le formulaire avec foobar pour le nom et f00bar pour le mot de passe. Entrez le code de vérification. Appuyez sur Entrée. Cliquez sur l'icône rouge avec une croix dans le bandeau de la page d'accueil ou de la page de contact pour vous déconnecter.

Commencez par créer les actions user et nobody en ajoutant les fichiers user.php et nobody.php dans le dossier actions avec les contenus suivants :

  1. /cms/site14
    1. actions
      1. user.php
      2. nobody.php
  1. function user($lang) {
  2.     $login = build('login', $lang);
  3.     if (true === $login) {
  4.         $next_page = url('home', $lang);
  5.  
  6.         header("Location: $next_page");
  7.         return false;
  8.     }
  9.  
  10.     $banner = build('banner', $lang);
  11.     $content = view('user', $lang, compact('login'));
  12.  
  13.     head('title', translate('user:title', $lang));
  14.     head('description', false);
  15.     head('keywords', false);
  16.     head('robots', 'noindex, nofollow');
  17.  
  18.     $output = layout('standard', compact('banner', 'content'));
  19.  
  20.     return $output;
  21. }

L'action user commence par construire le bloc du formulaire. login retourne true si l'exécution du formulaire a connecté l'utilisateur auquel cas user renvoie à la page d'accueil.

Notez que la page d'identification n'a pas de description ni de mots clés et que les moteurs de recherche ne doivent pas l'indexer ni suivre les liens qu'elle contient.

  1. function nobody($lang) {
  2.     unset($_SESSION['user']);
  3.  
  4.     $next_page=url('home', $lang);
  5.     header("Location: $next_page");
  6.  
  7.     return false;
  8. }

L'action nobody déconnecte l'utilisateur et renvoie à la page d'accueil.

Pour donner accès aux actions user et nobody, ajoutez dans le fichier includes/aliases.inc un alias par langue pour chaque action :

  1.         'utilisateur'           => 'user',
  2.         'deconnexion'           => 'nobody',
  1.         'user'                  => 'user',
  2.         'disconnect'            => 'nobody',

Ajoutez le titre de la page d'identification dans le fichier includes/strings.inc.

En français dans le tableau 'fr' :

  1.         'user:title'            => 'Identification',

En anglais dans le tableau 'en' :

  1.         'user:title'            => 'Identification',

Ajoutez la vue de la page d'identification dans les dossiers views/fr pour la version en français et views/en pour la version en anglais.

  1. /cms/site14
    1. views
      1. fr
        1. user.phtml
      2. en
        1. user.phtml
  1. <h3>Accès privilégié</h3>
  2. <?php echo $login; ?>
  1. <h3>Privileged access</h3>
  2. <?php echo $login; ?>

Le formulaire d'identification d'un utilisateur est dans un bloc. Commencez par écrire la vue, d'abord dans une langue :

  1. /cms/site14
    1. views
      1. fr
        1. user.phtml
        2. login.phtml
  1. <div class="form">
  2. <form action="" method="post">
  3. <input type="hidden" name="login_token" value="<?php echo $token; ?>" />
  4. <div class="fields">
  5. <p class="label">Quel est votre nom de connexion ?</p>
  6. <p class="input"><input type="text" name="login_login" id="login_login" size="40" maxlength="100" title="Identifiant" onkeypress="return focusonenter(event, 'login_password')" value="<?php echo htmlspecialchars($login, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  7. <p class="info">Vous pouvez aussi entrer votre adresse d'email.</p>
  8. <p class="label">Et votre clé d'accès ?</p>
  9. <p class="input"><input type="password" name="login_password" id="login_password" size="20" maxlength="20" title="Mot de passe" onkeypress="return focusonenter(event, 'login_code')" /></p>
  10. <?php if ($with_captcha): ?>
  11. <p class="input">
  12. <img src="<?php echo $base_path; ?>/captcha" alt="" title="Code de vérification" />
  13. &nbsp;:&nbsp;
  14. <input type="text" name="login_code" id="login_code" size="4" maxlength="4" title="4 lettres" onkeypress="return submitonenter(event, 'login_enter')" value="" />
  15. </p>
  16. <?php endif; ?>
  17. <p class="submit"><button type="submit" name="login_enter" id="login_enter">Entrer</button></p>
  18. </div>
  19. </form>

Le formulaire comprend 3 champs de saisie : identifiant, mot de passe et code de vérification. En plus de $token, 1 variable est nécessaire : $login. Le paramètre $captcha détermine si un captcha est affiché. Tous les noms des champs sont préfixés par login_. Le formulaire a un seul bouton appelé login_enter.

Le reste de la vue gère tous les messages d'erreur. Les erreurs possibles sont $missing_code, $bad_code, $missing_login, $missing_password, $bad_login, $bad_password et $access_denied.

  1. <?php if ($errors):
  2. extract($errors);
  3. ?>
  4. <div class="errors">
  5. <?php if ($missing_code): ?>
  6. <p>Entrez le code de vérification affiché dans l'image.</p>
  7. <?php elseif ($bad_code): ?>
  8. <p>Le code de vérification est incorrect.</p>
  9. <?php endif; ?>
  10. <?php if ($missing_login or $missing_password): ?>
  11. <p>Entrez votre identifiant et votre mot de passe.</p>
  12. <?php elseif ($bad_login): ?>
  13. <p>L'identifiant est invalide.</p>
  14. <?php elseif ($bad_password): ?>
  15. <p>Le mot de passe est invalide.</p>
  16. <?php elseif ($access_denied): ?>
  17. <p>Accès refusé.</p>
  18. <?php endif; ?>
  19. </div>
  20. <?php endif; ?>
  21. </div>

Pour valider la vue, écrivez une première version de la fonction login qui se limite à l'affichage du formulaire :

  1. /cms/site14
    1. blocks
      1. login.php
  1. require_once 'tokenid.php';
  2.  
  3. function login($lang) {
  4.     $login=$password=$code=$token=false;
  5.  
  6.     $missing_code=false;
  7.     $bad_code=false;
  8.  
  9.     $bad_token=false;
  10.  
  11.     $missing_login=false;
  12.     $bad_login=false;
  13.     $missing_password=false;
  14.     $bad_password=false;
  15.     $access_denied=false;
  16.  
  17.     $with_captcha=true;
  18.  
  19.     $_SESSION['login_token'] = $token = token_id();
  20.  
  21.     $errors = compact('missing_code', 'bad_code', 'missing_login', 'bad_login', 'missing_password', 'bad_password', 'access_denied');
  22.  
  23.     $output = view('login', $lang, compact('token', 'with_captcha', 'login', 'errors'));
  24.  
  25.     return $output;
  26. }

Entrez http://localhost/cms/site14/fr/utilisateur dans la barre d'adresse de votre navigateur. Éditez la fonction login. Donnez des valeurs aux variables des champs de saisie. Mettez toutes les variables d'erreur à true.

Ajoutez la vue en anglais :

  1. /cms/site14
    1. views
      1. en
        1. user.phtml
        2. login.phtml
  1. <div class="form">
  2. <form action="" method="post">
  3. <input type="hidden" name="login_token" value="<?php echo $token; ?>" />
  4. <div class="fields">
  5. <p class="label">What is your connection name?</p>
  6. <p class="input"><input type="text" name="login_login" id="login_login" size="40" maxlength="100" title="Identifier" onkeypress="return focusonenter(event, 'login_password')" value="<?php echo htmlspecialchars($login, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  7. <p class="info">You may also enter your email address.</p>
  8. <p class="label">And your access key?</p>
  9. <p class="input"><input type="password" name="login_password" id="login_password" size="20" maxlength="20" title="Password" onkeypress="return focusonenter(event, 'login_code')" /></p>
  10. <?php if ($with_captcha): ?>
  11. <p class="input">
  12. <img src="<?php echo $base_path; ?>/captcha" alt="" title="Verification code" />
  13. &nbsp;:&nbsp;
  14. <input type="text" name="login_code" id="login_code" size="4" maxlength="4" title="4 letters" onkeypress="return submitonenter(event, 'login_enter')" value="" />
  15. </p>
  16. <?php endif; ?>
  17. <p class="submit"><button type="submit" name="login_enter" id="login_enter">Enter</button></p>
  18. </div>
  19. </form>
  20. <?php if ($errors):
  21. extract($errors);
  22. ?>
  23. <div class="errors">
  24. <?php if ($missing_code): ?>
  25. <p>Enter the verification code displayed in the image.</p>
  26. <?php elseif ($bad_code): ?>
  27. <p>The verification code is incorrect.</p>
  28. <?php endif; ?>
  29. <?php if ($missing_login or $missing_password): ?>
  30. <p>Enter your identifier and your password.</p>
  31. <?php elseif ($bad_login): ?>
  32. <p>The identifier is invalid.</p>
  33. <?php elseif ($bad_password): ?>
  34. <p>The password is invalid.</p>
  35. <?php elseif ($access_denied): ?>
  36. <p>Access denied.</p>
  37. <?php endif; ?>
  38. </div>
  39. <?php endif; ?>
  40. </div>

Entrez http://localhost/cms/site14/en/user dans la barre d'adresse de votre navigateur pour valider la version anglaise.

Une fois la mise au point des vues terminée, complétez login avec le code suivant :

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

Charge le code des fonctions readarg, strflat, validate_user_name, validate_password, validate_mail et token_id. Ajoutez les fichiers validateusername.php et validatepassword.php dans le dossier library avec les contenus suivants :

  1. /cms/site14
    1. library
      1. validateusername.php
      2. validatepassword.php
  1. function validate_user_name($name) {
  2.     return preg_match('/^[a-z]{2,20}$/', $name);
  3. }

validate_user_name retourne true si $name contient entre 2 et 20 lettres minuscules, false dans le cas contraire.

  1. function validate_password($s) {
  2.     $regexp='/(?=[a-zA-Z0-9]*?[A-Za-z])(?=[a-zA-Z0-9]*?[0-9])[a-zA-Z0-9]{6,}/';
  3.  
  4.     return preg_match($regexp, $s);
  5. }

validate_password retourne true si $password contient au moins 6 lettres minuscules ou majuscules et des chiffres avec au moins un chiffre et une lettre, false dans le cas contraire.

  1. function login($lang) {
  2.     $action='init';
  3.     if (isset($_POST['login_enter'])) {
  4.         $action='enter';
  5.     }
  6.  
  7.     $login=$password=$code=$token=false;

login commence par initialiser $action à 'enter' si l'utilisateur a appuyé sur le bouton Entrer ou à 'init' par défaut si le formulaire est juste affiché.

  1.     switch($action) {
  2.         case 'enter':
  3.             if (isset($_POST['login_login'])) {
  4.                 $login=strtolower(strflat(readarg($_POST['login_login'], true)));
  5.             }
  6.             if (isset($_POST['login_password'])) {
  7.                 $password=readarg($_POST['login_password'], true);
  8.             }
  9.             if (isset($_POST['login_code'])) {
  10.                 $code=readarg($_POST['login_code'], true);
  11.             }
  12.             if (isset($_POST['login_token'])) {
  13.                 $token=readarg($_POST['login_token']);
  14.             }
  15.             break;
  16.         default:
  17.             break;
  18.     }

Lit les champs de saisie et les filtre avec readarg. strtag retire les accents de $login qui est ensuite converti en minuscules.

  1.     $missing_code=false;
  2.     $bad_code=false;
  3.  
  4.     $bad_token=false;
  5.  
  6.     $missing_login=false;
  7.     $bad_login=false;
  8.     $missing_password=false;
  9.     $bad_password=false;
  10.     $access_denied=false;
  11.  
  12.     $with_captcha=true;

Initialise toutes les variables d'erreur avant de valider les données envoyées par le formulaire. $with_captcha opte pour l'affichage d'un captcha.

  1.     switch($action) {
  2.         case 'enter':
  3.             if (!isset($_SESSION['login_token']) or $token != $_SESSION['login_token']) {
  4.                 $bad_token=true;
  5.                 break;
  6.             }
  7.  
  8.             if ($with_captcha) {
  9.                 if (!$code) {
  10.                     $missing_code=true;
  11.                     break;
  12.                 }
  13.                 $captcha=isset($_SESSION['captcha']) ? $_SESSION['captcha'] : false;
  14.                 if (!$captcha or $captcha != strtoupper($code)) {
  15.                     $bad_code=true;
  16.                     break;
  17.                 }
  18.             }
  19.  
  20.             if (!$login) {
  21.                 $missing_login=true;
  22.             }
  23.             else if (!validate_user_name($login) and !validate_mail($login)) {
  24.                 $bad_login=true;
  25.             }
  26.             if (!$password) {
  27.                 $missing_password=true;
  28.             }
  29.             else if (!validate_password($password)) {
  30.                 $bad_password = true;
  31.             }
  32.             break;
  33.         default:
  34.             break;
  35.     }

Contrôle le jeton, vérifie si le captcha correspond si $with_captcha est true, puis valide les saisies de l'identifiant et du mot de passe.

  1.     switch($action) {
  2.         case 'enter':
  3.             if ($bad_token or $missing_code or $bad_code or $missing_login or $bad_login or $missing_password or $bad_password) {
  4.                 break;
  5.             }
  6.  
  7.             require_once 'models/user.inc';
  8.  
  9.             $user = user_login($login, $password);
  10.  
  11.             if (!$user) {
  12.                 $access_denied=true;
  13.  
  14.                 require_once 'log.php';
  15.                 write_log('enter.err', substr($login, 0, 40));
  16.  
  17.                 break;
  18.             }
  19.  
  20.             $user['ip'] = client_ip_address();
  21.             $_SESSION['user'] = $user;
  22.  
  23.             unset($_SESSION['login_token']);
  24.  
  25.             return true;
  26.  
  27.         default:
  28.             break;
  29.     }

Vérifie qu'aucune erreur n'a été détectée, charge le modèle user.inc et appelle la fonction user_login avec les paramètres $login et $password. Si user_login retourne false, l'erreur est notée dans le journal enter.err. Si l'identifiant et le mot de passe sont reconnus, les informations retournées par user_login ainsi que l'adresse IP du client sont mémorisées dans la variable de session $_SESSION['user'] et login retourne true après avoir effacé le jeton. Rappelez-vous que dans ce cas, l'action user renvoie à la page d'accueil.

  1.     $_SESSION['login_token'] = $token = token_id();
  2.  
  3.     $errors = compact('missing_code', 'bad_code', 'missing_login', 'bad_login', 'missing_password', 'bad_password', 'access_denied');
  4.  
  5.     $output = view('login', $lang, compact('token', 'with_captcha', 'login', 'errors'));
  6.  
  7.     return $output;
  8. }

Prépare tous les paramètres de la vue, dont le jeton qui est mémorisé dans la variable de session $_SESSION['login_token'], avant de générer la vue et de retourner son contenu.

Ajoutez le dossier models directement à la racine du site, puis le fichier user.inc dans models avec le contenu suivant :

  1. /cms/site14
    1. models
      1. user.inc
  1. function user_login($login, $password) {
  2.     if ( ! ($login == 'foobar' and $password == 'f00bar') ) {
  3.         return false;
  4.     }
  5.  
  6.     $now=time();
  7.  
  8.     $user = array();
  9.     $user['id'] = 0;
  10.     $user['name'] = $login;
  11.     $user['access'] = $now;
  12.  
  13.     return $user;
  14. }

user_login retourne un tableau contenant des informations sur le compte de l'utilisateur dont l'identifiant est $login et le mot de passe $password. Si l'utilisateur n'est pas reconnu, user_login retourne false. NOTE : Le modèle est pour l'instant réduit au strict minimum afin de permettre la mise au point de la page d'identification.

Entrez http://localhost/cms/site14/fr/utilisateur et http://localhost/cms/site14/en/user pour tester le formulaire en français et en anglais. Vérifiez que les contrôles sur les champs fonctionnent. Connectez-vous.

Pour accéder à la page d'identification, ajoutez un lien dans le bandeau de la page d'accueil :

  1.     $contact=$account=true;
  2.  
  3.     $banner = build('banner', $lang, compact('languages', 'contact', 'account'));

home passe 'account' à true à banner.

  1.     $menu=$login=$logout=$contact=false;
  2.     $languages=false;
  3.     $nobody_page=$contact_page=false;
  4.  
  5.     $is_identified = user_is_identified();
  6.  
  7.     if ($is_identified) {
  8.         $nobody_page=url('nobody', $lang);
  9.         $logout = true;
  10.     }
  11.  
  12.     if ($components) {
  13.         foreach ($components as $v => $param) {
  14.             switch ($v) {
  15.                 case 'account':
  16.                     if ($param) {
  17.                         if (!$is_identified) {
  18.                             $user_page=url('user', $lang);
  19.                             $login = true;
  20.                         }
  21.                     }
  22.                     break;

Dans tous les cas, si l'utilisateur est identifié, banner ajoute un lien sur la page de déconnexion. Si $components contient 'account' à true et si l'utilisateur n'est pas identifié, banner ajoute un lien sur la page d'identification.

  1.     if ($logout or $contact) {
  2.         $menu = view('bannermenu', $lang, compact('contact', 'contact_page', 'logout', 'nobody_page', 'login', 'user_page'));
  3.     }

Ajoutez le fichier userisidentified.php dans le dossier library avec le contenu suivant :

  1. /cms/site14
    1. library
      1. userisidentified.php
  1. function user_is_identified() {
  2.     return isset($_SESSION['user']);
  3. }

user_is_identified retourne true si la description de l'utilisateur est dans la session.

Ajoutez les liens dans le menu du bandeau dans les fichiers views/fr/bannermenu.phtml et views/en/bannermenu.phtml.

  1. <?php if (isset($logout) and $logout): ?>
  2. <li><a id="exit" href="<?php echo $nobody_page; ?>" title="Déconnexion"><span>Déconnexion</span></a></li>
  3. <?php endif; ?>
  4. <?php if (isset($login) and $login): ?>
  5. <li><a id="enter" href="<?php echo $user_page; ?>" title="Votre compte"><span>Compte</span></a></li>
  6. <?php endif; ?>
  1. <?php if (isset($logout) and $logout): ?>
  2. <li><a id="exit" href="<?php echo $nobody_page; ?>" title="Disconnect"><span>Disconnect</span></a></li>
  3. <?php endif; ?>
  4. <?php if (isset($login) and $login): ?>
  5. <li><a id="enter" href="<?php echo $user_page; ?>" title="Your account"><span>Account</span></a></li>
  6. <?php endif; ?>

Modifiez la feuille de style pour afficher des boutons à la place des liens :

  1. #bannermenu {width:160px;float:left;margin-top:13px;margin-left:40px;}
  2. #bannermenu #mail {width:24px;height:24px;float:right;margin-left:6px;background:transparent url(../buttons/mail.png) no-repeat center center;}
  3. #bannermenu #exit {width:24px;height:24px;float:left;margin-right:6px;background:transparent url(../buttons/cancel.png) no-repeat center center;}
  4. #bannermenu #enter {width:24px;height:24px;float:right;margin-right:6px;background:transparent url(../buttons/user.png) no-repeat center center;}

Copiez les icônes des boutons dans le dossier buttons :

  1. /cms/site14
    1. buttons
      1. cancel.png
      2. user.png

Entrez http://localhost/cms/site14 dans la barre d'adresse de votre navigateur. Allez à la page d'identification. Affichez le code source. Désactivez le CSS pour juger de la qualité du document généré. Remplissez le formulaire en validant les champs avec Entrée. Vérifiez que le bouton de déconnexion est bien affiché sur la page de contact. Déconnectez-vous.

Commentaires

Votre commentaire :
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip aide 2000

Entrez un maximum de 2000 caractères.
Améliorez la présentation de votre texte avec les balises de formatage suivantes :
[p]paragraphe[/p], [b]gras[/b], [i]italique[/i], [u]souligné[/u], [s]barré[/s], [quote]citation[/quote], [pre]tel quel[/pre], [br]à la ligne,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]commande[/code], [code=langage]code source en c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].