81

Envoyer un nouveau mot de passe par email

Créez site16 en copiant site15.

  1. /cms
    1. ...
    2. site15
    3. site16

Dans ce chapitre, nous allons programmer l'envoi à un utilisateur enregistré d'un nouveau mot de passe par email dans un cryptogramme en pièce jointe.

Votre nouveau mot de passe est dans le cryptogramme en pièce jointe.

Si vous n'avez pas demandé à en changer, veuillez ignorer ce message.
NOTE : Votre ancien mot de passe est toujours valide.

Connectez-vous avec le nouveau mot de passe pour l'activer.

À bientôt.

frasq.org - http://www.frasq.org
--------------------------------------------------------------

Commencez par créer l'action password en ajoutant le fichier password.php dans le dossier actions avec le contenu suivant :

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

L'action password retourne une page avec un bandeau simple et le formulaire construit par le bloc remindme.

Pour donner accès à l'action password, ajoutez un alias par langue dans le fichier includes/aliases.inc :

  1.         'mot-de-passe'          => 'password',
  1.         'password'              => 'password',

Ajoutez le titre de la page d'envoi d'un mot de passe dans le fichier includes/strings.inc :

En français dans le tableau 'fr' :

  1.         'password:title'        => 'Mot de passe',

En anglais dans le tableau 'en' :

  1.         'password:title'        => 'Password',

Ajoutez la vue de la page d'envoi d'un mot de passe dans les dossiers views/fr pour la version en français et views/en pour la version en anglais :

  1. /cms/site16
    1. views
      1. fr
        1. password.phtml
      2. en
        1. password.phtml
  1. <h3>Nouvelle clé d'accès</h3>
  2. <?php echo $remindme; ?>
  1. <h3>New access key</h3>
  2. <?php echo $remindme; ?>

Le formulaire d'envoi d'un mot de passe est dans un bloc. Commencez par écrire la vue, d'abord dans une langue :

  1. /cms/site16
    1. views
      1. fr
        1. password.phtml
        2. remindme.phtml
  1. <div class="form">
  2. <form action="" method="post">
  3. <input type="hidden" name="remindme_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="remindme_login" id="remindme_login" size="40" maxlength="100" title="Identifiant" onkeypress="return focusonenter(event, 'remindme_code')" 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="input"><input name="remindme_confirmed" id="remindme_confirmed" type="checkbox" title="Confirmation" <?php if ($confirmed) echo 'checked="checked"'; ?> />&nbsp;Je veux recevoir un nouveau mot de passe</p>
  9. <?php if ($with_captcha): ?>
  10. <p class="input">
  11. <img src="<?php echo $base_path; ?>/captcha/remindme" alt="" title="Code de vérification" />
  12. &nbsp;:&nbsp;
  13. <input type="text" name="remindme_code" id="remindme_code" size="4" maxlength="4" title="4 lettres" onkeypress="return submitonenter(event, 'remindme_submit')" value="" />
  14. </p>
  15. <?php endif; ?>
  16. <p class="submit"><button type="submit" name="remindme_submit" id="remindme_submit">Envoyer</button></p>
  17. </div>
  18. </form>

Le formulaire comprend 3 champs de saisie : identifiant, confirmation et code de vérification. En plus de $token, 2 variables sont nécessaires : $login et $confirmed. Le paramètre $captcha détermine si un captcha est affiché. Tous les noms des champs sont préfixés par remindme_. Le formulaire a un seul bouton appelé remindme_submit.

