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

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