php التسجيل و تفعيل العضوية عبر البريد الإلكتروني

php التسجيل و تفعيل العضوية عبر البريد الإلكتروني

بتاريخ: 11-11-2014   

هل سبق لكم أن فتحتم حسابا لكم على أحد المواقع المشهورة ؟ كمواقع التواصل الإجتماعي مثلا . هل تذكرون كيف تم تفعيل عضويتكم ؟
في أغلب المواقع ، عندما تقومون بملأ استمارة التسجيل و إرسالها ، لن يتم تفعيل عضويتكم على الفور بدل ذلك تحصلون على رسالة تخبركم أن تسجيلكم قد تم بنجاح ، لكن لتفعيله يجب أن تنقروا على رابط تم إرساله إلى بريدكم الإلكتروني .
هذه الطريقة لتفعيل العضوية هي الأكثر استعمالا حاليا ، لأنها من جهة تحمينا من السبام "spam" و من جهة أخرى نكون متأكدين بأن العضو استعمل بريده الإلكتروني الصحيح .

كيف يتم تفعيل العضوية عبر البريد الإلكتروني ؟

هذا هو محور موضوعنا ، سنقوم بإنشاء نظام لتسجيل و تفعيل الأعضاء وفق التسلسل التالي :

  1. يقوم العضو بملأ استمارة التسجيل و إرسالها
  2. نقوم بمعالجة استمارة التسجيل ، ثم نُنشيء شيفرة فريدة ، نخزّنها في حقل مستقل مع باقي البيانات في القاعدة
  3. و في الوقت نفسه نرسل رابطا إلى بريده الإلكتروني . هذا الرابط سيضم الشيفرة السابقة بحيث ستمكنه من تفعيل عضويته
  4. لتفعيل العضوية ، وجب على العضو فتح علبة بريده الإلكتروني ، و البحث عن الرسالة التي أرسلناها إليه ، ثم النقر على الرابط المعني

    بمجرد نقره على الرابط ، سيتم تفعيل عضويته
  5. يمكنه الآن الولوج إلى حسابه متى شاء و ذلك بملأ استمارة الدخول

الصفحات التي سنحتاجها

لإنشاء هذا النظام ، سنحتاج لجدول في قاعدة البيانات و بعض الصفحات

  • site_members : إنشاء جدول للأعضاء في قاعدة البيانات
  • registration.php : إنشاء صفحة تضم استمارة لتسجيل الأعضاء الجدد
  • registration-confirm.php : إنشاء صفحة لمعالجة بيانات استمارة التسجيل
  • activate.php : إنشاء صفحة لتفعيل العضوية
  • connexion.php : إنشاء صفحة تضم استمارة الدخول
  • connexion-confirm.php : إنشاء صفحة لمعالجة بيانات استمارة الدخول

ربط الإتصال بقاعدة البيانات

أولا قبل كل شيء يجب ربط الإتصال بقاعدة البيانات

<?php
try 
{
  $db = new PDO('mysql:host=$hostname;dbname=$dbname;charset=utf8', $user, $password);
} 
catch(PDOException $e)
{
  die('خطأ:'. $e->getMessage());
}
?>

سأضع هذه الشيفرة في صفحة مستقلة "db-connection.php" داخل ملف سميته "includes" و سنقوم بإقحامها كلما دعت الضرورة
غيروا قيم ربط الإتصال حسب توضيبكم : ($hostname, $dbname, $user, $password)

هذا الدرس موجه للمواقع التي تمت استضافتها . إذا أردتم استعمال الخادوم المحلي "localhost" يجب أن تعدلوا ملف "php.ini" لتتمكنوا من إرسال الرسائل

إنشاء جدول الأعضاء : site_members

