# زبان های اسکریپتی > PHP > Yii Framework >  فرم login و ایجاد امنیت بیشتر برای تمامی صفحات

## ranataher

با سلام به دوستان عزیز و خسته نباشید
فرم لاگین ای که خود Framwork ارائه میدهد چه با استفاده از username ,pass و چه بدون ان   هموراه میتوان تمامی صفحات را مشاهده کرد 
سوال: چگونه میشود ان را فقط متکی به username ,pass کرد که هیچ صفحه ای را تا login نکردیم نمایش ندهد و همچنین چگونه میتوان امنیت بیشتری را برای برنامه در framwork Yiiایجاد کرد




با تشکر

----------


## MMSHFE

شما توی کنترلر خودتون میتونید با محدودکردن اکشنها به @ (در قسمت users) فقط اجازه استفاده از اون اکشنها رو به کاربران لاگین کرده بدین. حالت پیشفرض Yii که توی پروژه Skeleton قرار گرفته این نیست چون قرار هم نیست این پروژه، پروژه واقعی و نهایی شما باشه و صرفاً یک اسکلت برای ساخت بقیه سایت روی اون و انجام تغییرات لازم هست.
درمورد امنیت بیشتر هم بهتره درمورد حملات SQL Injection و JS Injection و CSRF و XSS و... تحقیق کنید. Yii هم راههای خوبی رو برای مقابله با هرکدوم از این حملات ارائه کرده ولی قبل از اینکه راه حل Yii رو دنبال کنید، درمورد خود حملات تحقیق کنید.

----------


## ranataher

> شما توی کنترلر خودتون میتونید با محدودکردن اکشنها به @ (در قسمت users) فقط اجازه استفاده از اون اکشنها رو به کاربران لاگین کرده بدین. حالت پیشفرض Yii که توی پروژه Skeleton قرار گرفته این نیست چون قرار هم نیست این پروژه، پروژه واقعی و نهایی شما باشه و صرفاً یک اسکلت برای ساخت بقیه سایت روی اون و انجام تغییرات لازم هست.
> درمورد امنیت بیشتر هم بهتره درمورد حملات SQL Injection و JS Injection و CSRF و XSS و... تحقیق کنید. Yii هم راههای خوبی رو برای مقابله با هرکدوم از این حملات ارائه کرده ولی قبل از اینکه راه حل Yii رو دنبال کنید، درمورد خود حملات تحقیق کنید.


درحال حاضر به جز انچه که framework Yii  به عنوان action تعریف کرده من  action تعریف نکردم و در حال حاضر نیز می خواهم کاربر وقتی وارد سایت شد تا  هنگامی که لاگین نکرده هیچ صفحه ای از جمله index.php را نبیند و بعد از  لاگین این مجوز برای او صادر شود این مورد به چه صورت انجام میپذیرد

----------


## MMSHFE

توی SiteController این دو متد رو اضافه کنید:
    public function filters()
    {
        return array(
            'accessControl', // perform access control for operations
        );
    }
    public function accessRules()
    {
        return array(
            array('allow',  // allow only unauthorized users to perform 'login' action
                'actions'=>array('login'),
                'users'=>array('?'),
            ),
            array('allow', // allow only authorized users to perform all other actions
                'users'=>array('@'),
            ),
            array('deny',  // deny all other users to perform all other actions
                'users'=>array('*'),
            ),
        );
    }

----------


## ranataher

از کمکی که کردید واقعا متشکرم ، اگر امکان داشته باشه یک سوال دیگر هم دارم 
من 4 تا فایل php ساختم که هر کدام یک کار برای login انجام میدهند اما درست کار نمیکند که شامل register,login,logout,member البته نام کاربری و رمز را از database mysql  میخواند کدها به شرح ذیل میباشد 
ممنون میشم اگر  جواب این سوال ام را نیز بدهید
register.php\\

<form action="" method="POST">
Username: <input type="text" name="user"><br/>
Password: <input type="password" name="pass"><br/>
<input type="submit" value="ورود به سیستم" name="submit" />
</form>

