خوب در ابتدا یه تغییراتی انجام میدیم، میخوایم این کادر بالای صفحه Login توی کل صفحات باشه به عنوان هدر سایت و در ادامه یه قالب واسه لیست منو ها مینویسیم .
توی کد Index.php (توی فولدر Login) تگ div با id بنام SingUp داریم که این تگ رو انتقال میدیم به کدهای Header.php .
البته به غیر از انتقال تگ ، یکمی هم کد header.php بصورت زیر تغییر میدیم .
کد header.php :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
۱۸
۱۹
۲۰
۲۱
۲۲
۲۳
۲۴
۲۵
۲۶
۲۷
۲۸
۲۹
۳۰
۳۱
۳۲
۳۳
۳۴
۳۵
۳۶
۳۷
۳۸
۳۹
۴۰
۴۱
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="CSS/Header.css"/>
<title>Untitled Document</title>
</head>
<body>
    
    <div id="Header">
        <div id="SingUp">
            <ul>
                <li id="title">
                    PHP-MVC
                </li>
                <li>
                    <input type="button" id="Btn_SingUp" value="ثبت نام" name="Btn_SingUp" />
                </li>
            </ul>
        </div>
        
        <div id="MainMenu">
            <ul>
                <li>
                    <a href="Index">خانه</a>
                </li>
                <li>
                    <a href="Login">ورود</a>
                </li>
                <li>
                    <a href="About">درباره</a>
                </li>
            </ul>
        </div>       
    </div>
</body>
</html>

خوب حالا یه فایل بنام header.css توی فولدر CSS میسازیم و سپس کدهای CSS مربوط به تگ SingUp رو از فایل Login.css انتقال میدیم به فایل header.css (با کمی تغییرات) .

کد header.css :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
۱۸
۱۹
۲۰
۲۱
۲۲
۲۳
۲۴
۲۵
۲۶
۲۷
۲۸
۲۹
۳۰
۳۱
۳۲
۳۳
۳۴
۳۵
۳۶
۳۷
۳۸
۳۹
۴۰
۴۱
۴۲
۴۳
۴۴
۴۵
۴۶
۴۷
۴۸
#Header
{
    margin: 0 auto;
    background-color: #6260b6;
}
#SingUp
{
    margin: 0 auto;
    width: 1000px;
    height: 80px;
    background-color: #6260b6;
}
#SingUp ul
{
    list-style: none;
}
#SingUp li
{
    float: left;
    margin-top: 20px;
}
#SingUp #Btn_SingUp
{
    background-color: #168500;
    border: 1px solid #999;
    width: 70px;
    height: 30px;
    color: #FFF;
    font-weight: bold;
    cursor: pointer;
    
    text-shadow: 0px 0px 10px #FFF;
}
#SingUp #title
{
    font-size: 30px;
    font-weight: bold;
    color: #FFF;
    margin-right: 40px;
    margin-left: 100px;
    
    text-shadow: 0.5px 0.5px 5px #000;
}

کد Login.css :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
۱۸
۱۹
۲۰
۲۱
۲۲
۲۳
۲۴
۲۵
۲۶
۲۷
۲۸
۲۹
۳۰
۳۱
۳۲
۳۳
۳۴
۳۵
۳۶
۳۷
۳۸
۳۹
۴۰
۴۱
۴۲
۴۳
۴۴
۴۵
۴۶
۴۷
۴۸
۴۹
۵۰
۵۱
۵۲
۵۳
۵۴
۵۵
۵۶
۵۷
۵۸
۵۹
۶۰
۶۱
۶۲
۶۳
۶۴
۶۵
۶۶
۶۷
#Login
{
    margin: 0 auto;
    width: 550px;
    height: 200px;
    border: 1px solid;
    border-radius: 5px;
    border-color: #999;
}
#Login #textbox
{
    position: absolute;
    margin: 45px 0 0 170px;
}
#Login #label
{
    position: absolute;
    margin: 50px 0 0 80px;
}
#Login ul
{
    padding: 0;
    list-style: none;
}
#Login #title
{
    border-bottom: 1px solid #999;
    margin: 0 20px 30px 20px;
}
#Login #title div
{
    color: #4d279c;
    font-weight: bold;
    padding-bottom: 5px;
}
#Login label
{
    color: #615f64;
}
#Login #label li
{
    margin-bottom: 5px;
}
#Login #textbox #txt_Pass
{
    margin-top: 5px;
}
#Login #textbox #btn_Login
{
    margin-top: 12px;
    background-color: #005caa;
    border: 1px solid #000;
    color: #FFF;
    width: 50px;
    height: 27px;
    font-weight: bold;
    margin-left: 3px;
}

