DbHelp.ru
Маленький Yii блог
Комментарии
Гость: Намереваетесь оттрахать три киски сразу, обратите взо...
Гость: «Халва» - Карта Рассрочки взять кредит частный займ ...
Гость: Регистрируешься - огромный бонусы. Играешь - огромный ...
Гость: Быстро и качественно придам вашему фото идеальный вид....
Гость: Информативно,продолжай в том же духе [url=http://forum.oncolo...



Сервер 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. Я рад сообщить вам о выходе сразу двух версий нашего фреймворка. Для любителей стабильности была предоставлена версия 1.0.11 с большим ... "Yii PHP framework 1.0.11 и 1.1 RC"

  2. В данном переводе раскрыта идея как закрыть сайт от гостей. т.е. пользователи должны войти в систему прежде чем смогут увидеть ... "Закрываем сайт от лишних глаз"

  3. ... "Новый хост"

[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.

[guest] Гость

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

Почемуто не работает правило валидации для паролей.
В поле ПАРОЛЬ могу написать один пароль а в поле ПОВТОРИТЕ ПАРОЛЬ другой и регистрация юзера пройдет успешно без возмущений с первым паролем.
Подскажите пожалуйста куда смотреть чтобы исправить=)
Спасибо.

[guest] zolter

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

array('passwd', 'compare', 'compareAttribute'=>'passwd2', 'on'=>'registration'),

Правило работает только для сценария registration. посмотри вот этот вот комент http://www.dbhelp.ru/yii-auth-and-reg-1/page/#comment-1096

[guest] Гость

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

Спасибо за ответ, теперь пароли он сравнивает, но не хочет регистрировать нового пользователя, вместо этого ругаеться:
Такого Пользователя не существует!
Возможно Вы сможете подсказать, где я мог напортачить?
Большое Вам Спасибо за статьи, очень позновательные и удобные для изучения, особенно для начинающих=)

[guest] Гость

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

и еще если ввести в поле для регистрации существующего пользователя, то пользователь логиниться, это нормально? или это можно и нужно как-то исправить?

[guest] Гость

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

Нашел у себя ошибку:
array('passwd', 'authenticate'),
Исправил как в статье на:
array('passwd', 'authenticate', 'on' => 'login'),
и все заработало!
Не игнорируйте правила валидации!=)
Еще раз спасибо за статьи!

sobchukvadim

Было сказано: Вторник, 03 Апрель 2012

При нажатии кнопки выскакивает сообщение "Неправильный код проверки"
Как с этим бороться?

[guest] zolter

Было сказано: Вторник, 03 Апрель 2012

В коментах уже есть ответ на этот вопрос. Копайте в сторону установки 'on' для правила 'verifyCode' если не ошибаюсь.

[guest] Руслан

Было сказано: Вторник, 03 Апрель 2012

Никак не могу найти ошибку.
Пишет вот такой ответ "include(User.php) [<a href='function.include'>function.include</a>]: failed to open stream: No such file or directory "
и указывает на строку $form = new User();
хотя модель User.php создана

[guest] zolter

Было сказано: Вторник, 03 Апрель 2012

1. Возможно ошибка в имени файла (User.php)
2. Возможно внутри файла модели - неправильно написал клас модели. Т.е. не class User, а например class Usar
3. Если используешь модули - вынеси файл модели в родительскую папку с моделями
4. Проверь что б папка models не содержала в себе ошибок

[guest] Гость

Было сказано: Вторник, 03 Апрель 2012

названия написаны правильно
у меня есть контроллер UserController который лежит в protected/controllers
также есть модель User которая лежит в protected/models
названия скопировал все одинаково
я не понял по третьему пункту

[guest] Руслан

Было сказано: Вторник, 03 Апрель 2012

У меня впринципе не работает ни одна модель, хотя папка названа правильно

[guest] zolter

Было сказано: Вторник, 03 Апрель 2012

Вот тебе пример одной из модели, попробуй у себя. Только таблицу в БД создай новую или подставь уже существующую

protected/models/Cart.php

<?php
class Cart extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return 'cart';
}
public function attributeLabels()
{
return array(
'id' => 'ID',
);
}
}

[guest] Руслан

Было сказано: Вторник, 03 Апрель 2012

Да тут дело не в таблицах или в другой модели. У меня почему то вообще любой файл с моделью не находиться.

[guest] Руслан

Было сказано: Среда, 04 Апрель 2012

Нешел в чем была ошибка
Я не указал в конфиге
'import'=>array(
'application.models.*',
'application.components.*',
),

[guest] Гость

Было сказано: Пятница, 06 Апрель 2012

а как куда-то вывести код капчи чтобы посмотреть его и сравнить

[guest] Гость

