DbHelp.ru
Маленький Yii блог
Комментарии
Гость: комент
Гость: wahaha
zolter: Друпал на Yii? ))
nastia: http://drupal.org/
JB: Да там просто ад)) мне всего 3 значения нужно чтобы выпадало, все равно спасибо)...



Сервер Ultima Online - Forest Wars (от создателя данного блога)

Урок 6 : Регистрация и авторизация. Часть 1

Рубрика: Создаем блог вместе

Оцените эту статью:

Рейтинг: 0.00 (0)
24 Июн. 2009
Опубликовать в Twitter Написать в Facebook Опубликовать в своем блоге livejournal.com

Эта статья устарела т.к. была написана для yii версии 1.0.х; Если вы используете более новую версию - у вас могут возникнуть ошибки из-за несовместимости. Обычно ответы на все вопросы работы на 1.1.х были описаны в комментариях ниже статьи.

Сегодня с вами хотел бы поговорить про такую вещь как авторизация, регистрация и аутентификация. В дальнейшем я предполагаю что пользователи нашего блога смогут оставлять комментарии, сами создавать статьи и редактировать свой профиль. Чтобы это реализовать - надо во-первых разграничивать права пользователей, а во-вторых написать саму регистрацию (и обработку этих самых пользователей)...

---

Вступление

Я думаю моя статья не тянет на премию оригинальности т.к. вопросы освещенные в ней уже много раз поднимались ("Аутентификация и авторизация" [рус] и "Building a Blog System using Yii" [англ]). Несмотря на то что уже много было сказано по этой теме, я не могу пропустить такой важный момент в своей серии уроков "Создаем блог вместе".

Начнем

Наш небольшой план на данный урок выглядит следующим образом:

  1. Создаем для пользователя отдельный контроллер
  2. Создаем модель для работы с таблицей "users"
  3. Создаем форму регистрации
  4. Работа с моделью. Правила валидации
  5. Создаем форму авторизации
  6. Привязываем механизм авторизации
  7. Работа с моделью. Правила валидации

Приступим...

Создаем отдельный контроллер

Так как пользователи на нашем сайте это отдельные логические единицы которые должны в будущем обладать функциями:

  • Авторизации
  • Изменения профиля
  • Выхода (logout)
  • и тп.

то логичнее будет выделить всё это в отдельный контроллер.

Открываем protected/controllers и создаем UserController.php:

<?php
/**
 * UserController
 *
 * Контроллер для наших пользователей. Содержит в себе следующие функции:
 * - авторизация
 * - регистрация
 * - выход
 * - редактирование профиля [в будущем]
 *
 * @version 1.0
 *
 */
class UserController extends CController
{      
    public function actions()
    {
        return array(
            // Создаем экшинс captcha.
            // Он понадобиться нам для формы регистрации (да и авторизации)
            'captcha'=>array(
                'class'=>'CCaptchaAction',
                'backColor'=> 0x003300,
                'maxLength'=> 3,
                'minLength'=> 3,
                'foreColor'=> 0x66FF66,
            ),
        );
    }
   
    /**
     * Метод входа на сайт
     *
     * Метод в котором мы выводим форму авторизации
     * и обрабатываем её на правильность.
     */
    public function actionLogin()
    {
    }   
   
    /**
     * Метод выхода с сайта
     *
     * Данный метод описывает в себе выход пользователя с сайта
     * Т.е. кнопочка "выход"
     */
    public function actionLogout()
    {
    }
   
    /**
     * Метод регистрации
     *
     * Выводим форму для регистрации пользователя и проверяем
     * данные которые придут от неё.
     */
    public function actionRegistration()
    {
    }
   
}
Я сразу добавил туда пустых методов которые нам понадобятся. Надеюсь прочитав комментарии вам сразу стало понятно что для чего :)

Создаем модель

Как вы понимаете все наши пользователи будут находиться в таблице user. Сама таблица у нас уже была создана в прошлых уроках, а вот модель для её работы мы не создали. Я надеюсь вы помните по старым урокам что именно модель является связующим звеном нашего контроллера с базой данных, поэтому мы в ней очень сильно нуждаемся.

Заходим в protected/models и создаем файл User.php:
<?php
class User extends CActiveRecord
{       
    // для капчи
    public $verifyCode;
    // для поля "повтор пароля"
    public $passwd2;
   
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
    public function tableName()
    {
        return 'user';
    }
}
Нам этого каркаса хватит для простой работы с таблицей user. Правила влаидации, лэйблы и сэйв атрибуты - мы напишем чуть-чуть позже (в этом уроке!).

Создаем форму регистрации