<?php>
if(isset($_POST["submit"]))
{
 $user=$_POST['user'];
 $pass=$_POST['pass'];

$con=mysql_connect('localhost','root','123456') or die(mysql_error());
mysql_select_db('db1') or die("cannot select DB");

$query=mysql_query("SELECT * FROM  tbl_useraccounts WHERE username=' ".$user." ' ");
$numrows=mysql_num_rows($query);
if($numrows==0)
 {
   $sql="INSERT INTO tbl_useraccounts(Username,Password) VALUES ('$user','$pass')";

   $result=mysql_query($sql);

   if($result)
   {echo "Account Successfully Created";}
   else{ echo "Failure!";}


 }else{echo"That username already exisits!Please try again with another.";}

}
?>

//login.php


<?php
//شروع یک session
session_start();
//دریافت و تنظیم متغیرهای ارسال شده توسط کاربر
@$username = $_POST['username'];
@$password = $_POST['password'];
@$check = $_POST['check'];
?>
<!DOCTYPE >
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>فرم ورود به سیستم|</title>

<style type="text/css">
body{
    font-family:Tahoma, Geneva, sans-serif;
    direction:rtl;
    font-size:12px;
}
</style>
</head>
<body>
<?php
//بررسی معتبر بودن اطلاعات ارسالی کاربر
//نام کاربری
if (!isset($username) || $username == ''){
    echo "فیلد های  نام کاربری و کلمه عبور نباید خالی باشد!";
    $check_error = 1;
}
//کلمه عبور
elseif (!isset($password) || $password == ''){
    echo "فیلد کلمه عبور نباید خالی باشد!";
    $check_error = 1;
}
//اطلاعات اتصال به پایگاه داده
$con = mysql_connect("localhost", "root", "123456")
or die(mysql_error());
//نام دیتابیس
mysql_select_db("db1", $con)
or die(mysql_error());
//جلوگیری از نفوذ به دیتابیس
$username = mysql_real_escape_string($username);
$password = md5($password);
if ($check_error != 1 && $check == 'sended'){
    //تطبیق اطلاعات کاربر با آنچه که در دیتابیس ذخیره شده
    $result = mysql_query ("SELECT * FROM  Structuretbl_useraccounts WHERE Username = '$username' AND Password = '$password'");
    // تعداد ردیف های موجود
    $count = mysql_num_rows($result);
    if($count > 0){
        // اطلاعات کاربر درست است، تنظیم مجوز های استفاده از بخش اعضاء 
        $_SESSION['username'] = $_POST['Username'];
        $_SESSION['password'] = $_POST['Password'];
        // اطلاعات کاربر صحیح است
        echo "شما به سایت وارد شده اید!<br />"; 
header("location:index.php") ;
    }
    else{
        // اطلاعات کاربر صحیح نیست
        echo "اطلاعات وارد شده صحیح نیست!<br />";
    }
}
//پایان ارتباط با پایگاه داده  
mysql_close($con);
?>

 با تشکر

----------


## MMSHFE

خوب این کدها که الآن ربطی به Yii ندارن. دقیقاً مشکلتون چیه؟ میخواین اینها با ساختار Yii کار کنن؟

----------


## ranataher

> خوب این کدها که الآن ربطی به Yii ندارن. دقیقاً مشکلتون چیه؟ میخواین اینها با ساختار Yii کار کنن؟


نه خوب این 4 تا فایل جهت login , register کردن کاربر میباشد و صحبت شما  درست است ارتباطی با yii ندارد وبا  php نوشته شده است اما دلیل اینکه درست کار نمیکند را متوجه نمیشوم  نمیدانم که yii ایا راه حلی برای لاگین کردن توسط جداول ای که در دیتا بیس طراحی کردیم را به ما میدهد یا نه؟ چون در حال حاضر نمیدانم که ایا این کد ها این کار را درست انجام میدهند یا   باید توسط yii بخشی به این کدها اضافه شود؟
و اینکه وقتی اطلاعات نام کاربری و رمز ورودکه در دیتا بیس است را می زنم توسط یک postback فقط صفحه refresh میشود ؟!!!!!!!!
و هنگامی که بر روی register که در بالای صفحه است کلیک میکنم پیغام زیر ر میدهد(درصورتی که کدهایی که گفتید به usercontroller اضافه کنم باشند اصلا صفحه لاگین ای که خودم نوشتم لود نمیشود)