Было сказано: Воскресенье, 08 Апрель 2012

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

[guest] Гость

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

не могу скачать исходники,может кто скинет на почту vsobchuk@inbox.ru
заранее большое спасибо!!!!!!!!!!!!!

[guest] Гость

Было сказано: Понедельник, 21 Май 2012

Спасибо за статью!

[guest] Гость

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

Как сделать так, что бы после регистрации нового пользователя, автоматически происходила авторизация этого пользователя и он оказывался на главной странице?

[guest] Гость

Было сказано: Среда, 16 Апрель 2014

Добрый день. Скиньте пожалуйста исходники на почту kirlaide@yandex.ru

[guest] Denis

Было сказано: Четверг, 28 Август 2014

Все сделал с учетом вышеописанных комментов. После добавления нового пользователя все проверки проходят, пишет, что пользователь успешно зарегистрирован, а когда я захожу в саму таблицу User в базе-то там он не сохранился. Причем если страничку обновить- то выходим ошибка что капча введена неверно. Я ввожу её снова. И о чудо-только тогда пользователь появляется в базе. Может кто объяснить такое поведение Yii 1.1.14, php 5.5.15.

[guest] Denis

Было сказано: Четверг, 28 Август 2014

По поводу вышеописанной проблемы мой код можно посмотреть там:
https://github.com/dpmurm/bbb
Буду очень признателен за выявленный в нем косяк

[guest] Гость

Было сказано: Воскресенье, 02 Ноябрь 2014

Ощущение, что из практиков здесь нет никого, все сразу спасибо, тд тп..
а то что в коде вьюхи нет инпута для ввода повтора пароля, да и еще есть куча ошыбок, на практике ето не работает, не понимаю людей которые просто читают, хвалят и ни х*я не делают=) Автор ты сильно не парся, кое что все-таки есть полезного, но нужно много переделивать.

[guest] DrLenux

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

Ошибка Yii 1.1.16

GD with FreeType or ImageMagick PHP extensions are required.

throw new CException(Yii::t('yii','GD with FreeType or ImageMagick PHP extensions are required.'));

<td><?php $this->widget('CCaptcha', array('buttonLabel' => '<br>[новый код]')); ?></td>

$this->render('registration',array('form'=>$form));

Yii::createWebApplication($config)->run();

[guest] Гость

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

guest test post
<a href="http://googlee.te/">bbcode</a>
<a href="http://googlee.te/">html</a>
http://googlee.te/ simple

[guest] Гость

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

Пройдите 1 регистрацию, сделайте 2 действия
и получайте от 8950 рублей каждые сутки в автоматическом режиме.

Мы гарантируем:
- Первый заработок в течении 60 минут.
- Стабильный доход 24 часа в сутки.
- Поступление денег без задержек.
- Для России, стран СНГ и Европы.
- Без вложений и установки ПО.
- Специально для новичков и людей без опыта.

Ознакомтесь с условиями у нас на сайте. ( prosto.zarplatt.ru )

[guest] Гость

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

guest test post
<a href="http://googlee.te/">bbcode</a>
<a href="http://googlee.te/">html</a>
http://googlee.te/ simple

[guest] Гость

Было сказано: Суббота, 08 Апрель 2017

Оригинал Xiaomi Redmi Note 4 Х 4 Х Смартфон 3 ГБ ОПЕРАТИВНОЙ ПАМЯТИ 32 ГБ ROM Snapdragon 625 Octa Core MIUI 8.1 Отпечатков Пальцев 5.5 "FHD 4 Г FDD LTE

Лучшая версия себя. Полюбившийся публике RedMi Note 4 стал еще лучше, переродившись в новой модели – Xiaomi RedMi Note 4 Pro. И что самое приятное, цена на телефон по-прежнему радует не меньше, чем и сами нововведения!