CREATE TABLE IF NOT EXISTS `site_members` (
  `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_name` varchar(40) NOT NULL,
  `user_email` varchar(70) NOT NULL,
  `user_password` varchar(255) NOT NULL,
  `activation_code` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

تسجيل الأعضاء

سنحتاج لصفحتين : صفحة تضم استمارة التسجيل و صفحة لمعالجة بيانات الإستمارة
registration.php

<!DOCTYPE html>
<html dir='rtl'>
<head>
  <meta charset='utf-8'>
  <style>
   label {display: inline-block;width:120px;margin-top:1px;}
  </style>
</head>
<body>
  <h1>استمارة التسجيل</h1>
  <form method="post" action="registration-confirm.php">
    <label for="pseudo">الإسم</label><input  type="text" name="pseudo" id="pseudo" required><br>
    <label for="email">البريد الإلكتروني</label><input type="email" name="email" id="email" required><br>
    <label for="password">كلمة المرور</label><input type="password" name="password" id="password" required><br>
    <label for="password_confirm">تأكيد كلمة المرور</label><input type="password" name="password_confirm" id="password_confirm" required><br>

      <p><input type="submit" name="submitted" value="موافق" ></p>
  </form>
</body>
</html>

registration-confirm.php
سنعالج في هذه الصفحة بيانات الإستمارة . إذا كانت صحيحة نقوم بإنشاء شيفرة فريدة باستعمال دالة php md5() . بهذا ستكون هذه الشيفرة مختلفة من عضو لآخر . ثم سنُخزّنها مع باقي البيانات في القاعدة و في الوقت نفسه سنرسلها عبر البريد الإلكتروني للعضو المعني .
لإرسال الرسالة إلى البريد الإلكتروني للعضو ، سنستعمل الدالة mail()
للتأكد من البيانات التي أرسلها العضو سنقتصر على :

  • التأكد من أن العضو قام بملأ جميع حقول الإستمارة
  • التأكد من صحة البريد الإلكتروني
  • التأكد من أن كلمة المرور و تأكيد كلمة المرور متطابقتين
  • التأكد من أن إسم المستخدم فريدا و لم يتم استعماله من طرف شخص آخر
  • التأكد من أن البريد الإلكتروني فريدا و لم يتم استعماله من طرف شخص آخر
<?php
include 'includes/db-connection.php';
// عنوان ملف موقعكم الذي سيضم صفحة تفعيل العضوية
DEFINE('WEBSITE_URL', 'http://mywebsite.com'); 
// تعيين وقت إرسال الرسالة
date_default_timezone_set('UTC');

if (isset($_POST['submitted'])) {

  $error = array(); // تعيين جدول لجمع الأخطاء

  if (empty($_POST['pseudo'])) { //إذا كان حقل الإسم فارغا
    //إضافة خطأ للجدول
    $error[] = 'المرجو ملأ حقل إسم المستخدم '; 
  } else {
    $user = $_POST['pseudo']; //إنشاء متغير للإسم
  }

  if (empty($_POST['email'])) {
    $error[] = 'المرجو ملأ حقل البريد الإلكتروني';
  } else {
    if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
      $error[] = "! عذرا ، البريد الإلكتروني غير صحيح";
    } else {
      $email = $_POST['email'];
    }
  }

  if (empty($_POST['password'])) {
    $error[] = 'المرجو ملأ حقل كلمة المرور ';
  } else {
    $password = $_POST['password'];
  }
  if (empty($_POST['password_confirm'])) {
    $error[] = 'المرجو ملأ حقل تأكيد كلمة المرور ';
  } else {
    $password_confirm = $_POST['password_confirm'];
  }

  if (!empty($_POST['password']) AND !empty($_POST['password_confirm'])) {
    if ($_POST['password'] != $_POST['password_confirm'] ) {
      $error[] = 'حقلي كلمة المرور و تأكيد كلمة المرور غير متطابقين';
    }
  }
 // التأكد بأن العضو لم يستعمل إسما أو بريدا إلكترونيا موجودين مسبقا في القاعدة
  $response = $db->prepare('SELECT user_name, user_email
            FROM site_members
           ');
  $response->execute();
  $members = $response->fetchALL();
  $response->CloseCursor();

  if (!empty($_POST['pseudo']) AND !empty($_POST['email'])) {
    foreach ($members as $member) {
      if ($_POST['pseudo'] == $member['user_name']) {
        $error[] = 'المرجو تغيير إسم المستخدم . هذا الإسم موجود مسبقا';
      }
      if ($_POST['email'] == $member['user_email']) {
        $error[] = 'المرجو تغيير العنوان الإلكتروني ، هذا البريد موجود مسبقا';
      }
    }
  }

   /* إذا لم نسجل أي خطأ ، نرسل البيانات إلى القاعدة 
    ** و نرسل رسالة إلى بريد العضو تتضمن رابطا يضم شيفرة لتفعيل عضويته
	*/
  if (empty($error))
  {
    // تعيين شيفرة تفعيل العضوية 
    $activation = md5(uniqid(rand(), true));
    // تخزين البيانات في القاعدة 
    $stmt= $db->prepare('INSERT INTO site_members (user_name, user_email, user_password, activation_code) 
              VALUES (:name, :mail, :pass, :act)
            ');
    $stmt->bindValue(':name',$user,PDO::PARAM_STR);
    $stmt->bindValue(':mail',$email,PDO::PARAM_STR);
    $stmt->bindValue(':pass',$password,PDO::PARAM_STR);
    $stmt->bindValue(':act',$activation,PDO::PARAM_STR);
    $stmt->execute();

    $stmt->CloseCursor();
    // بعد تخزين البيانات ، نرسل رسالة إلى البريد الإلكتروني للعضو
	
    // عنوان الرسالة
    $subject ='Activation Code';
    // رأس الرسالة
    $header = "From: \"Admin\"<admin@mail.com> \n";
    $header.= "Reply-to: \"Admin\" <admin@mail.com> \n";
    $header.= "MIME-Version: 1.0 \n";	
   // محتوى الرسالة يتضمن رابط تفعيل العضوية
    $message = " لتفعيل عضويتك المرجو النقر على الرابط أسفله أو نقله و نسخه على متصفحك:\n\n";
    $message .= WEBSITE_URL . '/activate.php?email=' . urlencode($email) . "&key=$activation";
   // إرسال الرسالة إلى بريد العضو
    mail($email, $subject, $message, $header);

    // إنهاء الصفحة
    echo '<div class="success">شكرا على تسجيلك .
      لقد تم إرسال رسالة إلى بريدك الإلكتروني 
          <br>' . $email .
        '<br> تتضمن رابطا المرجو منك النقر عليه لتفعيل عضويتك  </div>';
		
 } else { // أو نقوم بعرض الأخطاء الناجمة
       echo '<div> <ol>';
       foreach ($error as $key => $values) {
          echo '  <li>' . $values . '</li>';
       }
       echo '</ol></div>';
   }

}else {echo '<p>المرجو ملأ الإستمارة</p>';}
?>
بالنسبة لكلمة المرور ، قمنا بتخزينها بالواضح ، لأنه ليست موضوعنا حاليا . لمعرفة كيف يتم حمايتها و تشفيرها المرجو الإطلاع على فحوى هذا الدرس تشفير كلمة المرور باستعمال bcrypt

تفعيل العضوية

لتفعيل العضوية ، بعدما أن قام العضو بالنقر على الرابط الموجود في بريده الإلكتروني . كما لاحظتم ، هذا الرابط يحتوي على عنوان البريد الإلكتروني للعضو و شيفرة التفعيل . سنقوم بمقارنتهما بالبيانات الموجودة في القاعدة ، إن كانتا متطابقتين ، سنُحيّن حقل "activation_code" و نعطيه قيمة : "NULL" .
activate.php

<?php 
include 'includes/db-connection.php';

if (isset($_GET['email']) AND filter_var($_GET['email'], FILTER_VALIDATE_EMAIL)) {
   $email = $_GET['email'];
}
/* MD5 إذا استعملتم تشفيرا آخر غير تشفير 
  في صفحة التسجيل ، يجب أن تغيروا القيمة 32 حسب عدد مكونات النص
  للتشفير الذي اعتمدتموه 
*/
if (isset($_GET['key']) AND (strlen($_GET['key']) == 32))
{
    $key = $_GET['key'];
}
	 
if (isset($email) AND isset($key)) {
    // تحيين جدول الأعضاء و محو شيفرة التفعيل للعضو المعني
    $stmt= $db->prepare('UPDATE site_members 
            SET activation_code = NULL
            WHERE user_email = :mail AND activation_code = :code
           ');
    $stmt->bindValue(':mail',$email,PDO::PARAM_STR);
    $stmt->bindValue(':code',$key,PDO::PARAM_STR);
    $stmt->execute();
    $stmt->CloseCursor();

    if ($stmt->rowCount() == 1){
       echo '<p>تم تفعيل عضويتك بنجاح ، للولوج إلى حسابك ، المرجو ملأ استمارة الدخول <br>
	   <a href="connexion.php">الدخول</a></p>';
    } else{
       echo 'وقع خطأ أثناء تفعيل العضوية . المرجو الإتصال بمدير الموقع';
    }
} else {
 echo '<div>خطأ غير متوقع</div>';
}
?>

الدخول أو ربط الإتصال

لإتاحة الأعضاء الولوج إلىى حساباتهم سنحتاج إلى صفحتين :

  • connexion.php : صفحة تضم استمارة الدخول
  • connexion-confirm.php : صفحة لمعالجة استمارة الدخول

connexion.php
يمكننا الإعتماد إما على إسم العضو أو بريده الإلكتروني لتمكين العضو الولوج إلى حسابه .

<!DOCTYPE html>
<html dir='rtl'>
<head>
  <meta charset='utf-8'>
  <style>
   label {display: inline-block;width:120px;margin-top:1px;}
  </style>
</head>
<body>
  <h1>استمارة الدخول</h1>
  <form method="post" action="connexion-confirm.php">
    <label for="pseudo">الإسم</label><input  type="text" name="pseudo" id="pseudo" required><br>
    <label for="password">كلمة المرور</label><input type="password" name="password" id="password" required><br>
    <p><input type="submit" name="submitted" value="موافق" ></p>
  </form>
</body>
</html>

connexion-confirm.php
لربط الإتصال بنجاح ، يجب أن يكون حقل "activation_code" يساوي "NULL"

<?php
session_start();
include 'includes/db-connection.php';

if (isset($_POST['submitted'])) {

  $error = array(); // تعيين جدول لجمع الأخطاء
  
  if (empty($_POST['pseudo'])) { //إذا كان حقل الإسم فارغا
    //إضافة خطأ للجدول
    $error[] = 'المرجو ملأ حقل إسم المستخدم '; 
  } else {
    $user = $_POST['pseudo']; //إنشاء متغير للإسم
  }

  if (empty($_POST['password'])) {
    $error[] = 'المرجو ملأ حقل كلمة المرور ';
  } else {
    $password = $_POST['password'];
  }   
 
  if (empty($error))
  {
    // أخذ البيانات من القاعدة اعتمادا على إسم العضو و كلمة مروره 
    // و عضويته يجب أن تكون مفعلة

    $response = $db->prepare('SELECT user_id, user_name
            FROM site_members
            WHERE user_name = :nom 
            AND user_password = :pass 
            AND activation_code IS NULL
           ');
    $response->bindValue(':nom',$user,PDO::PARAM_STR);
    $response->bindValue(':pass',$password,PDO::PARAM_STR);
    $response->execute();
    $member = $response->fetch();
    $response->CloseCursor();

    if(!$member) {
      echo 'البيانات غير صحيحة أو العضو غير مُفعّل';
    } else {
	  // تعيين متغيرات الجلسة
      $_SESSION['id'] = $member['user_id'];
      $_SESSION['user'] = $member['user_name'];
         // عرض رسالة ربط الإتصال بنجاح أو تحويله تلقائيا إلى صفحة أخرى
	  echo '<p> مرحبا بك  :
	        <b>'.htmlspecialchars($_SESSION['user']).'</b></p>';
    }	
	
  } else { // أو نقوم بعرض الأخطاء الناجمة
       echo '<div> <ol>';
       foreach ($error as $key => $values) {
       echo '  <li>' . $values . '</li>';
    }
       echo '</ol></div>';
    }
} else { 
   echo '<p>المرجو ملأ الإستمارة</p>';
}
?>