Le reste de la vue gère tous les messages d'erreur. Les erreurs possibles sont $missing_code, $bad_code, $missing_login, $bad_login, $missing_confirmation, $internal_error et $contact_page. Si $email_sent est true, on signale à l'utilisateur que le message a bien été envoyé et on lui propose un lien sur la page d'identification $user_page.

  1. <?php
  2. if ($errors):
  3. extract($errors);
  4. ?>
  5. <div class="errors">
  6. <?php if ($missing_code): ?>
  7. <p>Entrez le code de vérification affiché dans l'image.</p>
  8. <?php elseif ($bad_code): ?>
  9. <p>Le code de vérification est incorrect.</p>
  10. <?php endif; ?>
  11. <?php if ($missing_login): ?>
  12. <p>Vous n'avez pas saisi votre identifiant.</p>
  13. <?php elseif ($bad_login): ?>
  14. <p>L'identifiant n'est pas valide.</p>
  15. <?php endif; ?>
  16. <?php if ($missing_confirmation): ?>
  17. <p>Cochez la case de confirmation.</p>
  18. <?php endif; ?>
  19. <?php if ($internal_error): ?>
  20. <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>.
  21. <?php endif; ?>
  22. </div>
  23. <?php endif; ?>
  24. <?php
  25. if ($infos):
  26. extract($infos);
  27. ?>
  28. <div class="infos">
  29. <?php if ($email_sent): ?>
  30. <p>Un nouveau mot de passe vous a été envoyé par email.<br />
  31. Pour vous identifier, <a href="<?php echo $user_page; ?>">cliquez ici</a>.</p>
  32. <?php endif; ?>
  33. </div>
  34. <?php endif; ?>
  35. </div>

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

  1. /cms/site16
    1. blocks
      1. remindme.php
  1. require_once 'tokenid.php';
  2.  
  3. function remindme($lang, $login=false) {
  4.     $login=$confirmed=$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_confirmation=false;
  14.  
  15.     $email_sent=false;
  16.     $user_page=url('user', $lang);
  17.  
  18.     $internal_error=false;
  19.     $contact_page=false;
  20.  
  21.     $with_captcha=true;
  22.  
  23.     $_SESSION['remindme_token'] = $token = token_id();
  24.  
  25.     $errors = compact('missing_login', 'bad_login', 'missing_confirmation', 'missing_code', 'bad_code', 'internal_error', 'contact_page');
  26.     $infos = compact('email_sent', 'user_page');
  27.  
  28.     $output = view('remindme', $lang, compact('token', 'with_captcha', 'login', 'confirmed', 'errors', 'infos'));
  29.  
  30.     return $output;
  31. }

Entrez http://localhost/cms/site16/fr/mot-de-passe dans la barre d'adresse de votre navigateur. Éditez la fonction remindme. Donnez des valeurs aux variables des champs de saisie. Mettez toutes les variables d'erreur à true. Vérifiez les liens sur la page de contact et sur la page d'identification.

Ajoutez la vue en anglais :

  1. /cms/site16
    1. views
      1. en
        1. password.phtml
        2. remindme.phtml
  1. <div class="form">
  2. <form action="" method="post">
  3. <input type="hidden" name="remindme_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="remindme_login" id="remindme_login" size="40" maxlength="100" title="Identifier" onkeypress="return focusonenter(event, 'remindme_code')" 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="input"><input name="remindme_confirmed" id="remindme_confirmed" type="checkbox" title="Confirmation" <?php if ($confirmed) echo 'checked="checked"'; ?> />&nbsp;I want to receive a new password</p>
  9. <?php if ($with_captcha): ?>
  10. <p class="input">
  11. <img src="<?php echo $base_path; ?>/captcha/remindme" alt="" title="Verification code" />
  12. &nbsp;:&nbsp;
  13. <input type="text" name="remindme_code" id="remindme_code" size="4" maxlength="4" title="4 letters" onkeypress="return submitonenter(event, 'remindme_submit')" value="" />
  14. </p>
  15. <?php endif; ?>
  16. <p class="submit"><button type="submit" name="remindme_submit" id="remindme_submit">Send</button></p>
  17. </div>
  18. </form>
  19. <?php
  20. 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): ?>
  30. <p>You haven't typed your identifier.</p>
  31. <?php elseif ($bad_login): ?>
  32. <p>The identifier is not valid.</p>
  33. <?php endif; ?>
  34. <?php if ($missing_confirmation): ?>
  35. <p>Check the confirmation box.</p>
  36. <?php endif; ?>
  37. <?php if ($internal_error): ?>
  38. <p>An internal error has occurred. If you can describe the problem, please <a href="<?php echo $contact_page; ?>">contact us</a>.</p>
  39. <?php endif; ?>
  40. </div>
  41. <?php endif; ?>
  42. <?php
  43. if ($infos):
  44. extract($infos);
  45. ?>
  46. <div class="infos">
  47. <?php if ($email_sent): ?>
  48. <p>A new password has been sent to you by email.<br />
  49. To identify yourself, <a href="<?php echo $user_page; ?>">click here</a>.</p>
  50. <?php endif; ?>
  51. </div>
  52. <?php endif; ?>
  53. </div>

