آموزش ساخت سيستم كاربري - ورود/عضويت بازديد ها: 1625 , پاسخ ها: 8
آموزش ساخت سيستم كاربري اين مطلب رو در راستاي آموزش ساخت سيستم وبلاگ دهي مي نويسم و بعلاوه گفتم تو يك آموزش جدا باشه تا اگه كسي فقط دنبال همين بود هم راحت بهش برسه
خيلي خلاصه مي گم
كاربر وارد سايت ميشه
بررسي مي كنيم آيا قبلا كاربر وارد سايت شده يا نه
اگر وارد شده بود يعني login كرده بود كه مشخصات مربوط به خودش رو.نشونش مي ديم و گرنه فرم ثبت نام
آموزش رو خيلي ساده و بدور از رعايت هر گونه نكات امنيتي بيان مي كنم
انشالله فرصت كنم يك تاپيك امنيت هم تو انجمن ميذارم
تعاريف رو از زبان خودم ميگم بنابراين ممكنه دقيقا برابر تعارف كتابي نباشه!
سشن در لغت يعني جلسه. وقتي ما به يك سايت مي ريم مرورگر تمام كوكي هاي ذخيره شده در اون سايت رو به برنامه تحت وب ارسال مي كنه
همين الان اگر به تنظيمات مرورگر بريد و كوكي هاي مرتبط با انجمن رو ببينيد ، مي بينيد كه يك كوكي به نام session id
داريم.البته ممكنه در برنامه نام اين كوكي رو عوض كرده باشيم پس لزوما به همين نام نيست
در واقع وقتي كه ما وارد يك سايت مي شيم ، اگر در برنامه تحت وب از سشن ها استفاده شده باشه يك جلسه جديد براي ما ايجاد ميشه و عموما در يك فولدر tmp كه در php.ini مشخص شده يك فايل براي هر كاربر ايجاد ميشه كه ما توسط شناسه سشن يا همون session id مي تونيم به اون سشن دسترسي داشته باشيم
اما فرق كوكي با سشن چيه؟
در كوكي ها تمام اطلاعات در كامپيوتر كاربر ذخيره ميشه و به راحتي قابل رويت هست و به همين خاطر اعتبار سنجي كاربر توسط كوكي ها تقريبا امري اشتباه هست
يكي از دلايلي كه وقتي وارد سايتي ميشيم و ازمون مي پرسه براي چه مدت لاگين نگه دارمتون همينه كه چون ميشه كوكي ها رو به صورت fake ايجاد كرد و دسترسي غير مجاز ايجاد كرد
البته طبيعتا اين مربوط به امنيت و ضعف در كد نويسي هست كه بحث ما نيست!
در سشن ها فقط يك شناسه كد شده در قالب يك كوكي در سمت مرورگر كاربر ذخيره ميشه و بقيه اطلاعات به صورت index در همون فايلي كه در پوشه tmp براي كاربر ايجاد شده ذخيره ميشوند
البته حتي اگر در سشن ها هم موارد امنيتي رو رعايت نكنيم با جعل شناسه جلسه ميشه امنيت سايت رو تهديد كرد ولي بررسي موارد امنيتي رو به تاپيك امنيت مي سپارم و روش هاي مقابل با اين تهديد هاي امنيتي رو در اونجا بررسي مي كنم و آموزش رو از اين كه هست پيچيده تر نمي كنم
حالا كه با مفاهيم سشن و كوكي از زبان من(!) آشنا شديد بريم سمت كد نويسي
[COLOR="Red"]تابع session_start[/COLOR] sesison_start از جمله توابعي هست كه بايد قبل از هر خروجي ايي در برنامه استفاده بشه
يعني اگر قبل از اين تابع در برنامه خروجي داشته باشيم ، تابع خطا ميده و درست اجرا نميشه
دستورات و توابع header از اين قبيل هستند.
با اينكه بحث ما نيست اما اين رو هم بد نيست كه بگم يكي از دلايل توصيه به استفاده از اديتور هاي استاندارد پي اچ پي همين هست كه اديتور هايي مثل notepad ويندوز قبل از كد php به خصوص در حال utf
معمولا يك كاراكتر اضافي و غير قابل رويت در همون اديتور ايجاد مي كنند كه وقتي برنامه رو اجزا مي كنيم و خطاهايي مانند
header already sent at line...
يا اين قبلي مواجه ميشيم
پس درست بعد از تگ php اينجوري برنامه رو آغاز مي كنيم
کد: انتخاب همه <?php session_start(); //ادامه ?>حالا كه اين تابع رو زديم پي اچ پي مي گرده ببينه آيا اين كاربر براش سشن آي دي تعريف شده؟اگه شده آيا معتبر هست يا نه.
اگر درست بود كه اطلاعات فايل ذخيره شده در پوشه tmp مطابق با اين شناسه در قالب يك آرايه پيش فرض به نام $_SESSION در برنامه قابل استفاده خواهند بود.
و در غير اين صورت يك شناسه معتبر به كاربر تعلق مي گيره و يك جلسه جديد براي كاربر ايجاد ميشه
[COLOR="Red"]تابع isset[/COLOR] اين تابع ربطي به سشن ها نداره! با اين تابع مي تونيم بفهمين آيا يك متغير تعريف شده يا نه
برنامه زير رو ببنيد:
index.php
کد: انتخاب همه <?php session_start(); if(isset($_SESSION['username'])) echo "welcome, ".$_SESSION['username']; else echo "Please Login/register"; ?>در خط سوم گفتم اگر در آرايه $_SESSION ايندكسي به اسم username كه يك اسم دلخواه و انتخابي توسط خودم هست؛وجود داشت يعني كاربر وارد شده و در غير اينصوت به كاربر اطلاعات ورود/عضويت رو نشون بده
حالا يك فرم html ساده مي سازم
login.html
کد: انتخاب همه <form action="login.php" method=post> <input name=username value="" size="20"> <input name=password value="" size="20" type="password"> <input type=submit name=submit value="Login"> </from>فرو html رو توضيح نمي دم
فقط در خط اول به [COLOR="Red"]action [/COLOR]دقت كنيد
و [COLOR="Red"]method [/COLOR]كه
post هست و نه get
نام كاربري و پسورد هم كه در فرم با نام هاي username و password مشخص شده اند
فايل login.php
کد: انتخاب همه <?php session_start(); if(isset($_POST['username']) && isset($_POST['password'])) if($_POST['username'] == 'reza' && $_POST['password'] == 'test') { $_SESSION['username'] = 'reza'; HEADER('LOCATION: index.php'); } else die('wrong username/password!'); ?>در خط 3 بررسي كردم كه اين دو مقدار توسط فرم ارسال شده باشند
بعد در خط 4 به بعد بررسي كردم اگه نام كاربر و پسورد دررست بود سشن يوزر نيم ايجاد بشه و كاربر به صفحه اصلي بازگشت داده بشه در غير اينصورت خطا بگيره
چون خواستم ساده باشه براي يوزر نيم و پسورد فعلا از ديتابيس استفاده نكردم و ساده ترين حال ممكن رو پيش بردم!
تا اينجا ما در فايل اصلي چك كرديم كاربر وارد شده يا نه
در فايل login.html
فرم ورود رو داشتيم
و در فايل login.php اعتبار سنجي و تاييد هويت رو داشتيم
در مرحله آخر اين آموزش هم logout رو بررسي مي كنيم
براي logout كافيه سشن يوزر نيم رو حذف كنيم
در اينجا تمام سشن هاي كاربر رو مي تونيم با تابع
session_destroy();
نابود كنيم!
پس logout.php
کد: انتخاب همه <?php session_destroy(); HEADER('LOCATION: index.php'); ?>انشالله در ادامه مبحث عضو گيري رو هم ميگم و و استفاده از كدها رو با ديتابيس پيش م بريم تا كمي به واقعيت نزديك تر بشيم:)
[ تبليغات ] انجام پروژه هاي برنامه نويسي انجام پروژه هاي برنامه نويسي توسط تبم نرم افزاری پارس با پشتیبانی شرکت انديشه پرور سلام
بالاخره رسيدم سر وقت ادامه آموزش!
خب حالا فرض كنيد قرار هست بيش از يك يا چند كاربر داشته باشيم،و عضو گيري هم بكنيم در اين صورت بهتر گزينه استفاده از ديتابيس هست
خب يك جدول خيلي ساده براي اعضا در نظر مي گيرم
1. شناسه اي منحصر به فرد براي هر عضو
2. نام كاربري
3. رمز عبور
4. نام كاربر
پس ابتدا يك ديتابيس جديد بسازيم :
کد: انتخاب همه CREATE DATABASE `learn` ;حالا جدول مورد نيازمون
کد: انتخاب همه CREATE TABLE `learn`.`user` ( `id` INT( 10 ) NOT NULL AUTO_INCREMENT PRIMARY KEY , `user` VARCHAR( 255 ) NOT NULL , `pass` VARCHAR( 255 ) NOT NULL , `name` VARCHAR( 255 ) NOT NULL ) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ciاگر با دستورات sql آشنايي نداريد هيچ جاي نگراني نيست؛ چون با php my admin و ابزارهاي مشابه مي تونيد اين ضعف رو بهبود ببخشيد
اندكي توضيح در مورد اين كد
دستور Creat table كه از نامش مشخصه يك جدول ايجاد مي كنه!
`learn`.`user`
در اينجا learn نام ديتابيس و user نام جدول ما هست. مي تونيم از به كاربردن كلمه learn كه اسم ديتابيس هست صرف نظر كنيم البته در صورتي كه در برنامه همزمان با بيش از يك ديتابيس در ارتباط نباشيم.
id همون شناسه كاربر هست كه از نوع عدد صحيح و حداكثر 10 رقمي تعريفش كردم
در خصوصيت اين شناسه و موارد بعدي NOT NULL زدم يعني مقدار اين فيلد ها نبايد تهي باشد
شناسه خاصيت مهمي داره به نام AUTO_INCREMENT كه براي فيلد ها اصلي و عددي استفاده ميشه
در واقع به ازاي هر كاربر جديدي كه به ديتابيس اضافه مي كنيم اين فيلد به صورت خودكار يك واحد براي اون كاربر افزايش پيدا مي كنه
COLLATE جدول رو هم utf گذاشتم تا از utf پشتيباني بشه!
--
خب حالا بريم سر وقت كد نويسي
فايل config.php
اين فايل براي اتصال به ديتابيس استفاده شده كه در ادامه توضيح ميدم:
کد: انتخاب همه <?php $server = 'localhost'; $username = 'root'; $password = 'mysql'; $database = 'amozesh'; $Connection = mysql_connect( $server , $username , $password ) or die(mysql_error()); mysql_select_db( $database , $Connection ) or die(mysql_error()); ?>تابع mysql_connect رو چند باري توضيح دادم پس نقل قول ميزنم:
mysql_connect : اين تابع سه آرگومان (ورودي) اجباري مي گيرد که اولي نام هاست،دومي نام کاربري ديتا بيس و سومي کلمه عبور ديتا بيس مي باشد.
mysql_select_db : ديتابيس شما را با توجه به اطلاعات داده شده در مرحله قبل انتخاب مي کند تا بتواني عملياتي مانند نوشتن،خواندن،حذف و ... را انجام بديد.
فكر نكنم اين بخش كد چيز خاصي داشته باشه
فرم ثبت نام:
کد: انتخاب همه <form action="signup.php" method="post"> Username : <input name="user" type="text" /><br> Password : <input name="pass" type="password" /><br> Name : <input name="name" type="text" /><br> <input name="submit" type="submit" value="register!"></form>فرم خيلي ساده نوشته شده ؛ فقط قسمت هاي action و method و name رو دقت كنيد كه بعدا ازشون استفاده مي شه در برنامه.
عضو گيري - فايل signup.php
کد: انتخاب همه <?php include('config.php'); if(empty($_POST['user'])) die('username is empty!'); if(empty($_POST['pass'])) die('password is empty!'); if(empty($_POST['name'])) die('name is empty!'); $user = $_POST['user']; $pass = $_POST['pass']; $name = $_POST['name']; mysql_query("INSERT INTO `user` SET `user`='$user',`pass`='$pass',`name`='$name'") or die(mysql_error()); echo "Registeration was successfull! now login!"; ?>در خط 2 فايل اتصال به ديتابيس رو لود كردم، درواقع اين تنظيمات رو در يك فايل ديگه نوشتم تا هر بار و در هر بخش مجبور به تكرارش نباشيم
در خط 3 الي 8 چك كردم كه مقاديري كه از فرم ارسال شده اند خالي نباشند.
در سه خط بعدي اين مقادير رو به سه متغير كمكي با نام دلخواه نسبت دادم
در خط بعدي در تابع mysql_query يوزر جديد رو اضافه كردم!
براي افزودن يك ركورد به جدول بايد از INSERT استفاده كنيم
من query رو به زبان فارسي بيان مي كنم :
در داخل جدول user سطر جديدي درج كن كه در آن مقدار فيلد user برابر متغير user ، فيلد رمز عبور برابر متغير رمز عبور و نام برابر متغير نام باشد.
خارج از تابع
در غير اين صورت برنامه خاتمه پيدا كنيد (or die)
كه در داخل die خروجي رو mysql_error گذاشتم.اين تابع خطاي رخ داده رو بر مي گردونه و مي تونيم بفهميم اشكال كار كجا بوده
در خط آخر پيام موفقيت در عضويت رو بيان كردم!
فرم ورود -- login.html
کد: انتخاب همه <form action="login.php" method=post> <input name=username value="" size="20"> <input name=password value="" size="20" type="password"> <input type=submit name=submit value="Login"> </from>اين فرم رو در ابتداي آموزش داشتيم.
فايل login.php
کد: انتخاب همه <?php session_start(); include('config.php'); if(isset($_POST['username']) && isset($_POST['password'])) { $username = $_POST['username']; $query = mysql_query("SELECT `pass` FROM `user` WHERE `user`='$username'") or die(mysql_error()); $data = mysql_fetch_array($query); if($data['pass'] == $_POST['password']) { $_SESSION['username'] = $_POST['username']; HEADER('LOCATION: index.php'); } else die('wrong username/password!'); } ?> تنها تغييري كه در اين فايل نسبت به فايل آغاز برنامه داشتيم ، اين بود كه اطلاعات اعضا رو از ديتابيس مي كشيم بيرون و اعتبار سنجي مي كنيم
من هم فقط بخش هاي تغيير يافته رو توضيح ميدم
خط 7 : انتخاب كن ، مقدار فيلدي با نام pass را از جدول user در جايي كه فيلد username برابر با متغير $username باشد
در خط بعد ، تابع mysql_fetch_array() نتيجه به دست آمده از تابع mysql_query رو در قالب يك آرايه مي ريزه
پ.ن : براي درك بهتر متغير $data رو از تابع print_r رد كنيد
چون اين تابع رو هم در آموزش هاي ديگه توضيخ دادم بيشتر از اين روش نمي مونم
در خط بعدي بررسي كردم كه اگر مقدار پسورد موجود در آرايه data با مقدار پسوردي كه كاربر در فرم ارسال كرده يكسان بود لوگين كن و گرنه پيغام خطا بده
logout هم كه تغيير خاصي نكرده.
خواستم به قولي كه دادم عمل كرده باشم و آموزش رو امشب گذاشته باشم ، ببخشيد كمي خسته بودم!جايي رو اگه بد توضيح دادم بگيد تا بيشتر توضيح بدم
فايل zip شده فايل ها رو هم گذاشتم.
ادامه دارد....
سپاس
فايل ضميمه رو يادم رفته بود !
پيوست ها member_area.zip (1.75 کيلو بايت) دانلود 126 بار داداشی مرسی چه اکتیو شدی ، رایت کلیک یه طرف ، رضا هم اون طرف :دی تنکس
با سلام و سپاس
1-چرا بجاي استفاده ازکدي مثل :
کد: انتخاب همه $_SESSION['user']=rt54y;از کد :
کد: انتخاب همه $_SESSION['username'] = $_POST['username'];استفاده مي کنيد ؟ به دلاِيل امنيتي يا کاربردهاي بعدي که username مي تواند داشته باشد؟
2-در صورت استفاده از کد اول مي توانيم پس از لوگين شدن مقدار آن را با کدي مثل :
کد: انتخاب همه if($_SESSION['user']= rt54y){ کنترل کنيم و آيا اين شکل از نظر امنيتي و ... مناسب تر از :
کد: انتخاب همه if(isset($_SESSION['username'])) {نخواهد بود؟مثلا به اين دليل که در حالت اول برابري آن را با يک مقدار که بدست آوردن آن چندان ساده نخواهد بود را بررسي مي کنيم اما در حالت دوم فقط وجود $_SESSION['username']) راا؟
(قطعا نخواهد بود !!! اما دقيقا مي خواهم تفاوتهايشان را بدانم-لطفا )
3- تا جايي که من متوجه شدم اگر از HEADER استفاده کنيم نمي توانيم مقادير user و pass رو به همين شکل به صفحه بعدي (index)ارسال کنيم و بايد از طريق سشن ارسال شوند.حال اگر براي حل اين مساله بجاي HEADER از require استفاده کنيم چه مشکلاتي بوجود مي آيد؟
امیدوارم قبل از ادامه بحث به این چند ابهام و سوال جواب دهید.
بدرود
سلام
نقل قول :
آموزش رو خيلي ساده و بدور از رعايت هر گونه نكات امنيتي بيان مي كنمدر اينجا جنبه آموزشي مطرح بوده پس فقط خواستم نحوه authenticate يوزر ها رو به ساده ترين زبون ممكن بيان كنم.
ولي نگه داشتن username در سشن مشكل امينتي نيست...
مهم اينه كه جلوي fake كردن سشن رو بگيريم،كه اين كار رو هم مي تونيم با استفاده از ايندكس هاي $_SERVER و از اين قبيل انجام بديم (توضيح بيشتر در انجمن هست ، اگر پيدا نكرديد بگيد بگردم لينك بدم)
ريداركت كردن با require دو مفهموم جدا هستند و شما مي تونيد با توجه به سبك برنامه نويسي هر كدوم رو ترجيح ميديد بسته به نيازتون استفاده كنيد
از اینکه خیلی واضح دارید مطالب را ارایه می دین متشکرم.راستش این سوالاتی که مطرح کردم همیشه برام ابهام بوده و می خواستم یکبار برای همیشه و در همینجا تکلیفم با اونا روشن بشه !
می تونم از جوابم اینجوری نتیجه بگیرم که :فرقی نمی کنه و می تونیم از چیزی شبیه $_SESSION['user']=rt54y;
نیز استفاده کنیم بعد در صفحات بعدی اون رو با if($_SESSION['user']= rt54y){
چک کنیم. ضمنا در فرمی شبیه فرم لوگین شما ،استفاده از require بجای header مشکلی بوجود نمی آورد.
درست متوجه شدم؟
ضمنا متوجه این نکته هستم که موارد امنیتی زیادی هستند که باید رعایت شوند و یادم هست شما در همین انجمنها درباره آنها توضیحات خوبی ارایه دادید.
فرقي نمي كنه ، البته يك مورد هست ، وقتي من از نام كاربري كاربر رو مي ريزم تو سشن در بقيه صفحات مي فهمم *كدوم* كاربر وارد شده ولي اگر يك نام صرفا ثابت در سشن باشه و براي همه يكي باشه نمي تونم تشخيص بدم كدوم كاربر وارد شده.
به عبارتي بايد يك شناساننده از كاربر وارد شده داشته باشم...
حالا راه هاي مختلفي داريم
مثلا از سبك شما استفاده كنم و در ديتابيس سشن آي دي رو با يوزر مچ كنم
يا نه از روش خودم استغفاده كنم و يوزر نيم رو بريزم تو سشن
راه هاي زيادي هست.
در مورد سول دوم هم بايد عرض كنم ، خير فرقي نمي كنه...
فقط اگر در require كردن كدمون ادامه داشته باشه بايد بعد از require از die استفاده كنيم يا با ساختار هاي كنترلي برنامه رو مطابق نيازمون پيش ببريم
از شما که وقتی برای مطرح کردن مباحث و پاسخگویی به سوالات می گذارید متشکرم.
موفق و پیروز باشید