Создание формы регистрации в принципе включает в себя два пункта: создание отображение, обработка формы в экшинсе.
Давайте будем двигаться по логичной схеме и первым делом создадим actionRegistration

И так если вы забыли, открыть надо UserController.php. У нас там есть:
    public function actionRegistration()
    {
    }
заменяем на нечто подобное:
    public function actionRegistration()
    {
        // тут думаю все понятно
        $form = new User();

        // Проверяем являеться ли пользователь гостем
        // ведь если он уже зарегистрирован - формы он не должен увидеть.
        if (!Yii::app()->user->isGuest) {
            throw new CException('Вы уже зарегистрированны!');
        } else {
            // Если $_POST['User'] не пустой массив - значит была отправлена форма
            // следовательно нам надо заполнить $form этими данными
            // и провести валидацию. Если валидация пройдет успешно - пользователь
            // будет зарегистрирован, не успешно - покажем ошибку на экран
            if (!empty($_POST['User'])) {
               
                // Заполняем $form данными которые пришли с формы
                $form->attributes = $_POST['User'];
               
                // Запоминаем данные которые пользователь ввёл в капче
                $form->verifyCode = $_POST['User']['verifyCode'];
               
                    // В validate мы передаем название сценария. Оно нам может понадобиться
                    // когда будем заниматься созданием правил валидации [читайте дальше]
                    if($form->validate('registration')) {
                        // Если валидация прошла успешно...
                        // Тогда проверяем свободен ли указанный логин..

                            if ($form->model()->count("login = :login", array(':login' => $form->login))) {
                                // Указанный логин уже занят. Создаем ошибку и передаем в форму
                                $form->addError('login', 'Логин уже занят');
                                $this->render("registration", array('form' => $form));
                            } else {
                                // Выводим страницу что "все окей"
                                $form->save();
                                $this->render("registration_ok");
                            }
                                           
                    } else {
                        // Если введенные данные противоречат
                        // правилам валидации (указаны в rules) тогда
                        // выводим форму и ошибки.
                        // [Внимание!] Нам ненадо передавать ошибку в отображение,
                        // Она автоматически после валидации цепляеться за
                        // $form и будет [автоматически] показана на странице с
                        // формой! Так что мы тут делаем простой рэндер.
                       
                        $this->render("registration", array('form' => $form));
                    }
            } else {
                // Если $_POST['User'] пустой массив - значит форму некто не отправлял.
                // Это значит что пользователь просто вошел на страницу регистрации
                // и ему мы должны просто показать форму.
               
                $this->render("registration", array('form' => $form));
            }
        }
    }
После такого кол-ва комментариев в коде - логику как это работает думаю можно не объяснять. Как вы видите после успешной регистрации я делаю render страницы registration_ok. Такой страницы у нас пока еще не создано (как и registration), но их создание будет описано дальше.

Проверку на то, занят логин или нет, я делаю в экшинсе специально. Этим я хотел показать вам
что вы можете использовать addError в контроллере. Правильнее было бы вынести это в качестве
отдельного правила (rules) в модель.

Для вывода ошибок я использую встроенный класс CException. Это весьма неудобно на рабочих проектах,
поэтому вы можете заменить эту строчку на render какой то страницы для ошибок.

Теперь перейдем к созданию непосредственно самой формы.

Заходим в views/user и создаем registration_ok.php:
<h1>Спасибо</h1>
<p>Регистрация прошла успешно. Теперь вы можете войти под своим логином</p>

Теперь там же создаем registration.php:
<h1>Регистрация</h1>

<!-- Открываем форму !-->
<?=CHtml::form(); ?>
<!-- То самое место где будут выводиться ошибки
     если они будут при валидации !-->
<?=CHtml::errorSummary($form); ?><br>

    <table id="form2" border="0" width="400" cellpadding="10" cellspacing="10">
        <tr>
            <!-- Выводим поле для логина !-->
            <td width="150"><?=CHtml::activeLabel($form, 'login'); ?></td>
            <td><?=CHtml::activeTextField($form, 'login') ?></td>
        </tr>
        <tr>
            <!-- Выводим поле для пароля !-->
            <td><?=CHtml::activeLabel($form, 'passwd'); ?></td>
            <td><?=CHtml::activePasswordField($form, 'passwd') ?></td>
        </tr>
        <tr>
            <!-- Выводим капчу !-->
            <td><?php $this->widget('CCaptcha', array('buttonLabel' => '<br>[новый код]')); ?></td>
            <td><?=CHtml::activeTextField($form,'verifyCode'); ?></td>
        </tr>
        <tr>
            <td></td>
            <!-- Кнопка "регистрация" !-->
            <td><?=CHtml::submitButton('Регистрация', array('id' => "submit")); ?></td>
        </tr>
    </table>