Entrez http://localhost/cms/site16/en/password 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 remindme avec le code suivant :

  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';

Charge le code des fonctions readarg, strflat, validate_user_name, validate_mail, is_user_name_allowed, is_mail_allowed et token_id. Ajoutez les fichiers isusernameallowed.php et ismailallowed.php dans le dossier library avec les contenus suivants :

  1. /cms/site16
    1. library
      1. isusernameallowed.php
      2. ismailallowed.php
  1. function is_user_name_allowed($name) {
  2.     static $blacklist = array('frasq');
  3.  
  4.     return !in_array($name, $blacklist);
  5. }

is_user_name_allowed retourne false si $name est un nom qui est interdit par la liste $blacknamelist, true si $name est autorisé.

  1. function is_mail_allowed($mail) {
  2.     static $blacklist = array('frasq@frasq.org', 'webmaster@frasq.org', 'keymaster@frasq.org');
  3.  
  4.     return !in_array($mail, $blacklist);
  5. }

is_mail_allowed retourne false si $mail est une adresse d'email qui est interdite par la liste $blacknamelist, true si an email à $mail est autorisé.

  1. function remindme($lang, $login=false) {
  2.     $action='init';
  3.     if (isset($_POST['remindme_submit'])) {
  4.         $action='remindme';
  5.     }
  6.  
  7.     $login=$confirmed=$code=$token=false;
  8.  
  9.     switch($action) {
  10.         case 'remindme':
  11.             if (isset($_POST['remindme_login'])) {
  12.                 $login=strtolower(strflat(readarg($_POST['remindme_login'], true)));
  13.             }
  14.             if (isset($_POST['remindme_confirmed'])) {
  15.                 $confirmed=$_POST['remindme_confirmed'] ? true : false;
  16.             }
  17.             if (isset($_POST['remindme_code'])) {
  18.                 $code=readarg($_POST['remindme_code'], true);
  19.             }
  20.             if (isset($_POST['remindme_token'])) {
  21.                 $token=readarg($_POST['remindme_token']);
  22.             }
  23.             break;
  24.         default:
  25.             break;
  26.     }

Lit le formulaire.

  1.     $missing_code=false;
  2.     $bad_code=false;
  3.  
  4.     $bad_token=false;
  5.  
  6.     $missing_login=false;
  7.     $bad_login=false;
  8.     $missing_confirmation=false;
  9.  
  10.     $email_sent=false;
  11.     $user_page=false;
  12.  
  13.     $internal_error=false;
  14.     $contact_page=false;
  15.  
  16.     $with_captcha=true;
  17.  
  18.     switch($action) {
  19.         case 'remindme':
  20.             if (!isset($_SESSION['remindme_token']) or $token != $_SESSION['remindme_token']) {
  21.                 $bad_token=true;
  22.                 break;
  23.             }
  24.  
  25.             if ($with_captcha) {
  26.                 if (!$code) {
  27.                     $missing_code=true;
  28.                     break;
  29.                 }
  30.                 $captcha=isset($_SESSION['captcha']) ? $_SESSION['captcha'] : false;
  31.                 if (!$captcha or $captcha != strtoupper($code)) {
  32.                     $bad_code=true;
  33.                     break;
  34.                 }
  35.             }
  36.  
  37.  
  38.             if (!$login) {
  39.                 $missing_login=true;
  40.             }
  41.             else if ((!validate_user_name($login) or !is_user_name_allowed($login)) and (!validate_mail($login) or !is_mail_allowed($login))) {
  42.                 $bad_login=true;
  43.             }
  44.             if (!$confirmed) {
  45.                 $missing_confirmation=true;
  46.             }
  47.             break;
  48.         default:
  49.             break;
  50.     }

Contrôle les données saisies, en particulier si le nom de connexion est autorisé.

  1.     switch($action) {
  2.         case 'remindme':
  3.             if ($bad_token or $missing_code or $bad_code or $missing_login or $bad_login or $missing_confirmation) {
  4.                 break;
  5.             }
  6.  
  7.             require_once 'models/user.inc';
  8.  
  9.             $user_id = user_find($login);
  10.  
  11.             if (!$user_id) {
  12.                 $bad_login=true;
  13.  
  14.                 require_once 'log.php';
  15.                 write_log('password.err', substr($login, 0, 40));
  16.  
  17.                 break;
  18.             }
  19.  
  20.             $user = user_get($user_id);
  21.  
  22.             if (!$user) {
  23.                 $internal_error=true;
  24.                 break;
  25.             }

Vérifie qu'aucune erreur n'a été détectée, charge le modèle user.inc et récupère le numéro de l'utilisateur avec user_find. Si user_find retourne false, l'erreur est notée dans le journal password.err. Sinon le code obtient l'adresse d'email du compte $user_id avec user_get.

  1.             require_once 'newpassword.php';
  2.  
  3.             $newpassword=newpassword();
  4.  
  5.             if (!user_set_newpassword($user_id, $newpassword)) {
  6.                 $internal_error=true;
  7.                 break;
  8.             }

Charge la fonction newpassword puis assigne un nouveau mot de passe au compte de l'utilisateur $user_id.

  1.             require_once 'emailcrypto.php';
  2.  
  3.             global $sitename, $webmaster;
  4.  
  5.             $to=$user['user_mail'];
  6.  
  7.             $subject = translate('email:new_password_subject', $lang);
  8.             $msg = translate('email:new_password_text', $lang) . "\n\n" . translate('email:salutations', $lang);
  9.             if (!emailcrypto($msg, $newpassword, $to, $subject, $webmaster)) {
  10.                 $internal_error=true;
  11.             }
  12.             else {
  13.                 $email_sent=$to;
  14.             }
  15.  
  16.             $confirmed=false;
  17.  
  18.             break;
  19.         default:
  20.             break;
  21.     }

Charge la fonction emailcrypto. Prépare le message d'email selon la langue de l'utilisateur et appelle emailcrypto avec le nouveau mot de passe, le sujet et le texte du message, l'adresse d'email du destinataire et de l'expéditeur.

  1.     if ($internal_error) {
  2.         $contact_page=url('contact', $lang);
  3.     }
  4.     else if ($email_sent) {
  5.         $user_page=url('user', $lang);
  6.     }

Met $contact_page à l'URL de la page de contact si $internal_error est true ou $user_page à l'URL de la page d'identification si $email_sent est true.

  1.     $_SESSION['remindme_token'] = $token = token_id();
  2.  
  3.     $errors = compact('missing_login', 'bad_login', 'missing_confirmation', 'missing_code', 'bad_code', 'internal_error', 'contact_page');
  4.     $infos = compact('email_sent', 'user_page');
  5.  
  6.     $output = view('remindme', $lang, compact('token', 'with_captcha', 'login', 'confirmed', 'errors', 'infos'));
  7.  
  8.     return $output;
  9. }