Производитель:Xiaomi
Разблокировка телефона:Да
Тип батареи:Не съёмная
Разрешение дисплея:1920x1080
Емкость батареи (мАч):4000mAh(Min) - 4100mAh(Typ)
Операционная система:Android
Особенности:Гравитационный эффект,GPRS,Сенсорный экран,Сообщение,Bluetooth,Видеоплеер,Видеоплеер HD,Wi-Fi,Воспроизведение MP3,FM-радио,GPS-навигация,Передняя камера,Слоты карт памяти,E-mail,QWERTY-клавиатура
Модель Xiaomi:Редми Примечание 4X3 ГБ 32 ГБ
Язык:Русский,Немецкий,Испанский,Польский,Турецкий,Английский,Норвежский,Итальянский,Французский,Португальский
Камера:13.0 MP
Тип камеры:Передняя & задняя камера
Количество SIM-карт:Две SIM-карты
Дата выпуска:2017
Сотовая связь:GSM/WCDMA/LTE
ПЗУ:32 ГБ
Состояние:Новое
Чёткость записи:1080P
Размер дисплея:5,5
Производитель процессора:Qualcomm
Процессор:Восьмиядерный
Дизайн:Стержень
Толщина:Ультра тонкий (<9mm)
Тип сенсорного экрана:Ёмкостный экран
Время Разговора:About 6-8 hours
Режим диапазона:2SIM/Multi-Bands
Цвет дисплея:Цвет
ОЗУ:3 ГБ
Размер:151mm*76mm*8.45mm
Язык:Chinese
MIUI:MIUI 8.1
Fingerprint:Support
CPU:Snapdragon 625 Octa Core up to 2.0GHz
TF Card:Support , up to 128GB
2G:GSM B2/B3/B5/B8
3G:WCDMA B1/B2/B5/B8;TD-SCDMA B34/B39;CDMA2000/1X BC0
4G:FDD-LTE B1/B3/ B5/B7/ B8;TD-LTE B38/B39/B40/B41(2555-2655MHz)
Xiaomi Model:Xiaomi Redmi Note 4 X

Цена: 9 870 руб.

Более детальный обзор на нашем сайте. www.xiaomi-redmi-note.tk

[guest] Гость

Было сказано: Четверг, 13 Апрель 2017

Приветствую пользователей ресурса! Представляем досуг с элитными девушками все подробности можно узнать по мылу dosug-elitei@mail.ru

[guest] Гость

Было сказано: Вторник, 18 Апрель 2017

Авто обновляемая страничка новинок кино в хорошем качестве онлайн, сохраните себе в закладки https://goo.gl/xpHYly

[guest] Гость

Было сказано: Вторник, 18 Апрель 2017

HOMTOM HT7 Pro 4G это смартфон бюджетного класса от Китайского производителя, работающий из коробки на операционной системе Android 5.1. В смартфоне установлен чипсет начального уровня Mediatek MT6735, оснащенный четырех ядерным центральным процессором работающим на частоте 1ГГц, и графическим чипом Mali-T720. Оперативной памяти 2ГБ, постоянной 16ГБ, которую можно расширить при помощи microSD карты обьемом до 128ГБ.

В HOMTOM HT7 Pro большой 5.5 дюймовый дисплей с HD ( 1280 x 720 )разрешением, использующий технологию IPS, благодаря чему картинка выглядит более естественно по сравнению с обычными LCD дисплеями. Спереди и сзади установлены камеры с искусственно поднятым разрешением, таким образом задняя имеет реальных 8МП поднятых до 13МП, фронтальная имеет 2МП поднятые до 5МП.

Общей производительности HOMTOM HT7 Pro 4G смартфона хватит на большинство игр и приложений, даже для самых требовательных. Наличие 2ГБ оперативной памяти позволит запускать больше вкладок в браузере. Благодаря поддержке сетей 4G, смартфон способен принимать данные по высокой скорости.

Батареи емкостью 3000мАч должно хватить на сутки активного пользования.

Цена: 4 424 руб.

Более детальный обзор на нашем сайте. www.homtom-ht7.tk

[guest] Гость

Было сказано: Пятница, 21 Апрель 2017

Мебель -> mebel-catalog.blogspot.ru

[guest] Гость

Было сказано: Понедельник, 24 Апрель 2017

Наш сервис предоставляет настоящие лайки на фотографии заказчиков, которые готовы платить за качество.

Именно для этого мы и набираем удалённых сотрудников, которые будут выполнять работу, то есть ставить лайки и зарабатывать за это деньги.

Чтобы стать нашим удалённым сотрудником и начать ставить лайки, зарабатывая при этом 45 рублей за 1 поставленный лайк,

достаточно просто зарегистрироваться на нашем сервисе. > http://like-rabota.tk/ <

Вывод заработанных средств ежедневно в течении нескольких минут.

[guest] Гость

Было сказано: Вторник, 25 Апрель 2017

Мастерская по ремонту стиральных машин в городе Алматы. Ремонтируем все известные проблеммы у стиральных машин. Звоните по телефону 8(777)224-84-26 . Поможем решить вашу проблему быстро и с гарантией.

Поможем с <b>"Означает Стиральной Машинке"</b>

[guest] Гость

Было сказано: Четверг, 27 Апрель 2017

Мастерская по ремонту стиральных машин в городе Алматы. Ремонтируем все известные проблеммы у стиральных машин. Звоните по телефону 8(777)224-84-26 . Поможем решить вашу проблему быстро и с гарантией.

Поможем с <b>"Заменить Стиральную Машину"</b>

Перейти к странице:

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


Код:
Имя: