• Zend Framework: аутентификация и регистрация

    by  • 20.04.2010 • php, Zend Framework • Комментарии [8]

    Снимок ilovezf NetBeans IDE Dev 2010021520001 150x150 Zend Framework: аутентификация и регистрацияВ сегодняшней заметке речь пойдет о аутентификации и регистрации новых пользователей с помощью базы данных на Zend Framework.
    Для начала нам понадобится создать таблицу, пусть называться она будет users, sql- запрос представлен ниже.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    CREATE TABLE users (
    id INT(11) NOT NULL AUTO_INCREMENT,
    firstname VARCHAR(100) DEFAULT NULL,
    lastname VARCHAR(100) DEFAULT NULL,
    email VARCHAR(200) NOT NULL,
    username VARCHAR(100) NOT NULL,
    password VARCHAR(32) NOT NULL,
    PRIMARY KEY(id)
    );

    Дальше создадим модель в папке application/models/ и назовем ее Users.php. Этот класс будет расширять Zend_Db_Table

    1
    2
    3
    4
    5
    6
    <?php
    class Users extends Zend_Db_Table
    {
        protected $_name = 'users'; // имя таблицы, которую мы будем использовать
    }
    ?>

    Для эксперемента нам еще понадобится отдельный контроллер, который называть будет Auth, создать его можно в ZF Tools и просто ручками.
    Если вы используете NetBeans в качестве среды разработки, то в бета версии 6.9 есть возможность взаимодействия с ZF Tools прямо из IDE.
    auth1zf 300x223 Zend Framework: аутентификация и регистрация
    Затем создадим 4 метода у этой модели: для входа, регистрации, выхода и страницы, отображающей имя пользователя после успешного входа. Называться которые будет соответсвенно login, signin, logout, home.
    Для тех, кто предпочитает создавать все ручками, нужно создать помимо методов в модели, еще и шаблоны для их отображения в папке application/views/scripts/auth/
    auth2zf 300x223 Zend Framework: аутентификация и регистрация

    Создадим форму LoginForm.php, которая будет создавать форму для входа на сайт.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <?php

    /**
     * LoginForm
     */

    class LoginForm extends Zend_Form {
       
        public function init() {

            $username = $this->createElement('text', 'username', array(
                                'label' => 'Username: *',
                                'required' => TRUE
            ));

            $password = $this->createElement('password', 'password', array(
                                'label' => 'Password',
                                'required' => TRUE
            ));

            $signin = $this->createElement('submit', 'SignIn', array(
                                'label' => 'Sign In'
            ));

            $this->addElements(array(
                        $username,
                        $password,
                        $signin
            ));

        }
    }

    Далее добавим форму для регистрации новых пользователей RegistrationForm.php. Все формы, как вы, наверное, помините, должны располагаться в папке APPLICATION_PATH/forms

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    <?php

    /**
     * RegistrationForm
     */

    class RegistrationForm extends Zend_Form {
       
        public function init() {
            $firstname = $this->createElement('text', 'firstname', array(
                                'label' => 'First Name:',
                                'required' => FALSE
            ));

            $lastname = $this->createElement('text', 'lastname', array(
                                'label' => 'Last Name',
                                'required' => FALSE
            ));

            $email = $this->createElement('text', 'email', array(
                                'label' => 'E-mail: *',
                                'required' => TRUE
            ));

            $username = $this->createElement('text', 'username', array(
                                'label' => 'Username: *',
                                'required' => TRUE
            ));

            $password = $this->createElement('password', 'password', array(
                                'label' => 'Password: *',
                                'required' => TRUE
            ));

            $confirmPassword = $this->createElement('password', 'confirmPassword', array(
                                'label' => 'Confirm Password: *',
                                'required' => TRUE
            ));

            $register = $this->createElement('submit', 'Register', array(
                                'label' => 'Sign Uo'
            ));

            $this->addElements(array(
                        $firstname,
                        $lastname,
                        $email,
                        $username,
                        $password,
                        $confirmPassword,
                        $register
            ));
        }
    }

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    <?php

    class AuthController extends Zend_Controller_Action {
       
        public function init() {
            require_once 'Users.php';
            require_once 'LoginForm.php';
            require_once 'RegistrationForm.php';
        }
       
        public function indexAction() {
            $this->_redirect('auth/login');
        }
       
        public function loginAction() {
            $users = new Users();
            $form = new LoginForm();
            $this->view->form = $form;
            if ($this->getRequest()->isPost()) {
                if ($form->isValid($_POST)) {
                    $data = $form->getValues();
                    $auth = Zend_Auth::getInstance();
                    $authAdapter = new Zend_Auth_Adapter_DbTable($users->getAdapter(), 'users');
                    $authAdapter->setIdentityColumn('username')
                            ->setCredentialColumn('password')
                            ->setIdentity($data['username'])
                            ->setCredential($data['password']);
                    $result = $auth->authenticate($authAdapter);
                    if ($result->isValid()) {
                        $storage = new Zend_Auth_Storage_Session();
                        $storage->write($authAdapter->getResultRowObject());
                        $this->_redirect('auth/home');
                    } else {
                        $this->view->errorMessage = 'Invalid username or password. Please try again';
                    }
                }
            }
        }
       
        public function signupAction() {
            $users = new Users();
            $form = new RegistrationForm();
            $this->view->form = $form;
            if ($this->getRequest()->isPost()) {
                if ($form->isValid($_POST)) {
                    $data = $form->getValues();
                    if ($data['password'] != $data['confirmPassword']) {
                        $this->view->errorMessage = 'Password and confirm password dont \' match';
                        return;
                    }
                    if ($users->isUnique($data['username'])) {
                        $this->view->errorMessage = 'Name already taken. Please choose another one.';
                        return;
                    }
                    unset($data['confirmPassword']);
                    $users->insert($data);
                    $this->_redirect('auth/login');
                }
            }
        }
       
        public function logoutAction() {
            $storage = new Zend_Auth_Storage_Session();
            $storage->clear();
            $this->_redirect('auth/login');
        }
       
        public function homeAction() {
            $storage = new Zend_Auth_Storage_Session();
            $data = $storage->read();
            if (!$data) {
                $this->_redirect('auth/login');
            }
            $this->view->username = $data->username;
        }
    }

    Метод homeAction(): cперва мы создаем экземпляр класса Zend_Auth_Storage_Session, который будет хранить информацию о пользователе, который пытается войти най сайт или уже вошедшего. Объект данного класса возвращает непустую запись, если пользователь вошел на сайт, null в противном случае. Если же null, перенаправляем пользователя на страницу входа на сайт для ввода имени пользователя и пароля. Дальше в файле views/scripts/auth/home.html напишем следующее:

    1
    2
    3
    Welcome <?php echo $this->username;?>, <br />
    This is your home page<br />
    <a href="<?php echo $this->url(array('controller' => 'auth', 'action' => 'logout'));?>">click here to logout</a>

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

    Метод loginAction(): в первых 2х строчках мы создаем экземпляры нашей модели Users и формы для входа на сайт. (из-за неправильного сначала выбранного способа именования классов приходится подключать их в инициализационном методе, это мой промах и в последующих заметках я постараюсь исправить это). Третьей строкой мы ассоциируем нашу форму с переменной вида, которую отобразим в шаблоне.
    Дальше идет непосредстенно бизнес-логика. Сначала мы проверяем, чтобы отосланные данные были POST запросом, далее проверяем их правильность. Если оба этих условия соблюдены, мы получаем значения формы

    1
    $data = $form->getValues();

    Создаем экземпляр класса Zend_Auth и аутентификационный адаптер $authAdapter.
    Я использую адаптер, который непосредственно связан с базой данных, предоставляемый Zend’ом. Дальще мы указываем какие поля являются именем пользователя, а какие паролем.

    1
    2
    3
    4
                    $authAdapter->setIdentityColumn('username')
                            ->setCredentialColumn('password')
                            ->setIdentity($data['username'])
                            ->setCredential($data['password']);

    И пытаемся призвести аутентификацию по присланным из формы данным, метод ->authenticate()
    Если результат аутентификации валиден ->isValid() (мы нашли хотя запись в базе данных), сохраняем результат в сессии и переадресуем пользователя на домашнюю страницу. Если аутентификация не прошла, выводим сообщения об ошибке.
    Шаблон для этого метода. application/views/scripts/login.phtml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    if (isset($this->errorMessage)) {
        echo $this->errorMessage;
    }
    ?>
    <?php echo $this->form; ?>hf
    <a href="<?php echo $this->url(array('controller' => 'auth', 'action' => 'signup'));?>">
        New users click here?
    </a>

    Метод signinAction() делаем примерно тоже самое, за исключением вывода другой формы, проверки паролей (одинаковы ли они?) и записи в базу данных данных нового пользователя, если не возникло ошибок. В этом методе упоминается isUnique() метод, который сейчас мы допишем в Users.php, возвращающий true, если заданное в параметре имя в базе данных существует и false в противном случае. Что предотвратит создание двух пользоватлей с одинаковыми именами. Файл application/models/Users.php

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?php

    class Users extends Zend_Db_Table {
       
        protected $_name = 'users';

        public function isUnique($username) {
            $select = $this->_db->select()->from($this->_name)->where('username = ?', $username);
            $result = $this->getAdapter()->fetchOne($select);
            if ($result) {
                return TRUE;
            } else {
                return FALSE;

            }
        }
    }

    Начало серьезному проекту положено, хоть и остаются еще неправильности в коде, но с опытом я, надеюсь, от них избавлюсь. Удачного вам программирования! =)

    Комментарии к "Zend Framework: аутентификация и регистрация"

    1. Дмитрий
      06.07.2010 at 11:28

      Было бы неплохо выложить структуру файлов\каталогов.
      И у меня вопрос. Как получить доступ к БД MySQL, и вытащить из уже созданной таблицы поля, средствами зенд фреймворк.(у меня денвер)

    2. Maks
      30.07.2010 at 13:01

      спасибо большое за интересную статью. Мне она очень помогла

      • 31.12.2011 at 13:44

        Дмитрий, ставьте Zend Server, зачем вам денвер?
        Вытащить через Zend_Db_Table

    3. Zmei
      20.08.2010 at 17:40

      Thanks a lot!!
      I’ve found this note very useful!

    4. 25.08.2010 at 18:51

      Спасибо, полезная статейка.
      Но я бы сделал парочку изменений:
      1. БД-адаптер лучше поместить в реестр, чтобы не создавать каждый раз объект Users только для того, чтобы получить этот адаптер ( loginAction ).
      2. В signupAction создание объекта Users поместить после валидации поста ( if ($form->isValid($_POST)) ), так как нет необходимости при каждой попытке регистрации/входа создавать этот объект.

      • 26.08.2010 at 10:17

        Рад, что вам она пригодилась, на счет второго пункта предложенных вами изменений, я полностью согласен. В ответ на первый пункт — меня что-то побудило создать именно модель, может функционал, не рассмотренный в заметке, уж не упомнить — но в целом согласен с вами.
        Спасибо за развернутый комментарий.

        И если уж вообще быть занудой то,

        1
        ( if ($form->isValid($this->getRequest()->getPost())) )
    5. Capbl4
      16.09.2010 at 00:12

      А как можно добавить пользователю его личную страницу, где он бы отразил информацию о себе, после того как прошел регистрацию…
      Извините если вопрос не по теме, очень хочется узнать)

      • 16.09.2010 at 00:35

        создаете контроллер к примеру User и какой-нибудь экшн, к примеру user/profile и в зависимости от id, сохраненного в сессии, отображаете данные пользователя, это если в двух словах

    Добавить комментарий

    Ваш e-mail не будет опубликован. Обязательные поля помечены *