Le reste du code prépare tous les paramètres de la vue, dont le jeton qui est mémorisé dans la variable de session $_SESSION['remindme_token'], la génère et retourne son contenu.

Définissez les textes du sujet et du message en ajoutant les paramètres email:salutations, email:new_password_subject et email:new_password_text dans le fichier includes/strings.inc, en français et en anglais :

  1.         'email:salutations'             => 'À bientôt.',
  2.         'email:new_password_subject'    => 'frasq.org : Votre mot de passe.',
  3.         'email:new_password_text'       => "Votre nouveau mot de passe est dans le cryptogramme en pièce jointe.\n\nSi vous n'avez pas demandé à en changer, veuillez ignorer ce message.\nNOTE : Votre ancien mot de passe est toujours valide.\n\nConnectez-vous avec le nouveau mot de passe pour l'activer.",
  1.         'email:salutations'             => 'See you soon.',
  2.         'email:new_password_subject'    => 'frasq.org : Your new password.',
  3.         'email:new_password_text'       => "Your new password is in the attached cryptogram.\n\nIf you didn't ask to change it, just ignore this message.\nNOTE: Your old password is still valid.\n\nIdentify yourself with the new password to activate it.",

Ajoutez les fichiers newpassword.php et emailcrypto.php dans le dossier library avec les contenus suivants :

  1. /cms/site16
    1. library
      1. newpassword.php
      2. emailcrypto.php
  1. require_once 'strrand.php';
  2.  
  3. function newpassword($len=6) {
  4.     $charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  5.  
  6.     return strrand($charset, $len);
  7. }

