Урок 6 : Регистрация и авторизация. Часть 1
Рубрика: Создаем блог вместе
24 Июн. 2009Эта статья устарела т.к. была написана для yii версии 1.0.х; Если вы используете более новую версию - у вас могут возникнуть ошибки из-за несовместимости. Обычно ответы на все вопросы работы на 1.1.х были описаны в комментариях ниже статьи.
Сегодня с вами хотел бы поговорить про такую вещь как авторизация, регистрация и аутентификация. В дальнейшем я предполагаю что пользователи нашего блога смогут оставлять комментарии, сами создавать статьи и редактировать свой профиль. Чтобы это реализовать - надо во-первых разграничивать права пользователей, а во-вторых написать саму регистрацию (и обработку этих самых пользователей)...
---Вступление
Я думаю моя статья не тянет на премию оригинальности т.к. вопросы освещенные в ней уже много раз поднимались ("Аутентификация и авторизация" [рус] и "Building a Blog System using Yii" [англ]). Несмотря на то что уже много было сказано по этой теме, я не могу пропустить такой важный момент в своей серии уроков "Создаем блог вместе".
Начнем
Наш небольшой план на данный урок выглядит следующим образом:
- Создаем для пользователя отдельный контроллер
- Создаем модель для работы с таблицей "users"
- Создаем форму регистрации
- Работа с моделью. Правила валидации
- Создаем форму авторизации
- Привязываем механизм авторизации
- Работа с моделью. Правила валидации
Приступим...
Создаем отдельный контроллер
Так как пользователи на нашем сайте это отдельные логические единицы которые должны в будущем обладать функциями:
- Авторизации
- Изменения профиля
- Выхода (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" в ближайшие дни.
Исходники:
Если хотите опубликовать этот материал у себя - пожалуйста, разместите ссылку на страницу откуда вы его взяли.
- Рассмотрим правильный вариант решения задачи поставленной в статье "Шаг 5: Контроллер".
next
Тем кто читает все статьи за один ... "Шаг 5: Контроллер Д/З"
- Поздравляю Всех своих читателей и случайных посетителей с уже наступившим 2011 годом. Желаю Вам в новом году чтобы все ... "Всех с новым годом!"
- Сегодня обнаружил что мой бывший сокурсник написал свой некий мод на Yii Blog. Исходные коды я не смотрел, но ... "Yii blog new [update]"

[adm] zolter
Было сказано: Среда, 24 Июнь 2009
Ага. Как я и написал - лучше проверять уникальность в моделе через правила (тот же unique). Но что б народ понял как юзать addError - я этого не делал :)

[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() контроллера

[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] 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] Николай
Было сказано: Среда, 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] Гость
Было сказано: Вторник, 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
Теперь не вижу капчу. Пропериз показывает адрес http://yii/user/captcha.
Буду разбираться.

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

[guest] zolter
Было сказано: Четверг, 12 Январь 2012
Значит отлично :) Советую кстати подобрать какой то более проф. IDE чем Dreamweaverе. Будет намного комфортнее работать. Тот же нетбинс или зенд студио