<!-- Закрываем форму !-->
<?=CHtml::endForm(); ?>
Я добавил немного комментариев к отображению. Советую удалить их сразу после прочтения т.к.
они будут видны в html коде вашей страницы.

В принципе форма наша уже работает. Зайдите на страницу localhost/user/registration/ и попробуйте.
Если после регистрации вы увидите ошибку от базы данных - не удивляйтесь, ведь наша форма не проверяет входящие данные.

Вы наверняка подумали что я сошел сума, ведь мы используем $form->validate в нашем контроллере и валидация теоретически должна проходить. Теоретически - она проходит, но вы забыли что правил валидации мы негде не указывали :] Поэтому независимо от введенных данных - валидация по пустым правилам будет говорить что всё окей :] Поэтому идем в модель и исправляем это безобразие :]

Работа с моделью. Правила валидации.

Открываем protected/models/User.php. Добавляем туда метод rules :
    /**
     * Правила валидации
     */
    public function rules()
    {
        return array(
            // логин, пароль не должны быть больше 128-и символов, и меньше трёх
            array('login, passwd', 'length', 'max'=>128, 'min' => 3),
            // логин, пароль не должны быть пустыми
            array('login, passwd', 'required'),
            // для сценария registration поле passwd должно совпадать с полем passwd2
            array('passwd', 'compare', 'compareAttribute'=>'passwd2', 'on'=>'registration'),
            // правило для проверки капчи что капча совпадает с тем что ввел пользователь
            array('verifyCode', 'captcha', 'allowEmpty'=>!extension_loaded('gd')),
            array('login', 'match', 'pattern' => '/^[A-Za-z0-9А-Яа-я\s,]+$/u','message' => 'Логин содержит недопустимые символы.'),
        );
    }
Этих правил нам будет достаточно для формы регистрации. Теперь зададим safeAttributes, т.е. те поля которые могут быть массово присвоены. safeAttributes выступает в качестве некого защитного механизма. Объясняю в двух словах как это работает и от чего защищает.

У нас есть форма регистрации. Когда мы отправляем её в экшинс приходят данные в виде $_POST массива, значения которого мы массово присваиваем в $form при помощи строчки:
$form->attributes = $_POST['User'];

Это аналогично если бы мы сделали:
 $form->login = $_POST['User']['login'];
$form->passwd = $_POST['User']['passwd'];
$form->passwd2 = $_POST['User']['passwd2'];

и т.п.

После этого проходит валидация и все эти данные сохраняются в базу данных через вызов метода $form->save(). Метод save() проверяет заполнено ли значение первичного ключа в $form (т.е. $form->id): если заполнено - делает update этой записи, если не заполнено - делает insert новой записи в базу данных.

Т.к. у нас id с формы не передается - метод save() всегда будет вставлять новую запись (делать insert), а не делать обновление (update) какой то записи. Все было бы хорошо, но злоумышленник может сохранить вашу форму к себе на компьютер, добавить туда поле "id". Теперь он делает отправку формы с заведомо заполненным полем "id" и у нас получается что метод save() не вставит новую запись, а проведет обновление логина, пароля для записи с указанным "id".

Так вот чтобы строчка
$form->attributes = $_POST['User'];

не присваивала в $form переменные которые мы не предполагаем там видеть - надо использовать safeAttributes.В методе safeAttributes() мы перечисляем список полей которые могут быть массово присвоены. Мой метод выглядит следующим образом:
    /**
     * Список атрибутов которые могут быть массово присвоены
     * в любом из наших сценариев
     *
     * @return unknown
     */
    public function safeAttributes()
    {
        return array('login', 'passwd', 'passwd2', 'verifyCode');
    }

После этого нам нестрашно что кто то будет изменять нашу форму и добавлять туда поля "id". Даже если в $_POST['id'] будет значение - метод safeAttributes не позволит ему попасть в $form->id.

Теперь давайте зададим лэйблы. Вы наверняка заметили что на форуме у нас в качестве названия поля выводить "login", "passwd" и тп. Хотелось бы, конечно, это изменить на более понятный язык (русский). Для этого добавляем в модель:
     /**
     * Список синонимов
     */
    public function attributeLabels()
    {
        return array(
            'login'      => 'Логин',
            'passwd'  => 'Пароль',
            'passwd2' => 'Повтори пароль',
        );
    }

Это так, лирическое отступление. Наш файл protected/models/User.php должен выглядеть следующим образом:
<?php
class User extends CActiveRecord
{       
    // для капчи
    public $verifyCode;
    // для поля "повтор пароля"
    public $passwd2;
   
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
   