newpassword retourne 6 caractères majuscules ou chiffres aléatoires.

La signature, le mailer et l'adresse de retour de l'email sont des variables globales définies dans le fichier includes/config.inc :

  1. global $sitename, $webmaster, $mailer;
  2.  
  3. $sitename = 'frasq.org';
  4. $webmaster = 'nobody@frasq.org';
  5. $mailer = 'Frasq';
  6.  
  7. global $signature;
  8.  
  9. $signature='frasq.org - http://www.frasq.org';
  1. require_once 'strtag.php';
  2.  
  3. function emailcrypto($text, $tag, $to, $subject, $sender) {
  4.     global $signature, $mailer, $webmaster;

emailcrypto envoie le message $text avec en pièce jointe un cryptogramme de $tag à $to avec le sujet $subject de la part de $sender.

  1.     $img=strtag($tag);
  2.  
  3.     ob_start();
  4.     imagepng($img);
  5.     imagedestroy($img);
  6.     $imgdata=ob_get_contents();
  7.     ob_end_clean();
  8.  
  9.     $sep=md5(uniqid('sep'));
  10.     $data=chunk_split(base64_encode($imgdata));

Fabrique un cryptogramme à partir de la chaine de caractères $tag avec strtag puis convertit l'image obtenue en PNG. Le PNG est ensuite encodé en base64.

  1.     $headers = <<<_SEP_
  2. From: $sender
  3. Return-Path: $webmaster
  4. Content-Type: multipart/mixed; boundary="$sep"
  5. X-Mailer: $mailer
  6. _SEP_;

Génère l'en-tête MIME de l'email avec les champs From:, Return-Path:, Content-Type: et X-Mailer: avec le paramètre $sender et les variables globales $webmaster et $mailer. Le champ Content-Type: indique que le message est constitué de 2 parties, le texte de l'email et le cryptogramme en pièce jointe, séparées par $sep.

  1.     $body = '';
  2.  
  3.     if ($text) {
  4.         $body .= <<<_SEP_
  5. --$sep
  6. Content-Type: text/plain; charset=utf-8
  7.  
  8. $text
  9.  
  10. $signature
  11.  
  12. _SEP_;
  13.     }
  14.  
  15.     $body .= <<<_SEP_
  16. --$sep
  17. Content-Type: image/png; name="crypto.png"
  18. Content-Transfer-Encoding: base64
  19. Content-Disposition: inline; filename="crypto.png"
  20.  
  21. $data
  22. --$sep--
  23. _SEP_;
  24.  
  25.     return @mail($to, $subject, $body, $headers);
  26. }