*Error 404*   The system is unable to find the requested action "register".

----------


## MMSHFE

خوب فکر میکنم یک مقدار توی درک نحوه کار Yii دچار اشتباه شدین. برای نمونه، پیاده سازی سیستم login و logout رو توضیح میدم ببینید کدهاتون رو باید چطور تغییر بدین.
1- ابتدا توی فایل تنظیمات (protected/config/main.php)، کامپوننت db رو تنظیم کنید:
return array(
    //...
    'components'=>array(
        //...
        'db'=>array(
            'connectionString' => 'mysql:host=localhost;dbname=voip',
            'emulatePrepare' => true,
            'username' => 'root',
            'password' => '123456',
            'charset' => 'utf8',
            'tablePrefix' => 'Structuretbl_',
        ),
        //...
    //...
);
2- اکشنهای login و logout رو به کنترلر site اضافه کنید (فایل protected/controllers/SiteController.php) :
    public function actionLogin() {
        $model = new LoginForm();
        // collect user input data
        if(isset($_POST ['LoginForm'])) {
            $model->attributes = $_POST ['LoginForm'];
            // validate user input and redirect to the previous page if valid
            if($model->validate() && $model->login()) {
                $log = new Logs;
                $log->user_id = Yii::app()->user->id;
                $log->login = time();
                $log->activity = $log->login;
                $log->save();
                $this->redirect(Yii::app()->user->returnUrl);
            }
            else {
                Yii::app()->session->add('failure', 'خطا در نام کاربری یا رمز عبور');
            }
        }
        // display the login form
        $this->render('login', array ('model' => $model));
    }
    public function actionLogout()
    {
        Yii::app()->user->logout();
        $this->redirect(Yii::app()->homeUrl);
    }
3- کلاس UserIdentity رو اصلاح کنید (فایل protected/components/UserIdentity.php) :
<?php
/**
 * UserIdentity represents the data needed to identity a user.
 * It contains the authentication method that checks if the provided
 * data can identity the user.
 */
class UserIdentity extends CUserIdentity {
    private $_id;
    /**
     * Authenticates a user.
     * The example implementation makes sure if the username and password
     * are both 'demo'.
     * In practical applications, this should be changed to authenticate
     * against some persistent user identity storage (e.g. database).
     * @return boolean whether authentication succeeds.
     */
    public function authenticate() {
        $user = Users::model()->find('LOWER(username)=? AND confirmed=1', array(strtolower($this->username)));
        if($user === null) {
            $user = Users::model()->find('LOWER(email)=? AND confirmed=1', array(strtolower($this->username)));
        }
        if($user === null) {
            $this->errorCode = self::ERROR_USERNAME_INVALID;
        }
        elseif(!$user->validatePassword($this->password)) {
            $this->errorCode = self::ERROR_PASSWORD_INVALID;
        }
        else {
            $this->_id = $user->id;
            $this->username = $user->name;
            $this->errorCode = self::ERROR_NONE;
        }
        return $this->errorCode == self::ERROR_NONE;
    }
    /**
     * Get the current user ID
     * @return int Current user ID
     */
    public function getId() {
        return $this->_id;
    }
}
4- مدل Users رو با کمک Gii ایجاد کنید (من فرض کردم فقط دو فیلد username و password رو دارین - فایل protected/models/Users.php) :
<?php
/**
 * This is the model class for table "{{useraccounts}}".
 *
 * The followings are the available columns in table '{{useraccounts}}':
 * @property integer $id
 * @property string $username
 * @property string $password
 */
class Users extends CActiveRecord {
    public $password_repeat;
    private $_attributesBackup;
    /**
     *
     * @return string the associated database table name
     */
    public function tableName() {
        return '{{useraccounts}}';
    }
    /**
     *
     * @return array validation rules for model attributes.
     */
    public function rules() {
        // NOTE: you should only define rules for those attributes that
        // will receive user inputs.
        return array (
            array ('username, mobile, password, password_repeat', 'required', 'on'=>'create'),
            array ('username', 'required', 'on'=>'update'),
            array ('username, password', 'length', 'max' => 255),
            array ('password', 'compare', 'on'=>'create'),
            // The following rule is used by search().
            // @todo Please remove those attributes that should not be searched.
            array ('id, username, password', 'safe', 'on' => 'search'));
    }
    /**
     *
     * @return array relational rules.
     */
    public function relations() {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array (
        );
    }
    /**
     *
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels() {
        return array (
            'id' => 'ردیف',
            'username' => 'نام کاربری',
            'password' => 'رمز عبور',
        );
    }
    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * Typical usecase:
     * - Initialize the model fields with values from filter form.
     * - Execute this method to get CActiveDataProvider instance which will filter
     * models according to data in model fields.
     * - Pass data provider to CGridView, CListView or any similar widget.
     * @return CActiveDataProvider the data provider that can return the models
     *         based on the search/filter conditions.
     */
    public function search() {
        // @todo Please modify the following code to remove attributes that should not be searched.
        $criteria = new CDbCriteria();
        $criteria->compare('id', $this->id);
        $criteria->compare('username', $this->username, true);
        $criteria->compare('password', $this->password, true);
        return new CActiveDataProvider($this, array ('criteria' => $criteria));
    }
    /**
     * Returns the static model of the specified AR class.
     * Please note that you should have this exact method in all your CActiveRecord descendants!
     * @param string $className active record class name.
     * @return Users the static model class
     */
    public static function model($className = __CLASS__) {
        return parent::model($className);
    }
    /**
     * Apply a hash on the password before we store it in the database
     */
    protected function afterValidate() {
        parent::afterValidate();
        if(!$this->hasErrors() && $this->getOriginalAttribute('password') != $this->password) {
            $this->password = $this->hashPassword($this->password);
        }
    }
    /**
     * Generates the password hash
     * @param string $password The password to hash
     * @return string The hashed password
     */
    public static function hashPassword($password) {
        return md5($password);
    }
    /**
     * Checks if the given password is correct
     * @param string The password to be validated
     * @return boolean Whether the password is valid
     */
    public function validatePassword($password) {
        return $this->hashPassword($password) === $this->password;
    }
    /**
     * Store original attributes in a backup area
     */
    public function afterFind() {
        $this->_attributesBackup = $this->attributes;
    }
    /**
     * Get original specific attribute
     * @param string $attribute The attribute name to retrieve
     * @return mixed The original attribute value
     */
    public function getOriginalAttribute($attribute) {
        if($this->_attributesBackup) {
            return $this->_attributesBackup [$attribute];
        }
        return null;
    }
}
5- مدل LoginForm رو ایجاد کنید (فایل protected/models/LoginForm.php) :
<?php
/**
 * LoginForm class.
 * LoginForm is the data structure for keeping
 * user login form data. It is used by the 'login' action of 'SiteController'.
 */
class LoginForm extends CFormModel {
    public $username;
    public $password;
    public $rememberMe;
    private $_identity;
    /**
     * Declares the validation rules.
     * The rules state that username and password are required,
     * and password needs to be authenticated.
     */
    public function rules() {
        return array (
            // username and password are required
            array ('username, password', 'required'), 
            // rememberMe needs to be a boolean
            array ('rememberMe', 'boolean'), 
            // password needs to be authenticated
            array ('password', 'authenticate'));
    }
    /**
     * Declares attribute labels.
     */
    public function attributeLabels() {
        return array ('username' => 'نام کاربری', 'password' => 'رمز عبور', 'rememberMe' => 'به خاطر بسپار');
    }
    /**
     * Authenticates the password.
     * This is the 'authenticate' validator as declared in rules().
     */
    public function authenticate($attribute, $params) {
        if(!$this->hasErrors()) {
            $this->_identity = new UserIdentity($this->username, $this->password);
            if(!$this->_identity->authenticate())
                $this->addError('password', 'Incorrect username or password.');
        }
    }
    /**
     * Logs in the user using the given username and password in the model.
     * @return boolean whether login is successful
     */
    public function login() {
        if($this->_identity === null) {
            $this->_identity = new UserIdentity($this->username, $this->password);
            $this->_identity->authenticate();
        }
        if($this->_identity->errorCode === UserIdentity::ERROR_NONE) {
            $duration = $this->rememberMe ? 3600 * 24 * 30 : 0; // 30 days
            Yii::app()->user->login($this->_identity, $duration);
            Yii::app()->user->id = $this->_identity->id;
            return true;
        }
        else
            return false;
    }
}
6- ویوی لاگین رو بسازین (protected/views/site/login.php) :


```
<?php
/* @var $this UserController */
$this->pageTitle = Yii::app()->name . ' - ورود';
?>
<h1>ورود به سایت</h1>
<hr />
<p>لطفاً فرم زیر را برای ورود به سایت تکمیل کنید:</p>
<form action="<?php echo Yii::app()->createUrl('site/login'); ?>" method="post">
    <table>
        <tr>
            <td><strong>نام کاربری یا ایمیل:</strong></td>
            <td><input name="LoginForm[username]" placeholder="نام کاربری" style="width: 150px;" type="text" /></td>
        </tr>
        <tr>
            <td><strong>رمز عبور:</td></tr>
            <td><input name="LoginForm[password]" placeholder="رمز عبور" style="width: 150px;" type="password" /></td>
        </tr>
        <tr>
            <td><strong>مرا بخاطر بسپار:</td></tr>
            <td><input name="LoginForm[rememberMe]" style="width: 150px;" type="checkbox" /></td>
        </tr>
        <tr>
            <td>&nbsp;</span>
            <td><input style="width: 150px;" type="submit" value="ورود" /></td>
        </tr>
    </table>
</form>
```

توصیه میکنم پکیج آموزش Yii رو که لینکش توی امضام هست، تهیه کنید. درصورت عدم تمایل برای صرف هزینه هم میتونید eBookهای خوبی که در این زمینه هست مثل Web Development with Yii and PHP و... رو مطالعه کنید. خود سایت Yii هم مستندات کامل و خوبی داره (yiiframework.com)

----------


## ranataher

با تشکر از کدها و راهنمایی های شما ,میدونم خیلی طولانی شد اما اگر امکان داره راهنماییم کنید
بله من ایجاد فرم login با اطلاعات database از طریق mvc  فراموش کرده بودم  . مدل هایی که گفته بودید قبلا ایجاد کرده بودیم اما نمیدانستم چگونه باید در فرم لاگین از انها استفاده نمایم 
اما هنوز مشکل من برطرف نشده : 
من کارهای زیر را انجام دادم 
1-بتدا توی فایل تنظیمات (protected/config/main.php)، کامپوننت db رو تنظیم کنید
2- اکشنهای login و logout رو به کنترلر site اضافه کنید (فایل protected/controllers/SiteController.php) :* بودند تغییر دادم به انچه که شما گفته بودید*
3- کلاس UserIdentity رو اصلاح کنید *با تغییر این کلاس و زدن نام کاربری و رمز پیغام  زیر را میدهد*
         include(Users.php): failed to open stream: No such file or directory    
               /var/www/yii/framework/YiiBase.php(427)
بر روی خطها 

 include($className.'.php'); در ادرس بالا

2----------------->

/var/www/html/voip/protected/components/UserIdentity.php(21): *spl_autoload_call*("Users")در این ادرس و در کد زیر
   $user = Users::model()->find('LOWER(username)=? AND confirmed=1', array(strtolower($this->username))); و از این دست پیغام ها در sitecontroller,model/Loginform.php,
4- مدل Users رو با کمک Gii ایجاد کنید *قبلا ایجاد کرده بودم اما از این قسمت به بعد را نداشت* یعنی این قسمت بود
*public static function model($className = __CLASS__) {**        return parent::model($className);*
*    }*
5-- مدل LoginForm رو ایجاد کنید *قبلا ایجاد کرده بودم اما این قسمت را به انچه شما گفته بودید تغییر دادم public function attributeLabels() {
*
6.ویوی لاگین رو بسازین *این قسمت را نیز کلا تغییر دادم به انچه شما گفته بودید*

----------


## ranataher

یک نکته ای فکر میکنم گفتنش مفید باشه در دیتا بیس من فیلدها رو به صورت  زیر که در مدل مربوطه نیز میباشد ساختم یعنی با *حروف بزرگ و کوچک  UserAccID, Username, Password, FullNameفکر کنم به پیغامی هم که components/UserIdentity.php میدهد ارتباط داشته باشد
*$user = Users::model()->find('LOWER(username)=? AND confirmed=1', array(strtolower($this->username)));*
مدل :
*array('Username, Password, FullName', 'required'),
            array('Username, Password', 'length', 'max'=>50),
            array('FullName', 'length', 'max'=>256),
            // The following rule is used by search().
            // @todo Please remove those attributes that should not be searched.
            array('UserAccID, Username, Password, FullName', 'safe', 'on'=>'search'),

----------


## MMSHFE

فکر نمیکنم ارتباطی داشته باشه چون MySQL حساس به بزرگی و کوچکی اسامی فیلدها نیست. فقط باید فیلدهای موردنظرتون رو به مدل اضافه کنید. راستش اینقدر کدها و متن رو قاطی هم نوشتین که نفهمیدم کدوم، کد هست و کدوم، خطا! اگه میشد توی پیام خصوصی تیم ویور بدین، خیلی راحتتر میشد مشکل رو رفع کنیم.

----------


## ranataher

> فکر نمیکنم ارتباطی داشته باشه چون MySQL حساس به بزرگی و کوچکی اسامی فیلدها نیست. فقط باید فیلدهای موردنظرتون رو به مدل اضافه کنید. راستش اینقدر کدها و متن رو قاطی هم نوشتین که نفهمیدم کدوم، کد هست و کدوم، خطا! اگه میشد توی پیام خصوصی تیم ویور بدین، خیلی راحتتر میشد مشکل رو رفع کنیم.


ببخشید شما درست میگید اما بعد از اینکه نقل قول ارسال میشود  کدها و نوشته ها به هم میریزد ،هنوز خوب کار کردن با این بخش رو یاد نگرفتم
ممنون از پیشنهادتون حتما این کار رو میکنم
 با تشکر از تمام راهنماییاتون

----------


## afsaneh67

سلام،من همه این مراحلو انجام دادم ولی لاگین نمی کنه و پیغام خطای Incorrect username or password. میده. میشه راهنماییم کنید.

----------


## MMSHFE

کدتون رو بگذارین تا بررسی کنیم. این موارد رو باید بگذارین:
1- کد متد actionLogin از protected/controllers/SiteController.php
2- فایل protected/models/LoginForm.php
3- فایل protected/components/UserIdentity.php
4- فایل protected/components/models/Users.php (مدل مربوط به جدول کاربران)
5- فایل protected/views/site/login.php

----------


## hamidreza_zamanian

بهترین راه ساخت login و فرم های ثبت نام که نیاز به تایید هوویت کاربران داره  استفاده از componnet UserIdentity و compontent webUser هست که در مسیر

protected\components ساخته میشن و شما میتوانید تمام role های کاربران اونجا تعریف کنید و براختی سطوح دسترسی مختلف رو با تابع  checkAccess تعریف کنید یرای نمونه مینونید به وب سایت 

http://nazarfa.ir مراجعه کنید من تو این وب سایت به وفور از این تکنیک استفاده کردم

----------


## یاسمن زهرا

سلام.ببخشید من از طریق تین لینک لاگین ساختم اما ارور میده .چه کار کنم؟ ممکنه در ایمیلم بفرمایید.https://barnamenevis.org/register.php?do=addmember



*PHP Compile Error – yii\base\ErrorException*

*Cannot redeclare backend\controllers\SiteController::actionLogin()*

----------


## یاسمن زهرا

لطفا جواب بدیددددد

----------