    public function tableName()
    {
        return 'user';
    }

    /**
     * Правила валидации
     */
    public function rules()
    {
        return array(
            // логин, пароль не должны быть больше 128-и символов, и меньше трёх
            array('login, passwd', 'length', 'max'=>128, 'min' => 3),
            // логин, пароль не должны быть пустыми
            array('login, passwd', 'required'),
            // для сценария registration поле passwd должно совпадать с полем passwd2
            array('passwd', 'compare', 'compareAttribute'=>'passwd2', 'on'=>'registration'),
            // правило для проверки капчи что капча совпадает с тем что ввел пользователь
            array('verifyCode', 'captcha', 'allowEmpty'=>!extension_loaded('gd')),
            array('login', 'match', 'pattern' => '/^[A-Za-z0-9А-Яа-я\s,]+$/u','message' => 'Логин содержит недопустимые символы.'),
        );
    }
   
    /**
     * Список атрибутов которые могут быть массово присвоены
     * в любом из наших сценариев
     *
     * @return unknown
     */
    public function safeAttributes()
    {
        return array('login', 'passwd', 'passwd2', 'verifyCode');
    }
   
    /**
     * Список синонимов
     */
    public function attributeLabels()
    {
        return array(
            'login'      => 'Логин',
            'passwd'  => 'Пароль',
            'passwd2' => 'Повтори пароль',
        );
    }
}

Вот в принципе с регистрацией мы закончили. Заходим на страницу localhost/user/registration/ и пробуем.

К сожалению, урок получился достаточно затяжной, поэтому авторизацию я вынесу в отдельную часть. 
Ждите продолжение "Урок 6 : Регистрация и авторизация. Часть 2" в ближайшие дни.

Исходники:



Если хотите опубликовать этот материал у себя - пожалуйста, разместите ссылку на страницу откуда вы его взяли.
Другие yii статьи:

  1. Рассмотрим правильный вариант решения задачи поставленной в статье "Шаг 5: Контроллер". next Тем кто читает все статьи за один ... "Шаг 5: Контроллер Д/З"

  2. Поздравляю Всех своих читателей и случайных посетителей с уже наступившим 2011 годом. Желаю Вам в новом году чтобы все ... "Всех с новым годом!"

  3. Сегодня обнаружил что мой бывший сокурсник написал свой некий мод на Yii Blog. Исходные коды я не смотрел, но ... "Yii blog new [update]"

[guest] Гость

Было сказано: Среда, 24 Июнь 2009

Спасибо за новое чтиво! =)

romanoza

Было сказано: Среда, 24 Июнь 2009

я бы для поля login сделал unique

[adm] zolter

Было сказано: Среда, 24 Июнь 2009

Ага. Как я и написал - лучше проверять уникальность в моделе через правила (тот же unique). Но что б народ понял как юзать addError - я этого не делал :)

[guest] Макс

Было сказано: Четверг, 25 Июнь 2009

Большое спасибо за статью!

[guest] Гость

Было сказано: Четверг, 25 Июнь 2009

Супер! Жду вторую часть!

[guest] Рио

Было сказано: Четверг, 25 Июнь 2009

Когда примерно будет вторая часть?

[adm] zolter

Было сказано: Четверг, 25 Июнь 2009

Постараюсь сегодня-завтра.

[adm] zolter

Было сказано: Суббота, 27 Июнь 2009

К сожалению, продолжение будет не раньше вторника.

[guest] Гость

Было сказано: Понедельник, 29 Июнь 2009

А как задать права доступа к определенному виджету? Т.е., например, отображать виджет только для админа или для аторизированных пользователей?

[adm] zolter

Было сказано: Вторник, 30 Июнь 2009

Наверное моё способ будет не самым красивым (других просто еще не нашёл). В общем, в самом отображении там где делаете вывод виджета - окружаете блок в if следующего вида:


<?php if (Yii::app()->user->isGuest): ?>
... тут сам вывод виджета на страницу...
<?php endif; ?>


этим мы добьемся что виджет будут видить только гости (не авторез. пользователи сайта). если надо что б гости не видели, а видели тока пользователи тогда


<?php if (!Yii::app()->user->isGuest): ?>
... тут сам вывод виджета на страницу...
<?php endif; ?>

[adm] zolter

Было сказано: Четверг, 02 Июль 2009

ВНИМАНИЕ!! В коде была допущена ошибка из-за которой зарегистрированный пользователь не попадал в базу данных. Если вы читаете этот комментарий значит код статьи уже исправлен (файлы исходников тоже).

Ошибка была в коде контроллера:

                             } else {
// Выводим страницу что "все окей"
$this->render("registration_ok");
}