حالا یه خروجی میگیریم :

Image

 

Image

خوب الان میایم یه قالب واسه منوها مینویسیم .
کد زیر رو به کدهای header.css اضافه میکنیم :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
۱۸
۱۹
۲۰
۲۱
۲۲
۲۳
۲۴
#MainMenu
{
    margin: 0 auto;
    width: 1000px;
    background-color: #6260b6;
    border: 1px solid #000;
    height: 40px
}
#MainMenu li
{
    float: right;
    margin: 0 10px;
    border: 1px solid #000;
    text-align: center;
    line-height: 30px;
}
#MainMenu ul
{
    margin: 0 20px 0 0;
    padding: 0;
    list-style: none;
}

خروجی رو باهم میبینیم :

Image

حالا این کدهارو هم اضافه میکینم :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
#MainMenu a
{
    font: Arial, Helvetica, sans-serif;
    font-size: 16px;
    color: #bdbbbb;
    background-color: #3f44a0;
    text-decoration: none;
    display: block;
    width: 80px;
    height: 30px;  
}

خروجی :

Image

خوب حالا میخوایم زمانی که کاربر نشانگر موس رو روی منو ها میبره، رنگ پس زمینه منو ها عوض بشه :
این کد رو به header.css اضافه میکینم :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
#MainMenu a:hover
{
    color: #fff;
    background-color: #000676;
    text-shadow: 0px 0px 5px #fff;
     box-shadow: 0 0 20px #9b9b9b;
    -moz-box-shadow: 0 0 20px #9b9b9b;
    -webkit-box-shadow: 0 0 20px #9b9b9b;
    -ms-box-shadow: 0 0 20px #9b9b9b;
    -o-box-shadow: 0 0 20px #9b9b9b;
}

خروجی :

Image

خوب میبینید که با موس روی منو “خانه” رفتیم و رنگ پس زمینه عوض شد همچنین با استفاده از کد box-shadow یه سایه هم دور دکمه منو ها گذاشتیم ، بخاطر اینکه box-shadow روی browser های مختلف کار کنه در نتیجه به اول این کد moz و webkit و ms و o اضافه میکنیم . (این کد جز کدهای CSS3 هست) ولی خوب این قضیه ۱۰۰% جواب نمیده یعنی با اینکه به ابتدای کدها ms یا moz اضافه کردیم ولی ممکنه بازم روی بعضی از browser ها کار نکنه .
moz واسه mozila
webkit واسه google chrome
ms واسه Internet Explorer
o واسه Opera

حالا میایم کدهایی رو بصورت زیر تغییر میدیم :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
#MainMenu
{
    margin: 0 auto;
    width: 1000px;
    background-color: #6260b6;
    /*border: 1px solid #000;*/
    height: 40px
}
#MainMenu li
{
    float: right;
    margin: 0 10px;
    border: 1px solid #9b9b9b;
    text-align: center;
    line-height: 30px;
}

خروجی میگیریم :

Image

خوب توی قسمت قبلی دیدیم که کدمون اشکال داشت و یه هکر راحت میتونست بدون اینکه یوزر و پسورد داشته باشه به سایت نفوذ کنه حالا میایم این باگ رفع میکنیم .
میتونیم از تابعی به نام mysql_real_escape_string استفاده کنیم ابتدا قبل استفاده از این تابع، کد Login_Model.php بصورت زیر تغییر میدیم ( فقط یه تابع die اضافه میکنیم تا ببینیم مقادیری که وارد میکنیم به چه صورتی میشه )

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
             .
             .
             .
$user = $_POST["txt_User"];
$pass = md5($_POST["txt_Pass"]);
$sql = "select * from tlb_UserPass where username='{$user}' and password='{$pass}'";
        die($sql);
             .
             .
             .

خوب الان یه خروجی میگیریم :

Image

 

Image

خوب توی عکس میبینید که با توجه به ورودی ما، برنامه زمانی خروجی برمیگردونه که یا یوزر برابر مقدار alaki باشه یا هم ۱ برابر ۱ ، پس همیشه نتیجه شرط درست میشه و هکر میتونه به سایت نفوذ کنه و بقیه دستورات بعد از کاراکتر # نیز نادیده گرفته میشه (یعنی بقیه دستورات بصورت کامنت یا توضیحات در نظر گرفته میشه)
حالا میایم یه مقدار کد تغییر میدیم و تابع mysql_real_escape_string اضافه میکنیم .

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
                  .
                  .
                  .
//$user = $_POST["txt_User"];
//$pass = md5($_POST["txt_Pass"]);
$user = mysql_real_escape_string($_POST["txt_User"]);
$pass = md5(mysql_real_escape_string($_POST["txt_Pass"]));
$sql = "select * from tlb_UserPass where username='{$user}' and password='{$pass}'";
$result = mysql_query($sql);
                  .
                  .
                  .

و خروجی میگیریم ببینیم بازم میتونیم به سایت نفوذ کنیم یا نه ؟؟

Image

 

Image

خوب میبینید که دیگه اجازه نداد به سایت نفوذ کنیم، الان میایم از تابع die استفاده میکنیم ببینیم این تابع mysql_real_escape_string چه بلایی سر ورودی که ما بهش دادیم آورد که دیگه بهمون Welcome نداد (یعنی نتونستیم به سایت نفوذ کنیم)
کد بصورت زیر تغییر میدیم (فقط یه die بهش اضافه میکنیم) :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
             .
             .
             .
//$user = $_POST["txt_User"];
//$pass = md5($_POST["txt_Pass"]);
$user = mysql_real_escape_string($_POST["txt_User"]);
$pass = md5(mysql_real_escape_string($_POST["txt_Pass"]));
$sql = "select * from tlb_UserPass where username='{$user}' and password='{$pass}'";
die($sql);
           .
           .
           .

خروجی :

Image

خوب میبینید که کاراکتر های ‘ (تک کوتیشن) رو با استفاده از کاراکتر \ غیر فعال میکنه .

با این حال که باگ کد گرفتیم ولی بازم شاید یه هکر بتونه به سایت نفوذ کنه ، بهترین راه حل اینکه که از توابع PDO واسه اتصال به بانک اطلاعاتی و اجرای دستورات روی جداول استفاده کنیم اینجوری هم امنیت سایت بالا میره هم اینکه با استفاده از توابع PDO میتونیم به راحتی با تغییر خیلی کوچیک توی کدها، به انواع دیگه ای از بانکهای اطلاعاتی (مثلاً MSSql، SQLite و Oracle و…) متصل بشیم و ازشون استفاده کنیم ولی اگه از توابع PDO استفاده نکنیم زمانی که مثلاً دیگه نمیخوایم توی سایتمون از بانک Mysql استفاده کنیم و ترجیح میدیم از بانک Oracle استفاده کنیم در نتیجه مجبوریم خیلی از کدهایی که نوشتیمو تغییر بدیم که کلی دردسر داره و وقت زیادی میبره ولی با استفاده از توابع PDO این کار خیلی راحت با تغییر چند خط کد انجام میشه ، پس حالا میایم یه تغییراتی توی کدهامون میدیم که بتونیم از توابع PDO استفاده کنیم .
یه فولدر میسازیم بنام Config و یه فایل بنام database.php توش میسازیم ، حالا این کدهارو توش مینویسیم .

۱
۲
۳
۴
۵
۶
<?php
define("DB_TYPE", "mysql");
define("DB_HOST", "localhost");
define("DB_NAME", "ITPro");
define("DB_USER", "root");
define("DB_PASS", "mehdi!1230");

تابع define یه متغیر میسازه و یه مقدار داخلش میزاره، که میتونیم همه جای سایت به این متغیر دسترسی داشته باشیم و مقدارش هم ثابت هست (یعنی قابل تغییر نیست) .
الان میایم یه فایل دیگه بنام Database.php توی فولدر Libs میسازیم و کدهای زیر توش قرار میدیم (میخوایم یه کلاس بنام Database ایجاد کنیم که از PDO ارث میبره و میتونیم از توابع PDO استفاده کنیم توی سایتمون)

