Yii, Модуль SRBAC часть 2. Пишем регистрацию.



После того как мы подключили и настроили модуль srbac нам необходимо сделать регистрацию пользователей на нашем сайте. Этим сейчас и займемся.

Оговорюсь сразу, что для выполнения этого урока требуется yii версии 1.1.1 и дополнение email.

Почему взята именно эта, а не стабильная версия 1.1.0, потому что в новой версии появился очень интересный виджет «CActiveForm» позволяющий проводить валидацию форм на стороне клиента.

Кстати на счет этого виджета, если кто-то знает, как заставить его проводить валидацию по правилам, как например:

$model->validate('reg');

буду очень признателен.

Закончим это лирическое отступление и перейдем непосредственно к программированию.

Первым делам устанавливаем дополнение email. Как? На странице документации все подробно расписано и думаю, это затруднений не вызовет. Правда у данного модуля есть проблемка с отправлением сообщений на русском языке. Для ее устранения открываем “protected/extensions/email/Email.php” находим функцию mail() и заменяем mb_send_mail на mail. И все отлично работает.

У нас уже есть таблица User и конечно же модель User в папке “protected/models”.  Вот как выглядит моя таблица User:

CREATE TABLE IF NOT EXISTS `User` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(100) NOT NULL,
  `username` varchar(100) NOT NULL,
  `password` varchar(32) NOT NULL,
  `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `activationKey` varchar(32) NOT NULL,
  `status` varchar(1) NOT NULL,
  PRIMARY KEY (`id`)
)

На этом приготовления закончены, перейдем непосредственно к модулю регистрации.

Для этого создадим модуль “User” из консоли yiic и в DefaultController.php добавим функцию регистрации:

    /*
    * Регистрация
    *
    * @param
    * @return
    */
    public function actionRegistration() {

    }

После добавим вспомогательные функции для ajax валидации данных и для отправки кода активации на почту.

 protected function performAjaxValidation($model) {
        if(isset($_POST['ajax']) && $_POST['ajax']==='user-form') {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
    }


    /*
    * Отправление кода активации
    *
    * @param model $model
    * @return bolean
    */
    protected function activationKey($model) {
        $email = Yii::app()->email;
 
        $email->to = $model->email;

        $email->subject = 'Код активации аккаунта для сайта '.Yii::app()->name;

        $email->message = 'Код активации аккаунта: <a href="'.Yii::app()->homeUrl.'/user/default/activation/key/'.$model->activationKey.'">'.$model->activationKey.'</a>';
     
        $email->send();
    }

Тут все предельно просто. В первой функции проверяем, откуда пришел запрос и если он ajax то проводим валидацию данных.

Во второй функции создаем экземпляр класса email, устанавливаем значения для необходимых полей и отправляем письмо.

После этого простые рутинные операции, как при создании любой формы. Добавим действие captcha:

function actions() {
        return array('captcha'=>array(
                        'class'     =>'CCaptchaAction',
                        'maxLength' => 6,
                        'minLength' => 3,
                        'foreColor' => 0x667e9a,
                        'testLimit' => 2,)
        );
    }

Для вывода каптчи в форме регистрации и установим минимальную длинну кода на картинке в «3» символа, максимальную в «6», колличество попыток ввода до смены кода «2», что бы пользователь при ошибочном вводе кода видел свою ошибку.

Теперь создадим форму регистрации, для этого в папке «protected.modules/User/views/default» создадим файл “registration.php” и добавим следующий код:

<?php
$this->breadcrumbs=array(
        "Регистрация",
);
?>

<h1>Регистрация</h1>

<div class="form">
    <?php $form = $this->beginWidget('CActiveForm', array(
            'id'=>'user-form',
            'enableAjaxValidation'=>true,
    )); ?>

    <p class="note">Поля со <span class="required">*</span> обязательны.</p>

    <?php echo $form->errorSummary($model); ?>

    <div class="row">
        <?php echo $form->label($model, 'email', array('class' => 'required')); ?>
        <?php echo $form->textField($model, 'email')?>
        <?php echo $form->error($model,'email'); ?>
    </div>

    <div class="row">
        <?php echo $form->label($model, 'username'); ?>
        <?php echo $form->textField($model, 'username' )?>
        <?php echo $form->error($model,'username'); ?>
    </div>

    <div class="row">
        <?php echo $form->label($model, 'password'); ?>
        <?php echo $form->passwordField($model, 'password') ?>
        <?php echo $form->error($model,'password'); ?>
    </div>

    <div class="row">
        <?php echo $form->label($model, 'password2'); ?>
        <?php echo $form->passwordField($model, 'password2') ?>
        <?php echo $form->error($model,'password2'); ?>
    </div>

    <div class="row">
        <?php $this->widget('CCaptcha', array('buttonLabel' => '<br>[новый код]')); ?>
        <?php echo $form->label($model, 'captcha'); ?>
        <?=CHtml::activeTextField($model,'captcha'); ?>
    </div>

    <div class="row submit">
        <?=CHtml::submitButton('Зарегистрироваться', array('id' => "submit")); ?>
    </div>

    <?php $this->endWidget(); ?>
</div><!-- form -->

Перейдем к доработке модели User. Добавим два параметра:

public $captcha;
public $password2;

Установим имена для аттрибутов:

public function attributeLabels() {
         return array(
             'email'     => 'E-mail адресс:',
             'username'  => 'Имя пользователя:',
             'password'  => 'Пароль:',
             'password2' => 'Пароль еще раз:',
             'captcha'   => 'Введите код с картинки:',
         );
     }

И опишем правила валидации для полей:

/*
    * Правила валидации
    *
    * @param
    * @return
    */
    public function rules() {
        return array(
            array('email, username, password, password2, captcha', 'required', 'on'=>'reg'),
            array('password2', 'compare', 'compareAttribute' => 'password', 'on'=>'reg'),
            array('captcha',  'captcha', 'allowEmpty' => !extension_loaded('gd'), 'on'=>'reg'),
 
            array('email, username', 'required', ),
            array('email',    'match',   'pattern'    => '/^([a-z0-9_\.-]+)@([a-z0-9_\.-]+)\.([a-z\.]{2,6})$/', 'message' => 'Не верный формат e-mail адреса.'),
            array('username', 'match',   'pattern'    => '/^[A-Za-z0-9_-А-Яа-я\s,]+$/u','message'  => 'Логин содержит недопустимые символы.'),
                       
            array('username, email',     'length',  'max' => '100', 'min' => '3',),
            array('password, password2', 'length',  'max' => '40',  'min' => '5',),
        );
    }

Расписывать правила валидации не буду, про это и так много всего написано.

Теперь создадим представление для сообщения об успешной регистрации. Добавим в «protected.modules/User/views/default» файл «registratoinOk.php» со следующим содержимым:

<?php
$this->breadcrumbs=array(
                "Регистрация",
);
?>

<h1>Регистрация</h1>

<div id="content">
    <h1>Пользователь успешно добавлен!</h1>
</div>

Ну и наконец перейдем непосредственно к коду нашей регистрации:

/*
    * Регистрация
    *
    * @param
    * @return
    */
    public function actionRegistration() {
        if (Yii::app()->user->isGuest) {
 
            $user = new User;
 
            /*
            * Ajax валидация
            */
            $this->performAjaxValidation($user);

            if(empty($_POST['User'])) {
                /*
                * Если форма не отправленна, то выводим форму
                */
                $this->render('registration', array('model' => $user));

            } else {
                /*
                * Форма получена
                */
                $user->attributes = $_POST['User'];

                /*
                * Валидация данных
                */
                if($user->validate('reg')) {
                    /*
                    * Если проверка пройдена, проверяем на уникальность имя
                    * пользователя и e-mail
                    */
                    if($user->model()->count("email = :email",
                        array(':email' => $user->email))) {

                        $user->addError('email', 'E-mail уже занят');
                        $this->render("registration", array('model' => $user));

                    } else if($user->model()->count("username = :username",
                        array(':username' => $user->username))) {

                        $user->addError('username', 'Имя пользователя уже занято');
                        $this->render("registration", array('model' => $user));

                    } else {
                        /*
                        * Если проверки пройдены шифруем пароль, генерируем код
                        * активации аккаунта, а также устанавливаем время регистрации
                        * и роль по умолчанию для пользователя
                        */
                        $user->password      = md5(md5($user->password));
                        $user->activationKey = substr(md5(uniqid(rand(), true)), 0, rand(10, 15));
                        $user->status        = '0';

                        /*
                        * Проверяем если добавление пользователя прошло успешно
                        * устанавливаем ему права.
                        */
                        if($user->save()) {
                            $role = new AuthAssignment();
                            $role->itemname = 'User';
                            $role->userid   = $user->id;

                            if($role->save()) {
                                /*
                                * Если роль успешно добавилась, выводим сообщение
                                * об успешной регистрации и отправляем код активации аккаунта
                                */
                                $this->render("registrationOk");

                                $this->activationKey($user);

                            } else {
                                throw new CHttpException(403, 'Ошибка добавления в базу данных.');
                            }
                        } else {
                            throw new CHttpException(403, 'Ошибка добавления в базу данных.');
                        }
                    }
                } else {
                    /*
                    * Не прошел валидацию
                    */
                    $this->render('registration', array('model' => $user));
                }
            }
        } else {
            /*
            * Если пользователь залогинен редиректим обратно
            */
            $this->redirect(Yii::app()->user->returnUrl);
        }
    }

Я думаю комментариев в коде достаточно, что бы просто его понять. Если возникнут вопросы пишите в комментариях.

В следующем уроке мы будем делать активацию аккаунта.



Теги: , , ,

Комментарии

  1. Здорово. Уже давно ждал продолжения…
    Пока один маленький вопрос:
    А чем не устроил родной валидатор email?

    Reply

  2. оооо и правда)) Даже не знаю, что ответить) Заработался наверно…

    Reply

  3. Огромное человеческое спасбо!

    Reply

  4. Вы знаете редко сейчас кто пишет по данной тематике, очень приятно читать, я бы советовала картинок добавить еще!

    Reply

  5. Да, вот на счет картинок тоже думал)

    Reply

  6. Прочесть было очень интересно, а потом каша в голове.
    не чего не понял как это работает.

    Reply

  7. а что именно не понятно?

    Reply

  8. Умиляет:
    создаешь тему «Пишем спамер WordPress блогов», а потом отвечаешь на спам
    😉

    Reply

  9. Ирония судьбы, спамеры в основном спамят пост про wordpress спамер 🙂

    Reply

  10. А как всю эту регистрацию запустить на сайте? по какой ссылке? и надо ли для модуля User прописывать что либо в config/main.php?

    Reply

  11. запустить можно по site,ru/user/default/registration а в конфиге надо просто добавить ‘user’ к массиву modules

    ‘modules’ => array(
    ‘user’,
    ),

    Reply

  12. Для проверки на уникальность можно использовать валидатор «unique»

    «как заставить его проводить валидацию по правилам» — использовать сценарии
    в правилах :
    array(‘pwd’,’required’,’on’=>’registration’),
    в контроллере
    $model->scenario=’registration’;

    Reply

  13. если в #63 прошло сохранение в базу, а в #68 вылетел эксепшн, то получаем пользователя без выставленных прав

    Reply

  14. да) чет не подумал

    Reply

  15. Сделал все как описано в статье, но при попытке регистрации вываливается ошибка :
    YiiBase::include(AuthAssignment.php) [function.YiiBase-include]: failed to open stream: No such file or directory

    Матюкается видимо на этот кусок кода :

    $role = new AuthAssignment();

    Сохранение в базу проходит нормально.
    Как решить данную траблу?

    Спасибо.

    Reply

  16. Создать таблицу AuthAssignment в базе и создать модель AuthAssignment.

    Для этого идем в директорию framework/web/auth/, там хранится схема нужных нам таблиц «schema.sql«. Просто копируем все содержимое в phpmyadmin и выполняем запрос. У нас в базе появились 3 новых таблицы:

    цитата из первой статьи

    Reply

  17. при создании экземпляра модели указываем сценарий и проверка идет по данному сценарию
    $user = new User(‘reg’);

    Reply

  18. Ругается, в логе пишет:
    Не удалось присвоить небезопасный атрибут «captcha»
    Функция:
    01 protected function performAjaxValidation($model) {
    02 if(isset($_POST[‘ajax’]) && $_POST[‘ajax’]===’user-form’) {
    03 echo CActiveForm::validate($model);
    04 Yii::app()->end();
    05 }
    06 }
    Строка 3.
    Help me!

    Reply

  19. yii какой версии?

    если 1.0.*

    то нужно добавить

    public function safeAttributes()
    {
    return array(
    parent::safeAttributes(),
    ‘reg’ => ‘captcah и все остальные через запятую’
    );
    }

    Reply

  20. Спасибо!
    Я сделал в модели:
    array(‘captcha’, ‘safe’),
    Но, правильно ли теоретически? Привычка, подвергать сомнениям ВСЁ, что вводит пользователь на своё усмотрение.

    Reply

  21. ну можно проверить данные, хотя они же ни куда не сохраняются и не выводятся, так что не особо важно

    Reply

  22. Спасибо за статью, но у вас ошибочка имеется.
    Вместо:
    $email->message = ‘Код активации аккаунта: homeUrl.’/user/default/activation/key/’.$model->activationKey.'»>’.$model->activationKey.’‘;

    нужно:
    $email->message = ‘Код активации аккаунта: request->hostInfo.’user/default/activation/key/’.$model->activationKey.'»>’.$model->activationKey.’‘;

    Reply

  23. Обрезало немного 🙁
    Вот это нужно писать:
    Yii::app()->request->hostInfo
    а не
    Yii::app()->homeUrl

    Reply

  24. А разве Yii::app()->createAbsoluteUrl(‘user/default/activation/key/’.$model->activationKey) уже отменили?

    Reply

  25. У меня тоже не видит файл AuthAssignment. Уже где я его только не создавал — бесполезно. Что делать?

    Reply

    Max Reply:


    Проверьте создана ли таблица и есть ли нужная модель. В новой версии srbac’a модель называется Assignments и находится в файле Assignments.php. Поэтому нужно делать так: $role = new Assignments();

    Reply

    vitalka Reply:


    Я повторно внимательно уже 2-й раз переставил srbac.
    Сделал как вы написали: $role = new Assignments();
    Но опять таки получаю ошибку:
    «include(Assignments.php) [function.include]: failed to open stream: No such file or directory»

    Что сделать, что бы класс Assignments (и файл этого класса) был доступен ?

    Reply

    vitalka Reply:


    Для полной картины добавлю ещё пути к файлам:
    \protected\modules\srbac\models\Assignments.php

    \protected\modules\user\controllers\DefaultController.php

    Все верно?
    Но класс Assignments не видится … (

  26. Николай

    Какие есть предложения по исправлении такой ошибки:
    Missing argument 1 for CAuthAssignment::__construct(), called in Z:\home\one\www\protected\controllers\UserController.php on line 75 and defined

    В базу все сохраняет, ну как доходит до этого места, вылетает ошибка

    $role = new CAuthAssignment();

    $role->_itemName = ‘User’;
    $role->_userId = $user->id;

    Reply

    Николай Reply:


    Всеееееееее разобрался

    Reply

  27. Маленький вопросик. Путь должен идти
    protected.modules/User/views/default
    то есть создать папку в модуле, где у нас srbac создать User/views/default, или сначала зайти в srbac потом создать, то так будет же
    protected.modules/srbac/User/views/default

    А контроллер DefaultController.php описывать это тот, что в srbac
    Спасите новичка

    Reply

  28. туплю страшно оО.
    Разобрался

    Reply

  29. Замечательно что есть такие блоги.
    Но на мое мнение лучше так
    public function actionRegistration()
    {
    $user = new User;
    if(isset($_POST[‘User’])) {
    $user->scenario = ‘reg’; // устанавливаем сценарий
    $user->attributes = $_POST[‘User’];
    if($user->save()) {
    $auth = Yii::app()->authManager();
    $auth->assign(‘User’,$user->id); // не дергаем лишний раз модель
    // дальнейшие действия
    }
    }
    $this->render(‘registration’,array(‘model’=>$user))
    }
    А проверку гость ли это или нет можно добавить в accessRule()

    Reply

  30. Установил с нуля. Но регистрация нового пользователя доступно только для авторизованных. как убрать?

    Reply

  31. Сложно сказать без кода. Возможно проблема в фильтре access control.

    Reply

  32. В базу запись добавляется, но на страничке выдается warning: «include(AuthAssignment.php) [function.include]: failed to open stream: No such file or directory».

    Подскажите как поправить?
    Спасибо.

    Reply

    vitalka Reply:


    Нашел откуда вызов: protected\modules\user\controllers\DefaultController.php(77)
    и вот сам код:
    if($user->save()) {
    $role = new AuthAssignment();
    $role->itemname = ‘User’;
    $role->userid = $user->id;
    То есть Yii пытается подгрузить класс AuthAssignment и не находит его.
    Подскажите, может я что-то пропустил, где или на каком этапе должен быть создан файл/класс AuthAssignment.php ?

    Reply

    Max Reply:


    @vitalka, вы в /main/config.php подключаете этот класс? Должно быть, что-то вроде: ‘application.modules.admin.modules.srbac.models.Assignments.php

    Reply

  33. @vitalka. Есть также, уже собранный блог с srbac — https://code.google.com/p/srbac/downloads/detail?name=blog-srbac_1.2_r228.zip&can=2&q=. На его примере, можно посмотреть, как все работает.

    Reply

Оставить комментарий