перед $this->render надо добавить строчку сохранения:

 $form->save();


Извиняюсь за допущенную ошибку.

[guest] patison

Было сказано: Понедельник, 20 Июль 2009

Супер вообще! Хоть я и сделал регистрацию пользователей до прочтения этой статьи, всё равно интересно ознакомиться с вашим подходом, и предвкушаю уже чтение второй части.

зы кстати всем любителям JS валидаций, очень советую extension jformvalidate. погуглите, обязательно найдёте. Сегодня наткнулся, поставил, и не нарадуюсь. Валидация формы средствами jQuery :)

[guest] patison

Было сказано: Понедельник, 20 Июль 2009

А кстати, такой вопрос к Вам по поводу safeAttributes.
У меня ведь модель для User верно? safeAttributes относится ко всем actions'ам данной модели, так? Оно хорошо сработает если пользователь создаётся (и нужен инсерт в базу). А что если пользователь редактирует себя (или админ его редактирует)? В таком случае НУЖНО передавать id, а safeAttributes будет фильтровать.

[adm] zolter

Было сказано: Понедельник, 20 Июль 2009

Верно. Сэйв атрибутес спасает вас от массового присваивания. Т.е. на строчке

$form->attributes = $_POST['User'];

вы в $form->id данных не получите. Но ничего не мешает вам сделать вот так:

$form->attributes = $_POST['User'];
$form->id = $_POST['User']['id'];


в том экшинсе в котором вы точно знаете что id будет передано с формы.

[adm] zolter

Было сказано: Понедельник, 20 Июль 2009

Кстати! При редактировании пользователя самим собой же (к примеру изменение своего профиля) - id с формы передавать не надо! Для этого просто берите id текущего авторизированного пользователя т.е. Yii::app()->user->id; иначе вам могут прислать не то что вы ожидаете.

[guest] patison

Было сказано: Понедельник, 20 Июль 2009

Хм.. Вы знаете, мне уже кажется что гораздо проще конкретно присваивать конкретные значения, и их уже валидировать.
Т.е. в каждом экшне я знаю что должно придти, и я не морочу себе моск и просто пишу:
$form->id=$_POST['User']['id'];
$form->username=$_POST['User']['name']
и т.д.
Тогда можно ничего не бояться, кроме криво введённых данных :)

[adm] zolter

Было сказано: Понедельник, 20 Июль 2009

Не проще :) Вы меня поймете когда поработаете с формами >25 параметров, к примеру. :) а для простых форм в принципе можно и в ручную присваивать как вы описали.

[guest] patison

Было сказано: Вторник, 21 Июль 2009

Угу. т.е. либо Ваш вариант, либо мой. так получается? третьего не дано? например определять safeAttributes для каждого экшна в отдельности?

[adm] zolter

Было сказано: Вторник, 21 Июль 2009

ВотЪ http://dbhelp.ru/add-yii-captcha/page/#comment-459 :)

[guest] Гость

Было сказано: Понедельник, 31 Август 2009

после регистрации юзера не мешало бы редиректнуть его на страницу "Спасибо за регистрацию" сами знаете зачем.

[guest] snn

Было сказано: Понедельник, 31 Август 2009

Например вот так


$form->save();
$this->redirect('registrationok', true);

[adm] zolter

Было сказано: Понедельник, 31 Август 2009

В принципе можна и на этой странице просто отрендерить "спасибо за регистрацию без редиректов". ну это на вкус и цвет :)

[guest] zzz

Было сказано: Пятница, 04 Сентябрь 2009

Вместо