۱
۲
۳
۴
۵
۶
۷
۸
<?php
class Database extends PDO
{
    function __construct()
    {
        parent::__construct(DB_TYPE.":host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS);
    }
}

ورودی تابع سازنده PDO به ترتیب نوع بانک اطلاعاتی، هاست، نام دیتابیس، یوزر و پسورد هست که با استفاده از متغیرهایی که ساختیم مقدار دهی کردیم .
الان با این خط کد به بانک اطلاعاتی متصل شدیم حالا از این کلاس استفاده میکنیم توی فایل Login_Model.php .
ابتدا یه کلاس دیگه هم تولید میکنیم و کدهایی که مشترک هستن واسه کار با دیتابیس رو اونجا مینویسیم و سپس بقیه کلاس ها از این کلاس ارث میبرن .
یه فایل بنام Model.php توی فولدر Libs میسازیم و کدهای زیر توش مینویسیم (میخوایم کلاس Model ایجاد کنیم تا بقیه کلاسها که عملیاتی روی دیتابیس انجام میدن از این کلاس ارث ببرن)

۱
۲
۳
۴
۵
۶
۷
۸
۹
<?php
class Model
{
    function __construct()
    {
        $this->db = new Database();
    }
}

یه شی از نوع کلاس Database میسازه (و تابع سازنده اش فراخوانی میشه) و مقدار برگشتی رو توی یه متغیر به نام db میریزه که بعداً از این متغیر استفاده میکنیم .
حالا میایم کد Login_Model.php کمی تغییر میدیم بصورت زیر (فقط کاری میکنیم که این کلاس از کلاس Model ارث ببره و تابع سازنده کلاس Model فراخوانی میکنیم)، در ضمن کدهای اتصال به دیتابیس و MYSql غیر فعال میکنیم (یا بهتر که حذفشون بکنیم) چون دیگه این کدهارو توی کلاس Databese نوشتیم و دیگه نیازی بهشون نداریم .
کد Login_Model.php :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
۱۸
۱۹
۲۰
۲۱
۲۲
۲۳
۲۴
۲۵
۲۶
۲۷
۲۸
۲۹
۳۰
۳۱
۳۲
۳۳
۳۴
۳۵
۳۶
۳۷
۳۸
۳۹
۴۰
۴۱
۴۲
۴۳
۴۴
۴۵
۴۶
۴۷
۴۸
۴۹
۵۰
۵۱
۵۲
۵۳
۵۴
۵۵
۵۶
۵۷
۵۸
۵۹
۶۰
۶۱
<?php
class Login_Model extends Model
{
    function __construct()
    {
        parent::__construct();
    }
    
