سلام
نمیدونم تابه این لحظه مشکل شما برطرف شده یا نه اما من سعی میکنم مطالبی رو در رابطه با این موضوع عنوان کنم ، شاید هم برای بحث آموزشی خیلی هم بد نباشه . در هر صورت ...
اولین مشکلی که کد شما داره بخش مربوط به فرم اون هست ، همون طور که یکی از دوستان اشاره کردن، نوع دکمه شما باید ازنوع Button به sbmit تغییر کنه تا اینکه PHP بتونه از طریق متغیر سراسری post_$ و یا get_$ اطلاعات فرم رو ذخیره کنه .
دومین مشکل این هست که شما نتیجه حاصل از تابع
mysql_query رو برای نتیجه گیری از این که کاربر درست login کرده استفاده کردین در صورتی که این صحیح نیست . همون طور که میدونید تابع فوق زمانی که query شما از لحاظ این که mysql این query رو صحیح بدونه مقدار true و در غیر این صورت مقدار false رو برمیگردونه نه برای نتیجه حاصل از مقدار برگشتی query . در واقع در این شرایط حتی اگر نتیجه ای از query حاصل نشه اما از نظر syntax برای mysql درست تلقی بشه، حاصل برگشتی این تایع true خواهد بود.
خوب حالا باید چه کرد ؟ شما برای پردازش حاصل از خروجی باید از 2 تابع mysql_fetch_row و mysql_fetch_array استفاده کنید . چرا ؟ چون این توابع نتایج حاصل از خروجی تابع mysql_query رو مورد دستیابی قرارمیدن و نتیجه حاصل از این توابع به این ترتیب هست که اگر عملیات دستیابی به سطر مورد نظر با موفقیت همرا باشه مقدار true ودرغیر این صورت مقدار false رو برمیگردونن .
خوب این تا این قسمت از قطعه کد شما . اما مهمترین ایراد این کد اینها نیست چرا که با چندبار تست و خروجی گرفتن مشکل حل خواهد شد. اصلی ترین ایراد این کد این هست که خوانایی کد و قابلیت اون پایین هست . بهتر هست تا جایی که میتونیم عادات خوب کدزنی رو همیشه رعایت کنیم .
بهتره تا جاییکه میشه به صورت ماجولار کدهارو در PHP بنویسیم. با اینکه PHP قابلیت شی گرایی هم داره اما بعضی اوقات استفاده از متد شی گرایی توی PHP پیش از اینکه باعث سهولت بشه ، باعث دردسر و سردرگمی خواهد شد چون خیلی اوقات کد اسکریپت ما از چند خط بیشتر تجاوز نمیکنه
برای قطعه کد login کردن کابر چندتا مورد باید در نظر گرفته بشه . اول اینکه قبل از هرچیز چک بشه که آیا کاربری با این نام کاربری وجود داره که اگر نداشت پیغام مناسب چاپ بشه. دوم اینکه اگر چنین کاربری وجود داره ، آیا رمز عبور صحیح هست یا نه . اگر هردوی این موردها صحیح بود کاربر به صفحه مناسبی هدایت بشه.
من کدهایی که نیاز هست رو اینجا مینویسم خیلی ساده مینویسم و مواردی که لازم هست توضیح میدم :
1- بهتر هست همیشه برای اتصال به DB و پردازش query یه ماجول جدا نوشته بشه که هروقت خواستیم اون رو با query مور نظر صدا بزنیم. البته بعضی اوقات تنها نیاز هست فقط برای اتصال به db یه ماجول نوشته بشه و query به طور جداگانه پردازش بشه :
PHP:
function opendb($query)
{
$query = stripslashes($query);
error_reporting(0);
$link = @mysql_connect("127.0.0.1","user","pass")
or die("No connect");
$selectdb = mysql_select_db("dbname", $link)
or die("can not open data base. ");
$result = mysql_query($query, $link)
or die( print "Your request was canceled");
$close = mysql_close($link)
or die("can not close database");
return($result);
}
از اونجایی که بهتر هست کاربر خطای DB و PHP رو نبینه به همین خاطر ازتابع error_reportng با مقدار 0 استفاده شده . میشه با قرار دادن کاراکتر @ ابتدای هر تایع هم از نمایش خطا توی PHP جلوگیری کرد که من برای تابع connect این کارو کردم . ( یه حفره امنیتی دیگه هم هست که در ادامه عنوان میکنم )
دوم اینکه بهتر هست همیشه از یه ماجول برای گرفتن مقادیر فرم ها استفاده کرد که دیگه دردسری در رابطه با کارکردن با اونها نداشته باشیم و اونها رو با اسم خودشون توی یه متغیر ذخیره کنیم مثل ماجولیبه اسم getpost .
قبل از اینکه این ماجول رو بگم این موضوع یادم افتاد که بهتر هست از همون متد post برای ارسال داده ها استفاده کنید به جای get چرا ؟ چون از دید امنیتی متد post بهتر هست . همون طور که میدونید متد get همیشه مقادیر فرمها رو به صورت زوج مقدار و نام متغیر به انتهای آدرس URL صفحه تون اضاف میکنه که این از لحاظ امنیتی مشکل ایجاد میکنه چرا که با کم و اضاف کردن اون مقادیر میش خیلی راحت به مقاصدی رسید اما متد post این طور نیست .
خوب میرسیم به اون ماجولی که گفتم :
PHP:
function getpost()
{
foreach($_POST as $key => $value)
{
global $$key;
$$key=$value;
}
}
به همین سادگی میشه مقادیر متغیر سراسری post_$ رو با نام خودشون توی یه متغیر ذخیره کرد که این خیلی توی خوانایی کد به شما کمک میکنه . کد بالا چیکار میکنه ؟ خوب از اونجایی که متغیر سراسری post_$ یه آرایه هست که مقادیر فرم رو توی خودش ذخیره میکنه ، من همه اون مقادیر رو توی متغیرهایی با اسم خودشون ذخیره میکنم که کار راحت باشه . یعنی اگر textbox ورودی کاربر اسمش user باشه ، مقدار
داخل متغیری به اسم user ذخیره میشه .
خوب حالا بهتره یه ماجول هم برای چک کردن کاربر بنویسیم ( همون 2 تا موردی که باید برای login کردن کاربر در نظر گرفته میشد رو هم در نظر خواهیم گرفت )
PHP:
function checkuser($user, $password)
{
$query = "select * from stu_register where user='$user'";
$result = querydb($query);
if (!($line = mysql_fetch_array($result, MYSQL_ASSOC)))
{
die(header('location: no_user.php'));
}
else
{
if ( $line[pwd] == $password )
{
die(header('location: user_home.php'));
}
else
{
die(header('location: no_pass.php'));
}
}
}
مهمترین بخش کد هم همین ماجول هست . این ماجول 2 تا پارامتر ورودی داره یکی اسم کاربر و دیگری password . این پارامترها ابتدا با اجرای ماجول getpost که قبلن گفتم داخل متغیرها قرار میگیره ( هنوزبه قست main کد نرسیدیم اونجا توضیح میدم ) .
PHP:
$query = "select * from stu_register where email='$email'";
$result = opendb($query);
ابتدا یه query نوشته شده برای اینکه سطر مربوط به کاربر با تمام فیلدهاش گرفته بشه ( میشه محدودش هم کرد ) چون اسم کاربر مطمئنن یکی از کلیدهای اصلی توی جدول مربوطه هست، به این خاطر که نباید کاربر دیگه ای با اون اسم ثبت نام کرده باشه و سپس ماجول opendb فراخوانی شده با پارامتر مربوط به query تا تمام کارهای اتصال و fetch کردن رو این ماجول انجام بده .
PHP:
if (!($line = mysql_fetch_array($result, MYSQL_ASSOC)))
{
die(header('location: no_user.php'));
}
سپس خروجی ماجول opendb که متغیر result$ هست رو داخل تابع mysql_fetch_array قرار میدیم تا روی خروجی حاصل از تابع mysql_connect پردازش انجام بدیم. با یه شرط خروجی تابع رو تست میکنیم ببینیم آیا اصلا سطری با مشخصات کاربر وجود داشته یا نه ( این همون ایرادی بود که توی کد اولیه برنامه وجود داشت ) که اگر نداشت من اون رو به یه صفحه به اسم no_user ارجاع دادم که پیغام مناسبی رو برای کاربر نشون میده اما اگر وجود داشت :
PHP:
else
{
if ( $line[pwd] == $password )
{
die(header('location: user_home.php'));
}
حالا کلمه رمز رو چک میکنیم . همون طور که پیش تر گفتم با ماجول getpost مقادیر فرم ها رو قبلن داخل متغیری با اسم خودشون ذخیره کردیم . حالا فقط کافیه مقدار متغیر password$ با مقدار فیلد متناظرش در بانک که همون
هست مقایسه بشه . اگر درست بود کاربر به صفحه ای به اسم user_home هدایت میشه اما اگر نبود :
PHP:
else
{
die(header('location: no_pass.php'));
}
به صفحه ای هدایت میشه که پیغام مناسب درش قرار گرفته .
این نکته رو بگم که میشه بجای ارجاع به صفحه ای ، فقط یه صفحه در نظر گرفت و توی اون صفحه با قرار دادن شرط های مناسب ، پیغام های مناسب رو چاپ کنیم و ... .
خوب حالا میرسیم به قسمت main برنامه . دوستانی که قبلن با زبانهای برنماه نویسی مثل ++C کد زدن تا الان متوجه شدن که من دارم طبق syntax اون پیش میرم به دلیل شباهت زیاد syntax های PHP و ++C اما هیچ الزامی نیست . ( اشتباه نکنین اینجا تابعی به اسم main() نداریم من خودم این اسم رو گذاشتم روش )
قسمت main برنامه که توش از ماجول هایی که نوشته شده استفاده میکنیم :
PHP:
getpost();
$_SESSION['user'] = $user;
checkuser($email, $password);
header('location: user_home.php');
خوب همون طور که گفتم ابتدا ماجول getpost فراخوانی شده و تمام ورودی های فرم مون داخل متغیری با اسم خودشون ذخیره شده . سپس یه متغیر جلسه هم به اسم user تعریف کردم که قابلیت رهگیری کاربر رو در صفحات بعد داشته باشه . بعد از اون ماجول checkuser صدا زده شده و سپس اگر همه چیز درست بود انتقال به صفحه مورد نظر .
اگر بخوام کدمون رو یک جا بنویسم اینطور میشه :
PHP:
<?php
session_start();
function opendb($query)
{
$query = stripslashes($query);
error_reporting(0);
$link = mysql_connect("127.0.0.1","user","pass")
or die("No connect");
$selectdb = mysql_select_db("dbname", $link)
or die("can not open data base. ");
$result = mysql_query($query, $link)
or die( print "Your request was canceled");
$close = mysql_close($link)
or die("can not close database");
return($result);
}
function getpost()
{
foreach($_POST as $key => $value)
{
global $$key;
$$key=$value;
}
}
function checkuser($email, $password)
{
$query = "select * from stu_register where user='$user'";
$result = opendb($query);
if (!($line = mysql_fetch_array($result, MYSQL_ASSOC)))
{
die(header('location: no_user.php'));
}
else
{
if ( $line[pwd] == $password )
{
die(header('location: user_home.php'));
}
else
{
die(header('location: no_pass.php'));
}
}
}
//main
getpost();
$_SESSION['user'] = $user;
checkuser($email, $password);
header('location: user_home.php');
?>
به غیر از این مورد ، کد شما یه حفره امنیتی فاجعه ساز هم داره و اون هم این هست که چون شما با توابع مربوطه query خودتون رو ف ی ل ت ر نکردین ، یه کاربر محترم میتونه با یه کار نامحترمانه خیلی راحت از تزریق کدهای sql توی فیلد ورودی فرم تون ( به اصطلاح query injection ) وارد حساب کاربری کاربرهای دیگه بشه . چطوری ؟ این طوری
query شما این طور نوشته شده :
PHP:
$query="select * from student where Id_student='$_POST[u]' and shsh='$_POST[p]'";
حالا اگه یه کاربر به جای فیلد u اسم یه کاربر رو بنویسه ( مثلا hasan ) و توی فیلد p این کد رو بنویسه
اونوقت query شما به صورت زیر به سرور ارسال میشه :
PHP:
$query="select * from student where Id_student=' hasan ' and shsh=' ' OR ' ' = ' '";
اتفاقی که میفته این هست که این کاربر نامحترم خیلی راحت با اسم کاربری hasan وارد سایت یا حساب کاربری hasan میشه . چرا ؟ چیزی که مهم هست این قسمت از query شماست :
. فسمت اول شرط که صحیح نیست اما قسمت دوم شرط کاملا صحیح هست یعنی یه مقدار null همیشه با یه مقدار null برابر هست حالا چون از OR استفاده شده حتی اگر قسمت اول شرط هم درست نباشه ( که همین طور هم هست ) این query به درستی اجرا میشه و به اصطلاح مو لایه درزش هم نمیره ! و به همین راحتی بدون نیاز به password کاربر وارد سایت شم میشه .
کاری باید انجام داد اینه که شما query خودتون رو با توابعی مثل mysql_real_escape_string و stripslashes حتما ف ی ل ت ر کنید . البته من هم توی کد بالا این کار رو انجام ندادم چون نیازی نبود یعنی بعد از اتصال به DB این تابع رو بنویسید و پارامترهای ورودی خودتون رو داخل اون قرار بدین و بعد به query خودتون اضافه کنید و سپس query رو به server ارسال کنید .
امیدوارم این مطلب هرچند کوچیک مفید واقع شده باشه
پیروز باشید