if (!Yii::app()->user->isGuest) {
throw new CException('Вы уже зарегистрированны!');

Лучше, пожалуй, использовать правило
                 
array('allow',
'actions'=>array('registration'),
'users'=>array('?'),

в accessRules() контроллера

[adm] zolter

Было сказано: Пятница, 04 Сентябрь 2009

Это на вкус и цвет :)

[guest] Гость

Было сказано: Вторник, 24 Ноябрь 2009

Возможно у меня глупый вопрос, но пароль шифровать необязательно?
MD5('passwd')

я предпочитаю хранить в базе зашифрованные пароли

или степень защиты достаточная в самом фреймворке?
Как изменить код чтобы пароль попадал в базу в зашифрованном виде?

[adm] zolter

Было сказано: Среда, 25 Ноябрь 2009

Конечно, лучше шифровать. На каком уровне защиты останавливаться - решать только вам, обычно простого md5 достаточно.

Для того что б прикрутить шифрование пароля и его проверку при авторизации, вам требуется изменить следующие методы:

UserIdentity:
Там где идет проверка пароля в базе с введенным паролем в форме, вместо:

if($record->passwd!==$this->password)

делаем
if($record->passwd!==md5($this->password))


Теперь нам надо что б при самой регистрации, в базу летели пароли уже с md5 шифрованием. для этого делаем в actionRegistration(), изменяем следующий код:

if ($form->model()->count("login = :login", array(':login' => $form->login))) {
...
} else {
// Выводим страницу что "все окей"
$form->save();
$this->render("registration_ok");
}


вот так должно стать:

if ($form->model()->count("login = :login", array(':login' => $form->login))) {
...
} else {
// Выводим страницу что "все окей"
$form->passwd = md5($form->passwd);
$form->save();
$this->render("registration_ok");
}


т.е. просто перед сохранением кидаем поле passwd в md5.

Думаю всё должно быть понятно.

[guest] Гость

Было сказано: Четверг, 26 Ноябрь 2009

большок спасибо. Очень полезные уроки особенно для начинающий как я.

[adm] zolter

Было сказано: Четверг, 26 Ноябрь 2009

Пожалуйста! Заходите еще, в будущем порадую чем то новеньким

[guest] Гость

Было сказано: Пятница, 05 Февраль 2010

наконец-то. нашел то что мне надо. регистрация, мля...

[guest] BOLVERIN

Было сказано: Пятница, 05 Февраль 2010

А как запустить на сервере всю эту радость?

[guest] zolter

Было сказано: Пятница, 05 Февраль 2010

Прочитайте уроки с 1го по 5й. Это всё цельное руководство, что б понять как работает - надо посмотреть основы.

[guest] Kyuzo

Было сказано: Воскресенье, 14 Февраль 2010

Мне кажется или в куске


public function actionRegistration()
{
// тут думаю все понятно
$form = new User();

// Проверяем являеться ли пользователь гостем

забыто упоминание про registration
$form = new User('registration');


и как результат, сравнение полей passwd и passwd2 не производится

[guest] Kyuzo

Было сказано: Воскресенье, 14 Февраль 2010

и к слову в коде для registration.php пропущено само поле повторного ввода пароля, с файлом в конце урока все в порядке

прочитал второй урок по регистрации и авторизации, обнаружил тот же вопрос с "$form = new User()"
таки должно там что-нибудь быть или нет?
у меня не работало пока сам не дорисовал экшн в параметре

[guest] persy

Было сказано: Четверг, 25 Февраль 2010

постоянно при создании формы сталкиваюсь с такой ошибкой - "Call to a member function hasErrors()", чем она может быть вызвана

[guest] Гость

Было сказано: Четверг, 25 Февраль 2010

Разобрался)), просто необходимо было объект в методе создать!

[guest] alex3d

Было сказано: Вторник, 16 Март 2010

[guest] Kyuzo мне кажется был прав потому что я тоже столкнулся с аналогичной проблеммой:
1. в примерах пропущено поле для повторного ввода пароля (в файлах для загрузки - все ок.)
2. у меня версия 1.1. и даже скачаный готовый проект из "части 2" не работает как надо - на второе поле для сверки пароля ему вообще наплевать - его даже можно пустым оставить и скрипт скажет что успешно сохранили юзера.
3. попытка поменять на


$form->scenario = 'registration';
if($form->validate()) {

приводит к обратному результату - неважно что введем в поле с повтором пароля - скрипт говорит что "поля разные"... :) Отчего так? И та же самая фича что и описывалась до этого - такое ощущение что сессии не работают - но проверял - работают.
Заранее спасибо за пояснения!

[adm] zolter

Было сказано: Вторник, 16 Март 2010

Я для 1.0.х писал скрипты, в 1.1 совсем другая работа со сценариями.

Но я посмотрю в чем может быть дело.

to Kyuzo
вы правильно написали про $form = new User('registraion'); именно так указывается сценарий для версий 1.1.х
но т.к. этот урок писался для 1.0.х - то там было в самом validate

[guest] alex3d

Было сказано: Вторник, 16 Март 2010

Большое спасибо за оперативность! Было бы очень кстати обновить скрипты в примере блога для версии 1.1. Особенно это будет полезно для начинающих в Yii, таких как я :)

[adm] zolter

Было сказано: Среда, 17 Март 2010

Да... Надо будет выделить время, то думаю многим не удобно читать про старьё 1.0.х :)

alex3d

Было сказано: Четверг, 18 Март 2010

УРААА!!! Перечитав обновленное руководство по 1.1.1 и "включив мозги" я пытался в очередной раз сделать наскок на проблемы с валидацией пользователя (на 1.1.1 никак не хотел воспринимать поле $passwd2). Причину наше вот в чем:
1. В версии 1.1.1 оказывается фрагмент кода функции safeAttributes .... вообще не принимается во внимание - его удалил.
2. Вместо этого ДОБАВИЛ еще одну строку в правило Rules