Fabrique le corps de l'email, d'abord le texte puis l'image en pièce jointe, puis envoie l'email avec la fonction PHP mail.

Ajoutez une colonne dans la table user pour mémoriser le nouveau mot de passe :

mysql> ALTER TABLE user ADD newpassword VARCHAR( 32 ) NULL AFTER password;

Éditez le fichier user.inc dans le dossier models/user.inc et ajoutez la fonction user_set_newpassword :

  1. function user_set_newpassword($user_id, $password) {
  2.     if (!is_numeric($user_id)) {
  3.         return false;
  4.     }
  5.  
  6.     $sqlnewpassword=$password ? '\'' . md5($password) . '\'' : NULL;
  7.  
  8.     $tabuser=db_prefix_table('user');
  9.  
  10.     $sql="UPDATE $tabuser SET newpassword=$sqlnewpassword WHERE user_id=$user_id LIMIT 1";
  11.  
  12.     $r = db_update($sql);
  13.  
  14.     return $r;
  15. }

Modifiez la fonction user_get pour retourner le champ user_password :

  1.     $sql="SELECT name AS user_name, password AS user_password, newpassword AS user_newpassword, mail AS user_mail, UNIX_TIMESTAMP(created) AS user_created, UNIX_TIMESTAMP(access) AS user_access, locale AS user_locale, active AS user_active, banned AS user_banned FROM $tabuser WHERE user_id=$user_id LIMIT 1";

Modifiez la fonction user_login pour prendre en compte un éventuel nouveau mot de passe :

  1.     if ($user_newpassword) {
  2.         if ($password == $user_newpassword) {
  3.             // use the new one
  4.             $sql="UPDATE $tabuser SET access=FROM_UNIXTIME($now), password='$user_newpassword', newpassword=NULL WHERE user_id=$user_id LIMIT 1";
  5.         }
  6.         else {
  7.             // keep the old one
  8.             $sql="UPDATE $tabuser SET access=FROM_UNIXTIME($now), newpassword=NULL WHERE user_id=$user_id LIMIT 1";
  9.         }
  10.     }
  11.     else {
  12.         // just keep track
  13.         $sql="UPDATE $tabuser SET access=FROM_UNIXTIME($now) WHERE user_id=$user_id LIMIT 1";
  14.     }
  15.  
  16.     db_update($sql);

Si un nouveau mot de passe a été défini et si le mot de passe donné est le nouveau mot de passe, user_login remplace l'ancien mot de passe avec le nouveau, sinon, l'ancien est conservé. Le nouveau mot de passe est toujours effacé. Dans tous les cas, user_login note la date et l'heure de la connexion.

Ajoutez un lien sur la page d'envoi d'un nouveau mot de passe dans la vue de la page d'identification :

  1. <p class="info link">Si vous avez oublié votre mot de passe, <a href="<?php echo $password_page; ?>">cliquez ici</a>.</p>
  1. <p class="info link">If you have forgotten your password, <a href="<?php echo $password_page; ?>">click here</a>.</p>

Assignez l'URL de la page d'envoi d'un mot de passe à la variable $password_page des vues dans la fonction login :

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

Assurez-vous que l'adresse d'email du compte foobar est bien foobar@localnet.net. Entrez http://localhost/cms/site16 dans la barre d'adresse de votre navigateur. Allez sur la page d'identification. Cliquez sur le lien Si vous avez oublié votre mot de passe. Entrez foobar comme nom, cochez la case de confirmation, tapez le code de vérification et appuyez sur Envoyer. Lisez le courrier de foobar. Essayez de vous identifier avec le nouveau mot de passe. Déconnectez-vous. Redemandez un nouveau mot de passe. Identifiez-vous avec l'ancien mot de passe qui est toujours valide.

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].