    function run()
    {
        /*$link = mysql_connect('localhost', 'root', 'mehdi!1230');
        if (!$link) {
            die('Could not connect: ' . mysql_error());
        }
        $db_selected = mysql_select_db('ITPro', $link);
        if (!$db_selected) {
            die ('Can\'t use user_pass : ' . mysql_error());
        }*/
        
        $user = $_POST["txt_User"];
        $pass = $_POST["txt_Pass"];
        
        //$user = mysql_real_escape_string($_POST["txt_User"]);
        //$pass = md5(mysql_real_escape_string($_POST["txt_Pass"]));
        
        //$sql = "select * from tlb_UserPass where username='{$user}' and password='{$pass}'";
        //$result = mysql_query($sql);
        
        $qurey = $this->db->prepare("select * from tlb_UserPass where
                                        username = :userlogin and password = md5(:passlogin)");
        
        $qurey->execute(array(":userlogin" => $user, ":passlogin" => $pass));
        
        //die($sql);
        
        $count = $qurey->rowcount();
        
        /*if (!$result) {
            die ('Invalid query : ' . mysql_error());
        }
        if($row = mysql_fetch_row($result))
        {
            echo "<br>welcome";
        }
        else
        {
            echo "<br>Invalid Username Or Password";
        }
        die();*/
        
        if($count > 0)
        {
            echo "<br>welcome";
        }
        else
        {
            echo "<br>Invalid Username Or Password";
        }
    }
}

توضیح کدهای بالا، Query که مینویسیم رو توی تابع prepare قرار میدیم و تابع execute میاد Query که نوشتیمو اجرا میکنه و اگه این Query باید ورودی بگیره توی تابع execute ورودی هارو بصورت آرایه بهش میدیم (که اینجا من ورودی هارو بصورت آرایه به Query دادم) و سپس با تابع rowcount چک میکنیم که اگه بزرگتر از صفر بود یعنی Query با موفقیت اجرا شده و یه رکورد برای ما (به عنوان خروجی) برگردونده ولی اگه کمتر از صفر باشه یعنی نتونست نسبت به شرط و مقداری که به Query دادیم رکوردی برای ما برگردونده .

Image

 

Image

خطا میده ، میگه نتونست کلاس Model پیدا کنه ، پس ما باید با دستور require این خطا رو برطرف کنیم، کد زیر رو اضافه میکنیم به فایل Index.php (توی پوشه اصلی سایت) .
کد Index.php :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
             .
             .
             .
require("libs/view.php");
    
require("libs/Model.php");
require("libs/Bootstrap.php");
             .
             .
             .

فقط خط دوم به کدها اضافه میکنیم (مابقی خطها توی Index.php هست)
یه بار دیگه که امتحان کنیم به این خطا برخورد میکنیم :

Image

این سری کلاس Database پیدا نکرد در نتیجه همون کاری که بالا انجام دادیم واسه کلاس Database هم انجام میدیم، کد زیر به Index.php اضافه میکنیم :

۱
require("Libs/Database.php");

همین جوری هی خروجی میگیریم تا ببینیم به چه خطاهایی برخورد میکنیم و اونارو رفع کنیم :

Image

این خطا هم میگه که نتونست اون متغیرهایی که با دستور define تعریف کردیمو پیدا کنه پس این خطا رو هم مثل بالا رفعش میکنیم، کد زیر به Index.php اضافه میکنیم :

۱
require("Config/database.php");

خروجی میگیریم :

Image

میبینید که الان جواب داد ، حالا میایم یه تغییرات دیگه هم به کدهای سایتمون میدیم .
در ابتدا کد Bootstrap.php بصورت زیر تغییر میدیم .

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
                 .
                 .
                 .
$controller = new $url[0]();
$controller->loadModel($url[0]);
if(!empty($url[1]))
                 .
                 .
                 .

فقط خط دوم به کدها اضافه میکنیم (مابقی خطها توی Bootstrap.php هست)، یه تابع فراخوانی میکنیم بنام loadModel و مقدار [۰]url$ بهش میدیم (در ادامه این تابع توی کلاس Controller تعریف میکنیم)
کد Controller.php بصورت زیر تغییر میدیم :

۱
۲
۳
۴
۵
۶
۷
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
۱۸
۱۹
۲۰
۲۱
۲۲
۲۳
۲۴
<?php
class Controller
{
    function __construct()
    {
        //echo "<br>Main Controller<br>";
        
        $this->view = new View();
    }
    
    function loadModel($name)
    {
        $path = "models/".$name."_model.php";
        
        if(file_exists($path))
        {
            require($path);
            
            $ModelName = $name."_model";
            $this->model = new $ModelName();
        }
    }  
}

تابع loadModel یه ورودی میگیره که این ورودی اولین خانه آرایه url هست (یعنی [۰]url$) و این ورودی رو به model.php_ و /models میچسبونه و یه مقدار جدید (که میشه یه فایل بهمراه مسیرش) درست میشه و توی متغیر path$ قرار میگیره و سپس چک میکنه که اگه این فایل با همچین مسیری وجود داشت که یه شی ازش میسازه (که در نتیجه تابع سازندش فراخوانی میشه) و سپس نتیجه رو توی متغیر model میریزه که بعداً توی کلاس Login ازش استفاده میکنیم . (این کد رو واسه این نوشتیم چون در آینده توی فولدر Models یا Controllers کلاس های دیگه ای به غیر از Login_Model یا Login اضافه میکنیم و بخاطر اینکه از تعداد خط های کد اضافی بکاهیم این تابع رو نوشتیم اگه این تابع رو نمی نوشتیم باید توی هر کلاسی که (در آینده) توی فولدر Models یا Controlers تعریف میکنیم چند خط کد بنویسیم (مثلاً همین کدی که توی تابع run از کلاس Login نوشتیم) و اینجوری هم تعداد خط کد بالا میره هم بیشتر پیچیده میشه در نتیجه خطا یابیش مشکل تر میشه) .
خوب طبق چیزایی که در بالا گفتم باید تابع ()run توی کلاس Login بصورت زیر تغییر بدیم :

۱
۲
۳
۴
۵
۶
۷
۸
۹
function run()
{
    //require("models/Login_Model.php");
    
    //$L_M = new Login_Model();
    //$L_M->run();
    
    $this->model->run();
}

کدهای قبلی رو غیر فعال کردم و بجاش فقط خط آخر اضافه میکنم . (که پیچیدگی کمتر بشه و خطایابیش سریع تر انجام بگیره)
خوب الان یه خروجی میگیریم :

Image