// для сценария registration поле passwd2 должно присутствовать
array('passwd2', 'required', 'on'=>'registration'),

Хе-хе :) поля в правилах сравниваются, а обязательное наличие самого второго поля для сравнения НЕ БЫЛО определено!
3. обязательно заменить, где надо:

...
$form->scenario = 'registration';
if($form->validate()) {
...
$form->scenario='login';
if($form->validate()) {

так как в 1.1.1. нельзя передавать название сценария в скобках функции validate().
Уважаемый Zolter, мои рассуждения правильны?

[guest] zolter

Было сказано: Пятница, 19 Март 2010

Совершенно верно! :)
Тоже иногда люблю сесть и докопаться до истины :)

Тока вместо:

$form->scenario = 'registration';
if($form->validate()) {


можно:

$form = new Model('registration')
...
if($form->validate())


т.е. тот параметр который раньше в validete указывался (т.е. название сценария), теперь может быть указан при создании объекта.

[guest] like2dev

Было сказано: Воскресенье, 21 Март 2010

Зачем мы объявляем эти переменные?

public $verifyCode;
public $passwd2;

Если мы присваиваем атрибуту значения из формы все

scenario - содержит в себе имя действия?

Как вынести проверку на наличию пользователя в таблице в User модель?

[guest] Гость

Было сказано: Вторник, 23 Март 2010

to like2dev
потому что автоматическая присваивалка работает только для полей которые либо явно указаны как у нас (passwd2, verifyCode) либо являются полями в таблице User. Т.к. в таблице у нас этих полей нету, мы их используем только для проверки - то нам приходится обьявлять их в ручную.

>> Как вынести проверку на наличию пользователя в таблице в User модель?

Очень просто, для поля login делаете проверку отдельной функцией. А в ней уже проверяете есть ли запись в таблице с таким именем или нет.

>> scenario - содержит в себе имя действия?

не уверен. в 1.0.х не содержало. В 1.1 лучше указывать явно в $form->scenario или при создании объекта модели

[guest] Гость

Было сказано: Среда, 05 Май 2010

Где у Вас в изложенном выше, подобное чтоб заменить?
----------------------------------------
UserIdentity:
Там где идет проверка пароля в базе с введенным паролем в форме, вместо:
if($record->passwd!==$this->password)
делаем
if($record->passwd!==md5($this->password))
----------------------------------------
пересмотрел все, вроде ниче не пропустил, исходники ссылки не работают!!!

[guest] zolter

Было сказано: Среда, 05 Май 2010

Это во второй части 6го урока смотрите.
Ссылки на исходники постараюсь поправить в ближайшее время

[guest] Максимка

Было сказано: Суббота, 03 Июль 2010

А как же проверка на уникальность логина?

[guest] Гость

Было сказано: Суббота, 03 Июль 2010

Там есть проверка, посмотрите внимательнее

[guest] Николай

Было сказано: Среда, 28 Июль 2010

На счет safeAttributes в моделе как отдельной функции, а в рулес прописать
array('login, passwd, passwd2, verifyCode', 'safe')
не даст того же результата?

[guest] zolter

Было сказано: Среда, 28 Июль 2010

Совершенно верно, для 1.1.х достаточно прописать 'safe' в рулес для нужных атрибутов.

[guest] Гость

Было сказано: Среда, 28 Июль 2010

А теперь уже дочитал что для 1,1 заменили safeAttributes на safe в рулес, так что я правильно понял? чтоб исключить извне подставки айди такой код в рулес array('login, passwd, passwd2, verifyCode', 'safe') исключает возможность,или наоброт айди нужно прописать array('id', 'safe') чтоб исключить эту уязвимость?
Спасибо!

[guest] zolter

Было сказано: Среда, 28 Июль 2010

Бывает такая ситуация когда используются поля в форме (атрибуты) которые не ограничиваются какими либо правилами. К примеру, используется текстовое поле. Для того что бы yii считал его безопасным и нормально работал с ним нам следует прописать правило:

array('name_attribut', 'safe')

если над атрибутом мы проводим какую либо проверку, к примеру на кол-во введеных символов и тп - тогда нам не трубется дополнительно писать что атрибут является "safe" (безопасным), т.к. yii считает что раз вы используете его в одном из правил - значит оно автоматически в категории "safe".

Все атрибуты над которым не используется не одна проверка, не указаны в "safe" - являются не безопасными. К примеру, id и тп.

[guest] Гость

Было сказано: Среда, 28 Июль 2010

Спасибо за детальный расклад!
Извиняюсь если непонятлив, немного запутался уже, но хочеться разобраться в этом,
тогда если id нигде не проверяеться, а автоматом при сейв в БД присваиваеться, ему нужно задать safe
array('id', 'safe'), для формы регистрации, ведь по сути мы его не передаем формой, и ссотвественно он не являеться не безопасным, но его могут подстваить, и он уже получаеться не безопасным, чтоб его не переписало в БД если такой существует для этого его на всякий случай объявляем safe, этот код
array('id', 'safe') тогда нужно прописать в рулес в конкретном случае для регистрации? да или нет?

[guest] zolter

Было сказано: Среда, 28 Июль 2010

В форме регистрации мы еще не знаем какой id пользователю присвоит база данных, поэтому для значения id мы не каких правил не пишем. Вы же не передаете значение id из формы. Все значения которые есть в таблице, но которые мы не используем в текущей формы - мы считаем не безопасными, и в 'rules' их не прописываем.

[guest] Комлев Роман

Было сказано: Понедельник, 26 Сентябрь 2011

Пожалуйста помогите, как только не пробывал изменять код выходит ошибка

75 76                  $form->verifyCode = $_POST['User']['verifyCode'];
77
78 79
80 if($form->validate()) {
81 82 83
84 if ($form->model()->count("login = :login", array(':login' => $form->login))) {
85

Если кто может помочь, заранее большое спасибо!

[guest] maxx

Было сказано: Вторник, 27 Сентябрь 2011

Какая ошибка?

[guest] Гость

Было сказано: Вторник, 10 Январь 2012

Что же я сделал не так?
На этапе

В принципе форма наша уже работает. Зайдите на страницу localhost/user/registration/ и попробуйте. 

Вижу "The website cannot display the page".
Вроде всё делал как надо. Создано protected/views/user. Там два файла в php регистрацией.
Что может быть?

[guest] zolter

Было сказано: Вторник, 10 Январь 2012

Попробуй в первую очередь работать не под IE, а под ФФ например. Мало ли чего Ie пришло в голову при работе с локальным сайтом :)

[guest] Гость

Было сказано: Вторник, 10 Январь 2012

Пробывал и другие броузеры. Всё это я пробую под denwer. Буду разбираться.

[guest] Гость

Было сказано: Вторник, 10 Январь 2012

Попробывал сделать всё заново на другом копме. Дошел до "В принципе форма наша уже работает..."
И получил вот это:

PHP Error
Description
session_start() [<a href='function.session-start'>function.session-start</a>]: Cannot send session cache limiter - headers already sent (output started at Z:\home\yiiold\www\protected\controllers\UserController.php:1)

Source File
Z:\home\yiiold\framework\web\CHttpSession.php(102)

00090: return false;
00091: }
00092:
00093: /**
00094: * Starts the session if it has not started yet.
00095: */
00096: public function open()
00097: {
00098: if(session_id()==='')
00099: {
00100: if($this->getUseCustomStorage())
00101: session_set_save_handler(array($this,'openSession'),array($this,'closeSession'),array($this,'readSession'),array($this,'writeSession'),array($this,'destroySession'),array($this,'gcSession'));
00102: session_start();
00103: }
00104: }
00105:
00106: /**
00107: * Ends the current session and store session data.
00108: */
00109: public function close()
00110: {
00111: if(session_id()!=='')
00112: @session_write_close();
00113: }
00114:


Можно ли получить ту самую версию Framework, на которой делались эти уроки? Спасибо.

[guest] zolter

Было сказано: Среда, 11 Январь 2012

Попробуйте http://yii.googlecode.com/files/yii-1.0.12.r1898.zip

[guest] Гость

Было сказано: Среда, 11 Январь 2012

Работает :) Учусь дальше ...
Спасибо :)

[guest] Паша

Было сказано: Среда, 11 Январь 2012

Теперь не вижу капчу. Пропериз показывает адрес http://yii/user/captcha.
Буду разбираться.

[guest] Паша

Было сказано: Четверг, 12 Январь 2012

С Capcha разобрался! Методом тыка.
Оказалось проблема в файле UserController.php.
Я создал его Notepadом и сменил кодировку. Видимо мешала служебная информация, которую вставил Notepad.
В Dreamweaverе создан php, копипэйст туда всё. И Captcha заработала.

[guest] zolter

Было сказано: Четверг, 12 Январь 2012

Значит отлично :) Советую кстати подобрать какой то более проф. IDE чем Dreamweaverе. Будет намного комфортнее работать. Тот же нетбинс или зенд студио

[guest] Гость

Было сказано: Понедельник, 30 Январь 2012

Only PhpStorm.

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


Код:
Имя: