Написание CMS на Kohana 3.2 — 4 статья

Здравствуйте, сегодня мы продолжим работу над нашей cms.
В прошлой статьи мы не успели организовать вывод ошибок ,да и сама авторизация с регистрацией нуждается в доработке. Также напишу об одном возможном баге при работе с авторизацией.

1. Организация вывода ошибок и сообщений
2. Добавление модуля Captcha
3. Доработка авторизации и регистрации

1. Организация вывода ошибок и сообщений
Для этого мы напишем статические функции которые будут находиться в нашем базовом контроллере.

<br />
// Пример<br />
page::error('Текст ошибки или массив с ошибками(любой вложенности)');<br />
page::message('Текст ошибки или массив с сообщениями(одномерный)');<br />

При этом мы сделаем также чтобы если в качестве параметра функции передается массив(любой вложенности) он разбивался на множество строк и только в таком виде мы будем передавать его в файлы вида. Где мы будем перебирать строки через цикл и выводить их пользователю.
Также заодно внесем попутные изменения в базовый контроллер — Page
<br />
&lt;?php defined('SYSPATH') or die('No direct script access.'); </p>
<p>abstract class Page extends Controller_Template {<br />
    public $template = 'default';<br />
	public $error=array();<br />
	public $message=array();<br />
    public $main_config;<br />
	public $session;<br />
	public $title;<br />
	public $keywords;<br />
	public $description;<br />
	public $auth;<br />
	public $user;</p>
<p>    public function before()<br />
    {<br />
	/**<br />
	* Идентификация пользователя<br />
	*/<br />
	$this-&gt;session = Session::instance();<br />
	$this-&gt;auth = Auth::instance();<br />
	$this-&gt;user = $this-&gt;auth-&gt;get_user();</p>
<p>	/**<br />
	* Получение основных настроек<br />
	**/<br />
	$this-&gt;main_config = Kohana::$config-&gt;load('main');</p>
<p>    Kohana::add_path('themes/'.$this-&gt;main_config-&gt;get('web_theme').'/');<br />
    parent::before();</p>
<p>	$this-&gt;template-&gt;styles = array('main');<br />
	//$this-&gt;template-&gt;scripts = '';</p>
<p>    }</p>
<p>	public function error($error) {<br />
	  if (is_array($error)) {<br />
	   foreach ($error as $errors) {<br />
	    if (is_array($errors)) {<br />
	    return self::error($errors);<br />
	    }<br />
	   $this-&gt;error[]=$errors;<br />
	   }<br />
	  } else {<br />
	  return $this-&gt;error[]=$error;<br />
	  }<br />
	}</p>
<p>	public function message($message) {<br />
	  if (is_array($message)) {<br />
	   foreach ($message as $messages) {<br />
	   $this-&gt;message[]=$messages;<br />
	   }<br />
	  } else {<br />
	  return $this-&gt;message[]=$message;<br />
	  }<br />
	}</p>
<p>	public function after()<br />
	{<br />
	View::set_global(array(<br />
    'title' =&gt; !isset($this-&gt;title)?$this-&gt;main_config-&gt;get('title'):$this-&gt;title,<br />
	'keywords' =&gt; !isset($this-&gt;keywords)?$this-&gt;main_config-&gt;get('keywords'):$this-&gt;keywords,<br />
    'description' =&gt; !isset($this-&gt;description)?$this-&gt;main_config-&gt;get('description'):$this-&gt;description,<br />
	'session' =&gt; $this-&gt;session,<br />
	'user' =&gt; $this-&gt;user,<br />
	'error' =&gt; $this-&gt;error,<br />
	'message' =&gt; $this-&gt;message,<br />
	'view_captcha' =&gt; Captcha::instance()-&gt;render()<br />
    ));</p>
<p>	parent::after();<br />
	}</p>
<p>}<br />

Теперь нужно внести изменения в файлы видов.
Базовый файл вида — default.php
<br />
&lt;!DOCTYPE html&gt;<br />
&lt;html&gt;<br />
 &lt;head&gt;<br />
  &lt;meta charset=&quot;utf-8&quot; /&gt;<br />
  &lt;title&gt;&lt;?php echo $title ?&gt;&lt;/title&gt;<br />
  &lt;meta name=&quot;keywords&quot; content=&quot;&lt;?php echo $keywords ?&gt;&quot; /&gt;<br />
  &lt;meta name=&quot;description&quot; content=&quot;&lt;?php echo $description ?&gt;&quot; /&gt;<br />
  &lt;?php<br />
  foreach($styles as $style) {<br />
   echo HTML::style('themes/default/css/'.$style.'.css');<br />
  }<br />
  /*<br />
  foreach($scripts as $script) {<br />
   echo HTML::script('themes/default/css/'.$script.'.js');<br />
  }<br />
  */<br />
  ?&gt;<br />
 &lt;/head&gt;<br />
 &lt;body&gt;<br />
 &lt;div id=&quot;container&quot;&gt;<br />
  &lt;header&gt;<br />
  &lt;div id=&quot;header&quot;&gt;<br />
		&lt;h1&gt;PEGAS &lt;span&gt;CMS&lt;/span&gt;&lt;/h1&gt;<br />
		&lt;p&gt;Based on framework Kohana 3.2&lt;/p&gt;<br />
		&lt;div id=&quot;topmenu&quot;&gt;<br />
		&lt;ul&gt;<br />
			&lt;li&gt;&lt;?php echo HTML::anchor('/#', 'Главная'); ?&gt;&lt;/li&gt;<br />
			&lt;li&gt;&lt;?php echo HTML::anchor('/about/', 'О Pegas CMS'); ?&gt;&lt;/li&gt;<br />
		&lt;/ul&gt;<br />
		&lt;/div&gt;</p>
<p>  &lt;/div&gt;<br />
  &lt;/header&gt;</p>
<p> &lt;div id=&quot;contentcontainer&quot;&gt;</p>
<p>		&lt;div id=&quot;content&quot;&gt;</p>
<p>		&lt;!-- ### Post Entry Begin ###  --&gt;</p>
<p>		&lt;div class=&quot;post&quot;&gt;<br />
		&lt;?php<br />
		echo View::factory('/main/error');<br />
		echo View::factory('/main/message');<br />
		if(!empty($content))echo $content;<br />
		?&gt;<br />
		&lt;/div&gt;</p>
<p>		&lt;/div&gt;</p>
<p>		&lt;!-- ### Sidebar Begin ### --&gt;</p>
<p>		&lt;?php echo View::factory('/main/sidebar'); ?&gt;</p>
<p>		&lt;!-- ### Sidebar End ### --&gt;</p>
<p>	&lt;/div&gt;<br />
 &lt;/div&gt;<br />
  &lt;footer&gt;<br />
  &lt;div id=&quot;footer&quot;&gt;<br />
    &amp;copy; Pegas CMS 2011-&lt;?php echo date('Y'); ?&gt; г<br />
  &lt;/div&gt;<br />
  &lt;/footer&gt;<br />
 &lt;/body&gt;<br />
&lt;/html&gt;<br />

Файлы вида — error.php и message.php
<br />
&lt;?php<br />
if (!empty($error)) {<br />
   foreach ($error as $errors) {<br />
   ?&gt;<br />
   &lt;div class=&quot;post_error&quot;&gt;<br />
   &lt;span&gt;&lt;?php echo $errors; ?&gt;&lt;/span&gt;<br />
   &lt;/div&gt;<br />
   &lt;?php<br />
   }<br />
}<br />

<br />
&lt;?php<br />
if (!empty($message)) {<br />
   foreach ($message as $messages) {<br />
   ?&gt;<br />
   &lt;div class=&quot;post_message&quot;&gt;<br />
   &lt;span&gt;&lt;?php echo $messages; ?&gt;&lt;/span&gt;<br />
   &lt;/div&gt;<br />
   &lt;?php<br />
   }<br />
}<br />

Теперь нужно все это дело оформить, для красивого вывода сообщений =)
Добавим в /css/main.css
<br />
.post_error {<br />
padding:3px;<br />
font-size:15px;<br />
font-family: Tahoma;<br />
color: #7f0000;<br />
border-left: 2px solid #7f0000;<br />
border-right: 2px solid #7f0000;<br />
border-top: 1px dotted #7f0000;<br />
}<br />
.post_error span {<br />
padding-left:5px;<br />
}</p>
<p>.post_message {<br />
padding: 3px;<br />
font-size:15px;<br />
font-family: Tahoma;<br />
color: #59A84A;<br />
border-left: 2px solid #59A84A;<br />
border-right: 2px solid #59A84A;<br />
border-top: 1px dotted #59A84A;<br />
}<br />
.post_message span {<br />
padding-left:5px;<br />
}<br />

Переходим к следующему пункту.
2. Добавление модуля Captcha
Модуль Captcha мы возьмем уже готовый и внедрим его в наш проект.
Скачать исправленный и вполне работоспособный модуль можно здесь Captcha.
После того как скачали устанавливаем его ,для этого добавляем строку в массив подключаемых модулей — bootstrap.php
<br />
'captcha'  =&gt; MODPATH.'captcha', //Captcha<br />

Не забываем также закинуть файл настроек с самого модуля в папку /application/config/. Так лучше всего поступать со всеми модулями ,это позволит нам создавать более упорядоченные приложения которым не так страшны обновления модулей.
Теперь после того как мы разобрались с двумя пунктами сегодняшней работы осталось эти изменения внедрить.
3. Доработка авторизации и регистрации
Изменим контроллер — /controller/registration.php. Добавим в него новую проверку — цифровый код (Captcha) — это позволит нам избежать регистрации ботов на сайте. Для этого придется также поработать с моделями и валидацией. Тема — это довольно сложная для понимания. Поэтому рекомендую почитать статьи на данные тематики.
<br />
&lt;?php defined('SYSPATH') or die('No direct script access.');</p>
<p>class Controller_Registration extends Page {</p>
<p>	public function action_index()<br />
	{<br />
	$this-&gt;title = 'Регистрация';<br />
	$data = array();</p>
<p>	     if ($_POST) {<br />
		 $user = ORM::factory('user');</p>
<p>		 $data = Arr::extract($_POST, array('username', 'email', 'password', 'confirm_password', 'captcha'));<br />
$data['username']=HTML::chars($data['username']);<br />
         $user-&gt;values($data,  array('username', 'email', 'password'));</p>
<p>		 $extra_validation = Validation::factory(<br />
         array('password' =&gt; $data['password'],<br />
               'password_confirm' =&gt; $data['confirm_password'],<br />
			   'captcha' =&gt; $data['captcha']));</p>
<p>         $extra_validation-&gt;rule('password' , 'not_empty')<br />
                          -&gt;rule('password' , 'min_length', array(':value', 4))<br />
                          -&gt;rule('password' , 'max_length', array(':value', 32))<br />
                          -&gt;rule('password_confirm', 'matches', array(':validation', 'password_confirm', 'password'))<br />
						  -&gt;rule('captcha' , 'not_empty')<br />
						  -&gt;rule('captcha' , 'Model_User::captcha_valid');<br />
         try {<br />
         $user-&gt;save($extra_validation);<br />
         $user-&gt;add('roles', ORM::factory('role')-&gt;where('name', '=', 'login')-&gt;find());</p>
<p>		 $this-&gt;auth-&gt;login($data['username'], $data['password'], 1);</p>
<p>         $this-&gt;template-&gt;content =  View::factory('registration/ok',$data);</p>
<p>		 return TRUE;<br />
         } catch (ORM_Validation_Exception $e) {<br />
           page::error($e-&gt;errors('validation'));<br />
         }<br />
		}</p>
<p>    $this-&gt;template-&gt;content =  View::factory('registration/main');<br />
	}</p>
<p>} // End Registration<br />

В файле вида /registration/main.php добавим вывод Captcha.
<br />
&lt;h2&gt;Регистрация&lt;/h2&gt;<br />
&lt;?php echo Form::open('registration')?&gt;<br />
&lt;?php echo Form::label('username', 'Логин (max 32)') ?&gt;&lt;br /&gt;<br />
&lt;?php echo Form::input('username', HTML::chars(Arr::get($_POST, 'username')))?&gt; &lt;br /&gt;<br />
&lt;?php echo Form::label('email', 'E-mail') ?&gt;&lt;br /&gt;<br />
&lt;?php echo Form::input('email', HTML::chars(Arr::get($_POST, 'email')))?&gt; &lt;br /&gt;<br />
&lt;?php echo Form::label('password', 'Пароль (max 64)')?&gt; &lt;br /&gt;<br />
&lt;?php echo Form::password('password')?&gt; &lt;br /&gt;<br />
&lt;?php echo Form::label('confirm_password', 'Повторите пароль')?&gt; &lt;br /&gt;<br />
&lt;?php echo Form::password('confirm_password')?&gt; &lt;br /&gt;<br />
&lt;?php echo Form::label('captcha', 'Введите символы с картинки')?&gt; &lt;br /&gt;<br />
&lt;?php echo $view_captcha; ?&gt; &lt;br /&gt;<br />
&lt;?php echo Form::input('captcha', FALSE,array('size'=&gt;4))?&gt; &lt;br /&gt;<br />
&lt;?php echo Form::submit('register','Зарегистрироваться')?&gt; &lt;br /&gt; &lt;br /&gt;<br />
&amp;raquo; &lt;?php echo HTML::anchor('/auth', 'Авторизация')?&gt;<br />
&lt;?php echo Form::close()?&gt;<br />

Теперь нам нужно добавить метод проверки кода Captcha в модель — User. Для это мы создадим — /model/user.php наследуемого от базовой модели модуля -Auth.
<br />
&lt;?php defined('SYSPATH') or die('No direct access allowed.');</p>
<p>class Model_User extends Model_Auth_User {</p>
<p>	public function labels()<br />
	{<br />
		return array(<br />
			'username'         =&gt; 'username',<br />
			'email'            =&gt; 'email address',<br />
			'password'         =&gt; 'password',<br />
			'captcha'          =&gt; 'captcha',<br />
		);<br />
	}</p>
<p>	public static function captcha_valid($captcha)<br />
	{<br />
	  return (bool)Captcha::valid($captcha);<br />
	}</p>
<p>} // End User Model<br />

Перейдем к контроллеру авторизации — /controller/auth.php. Кой-чего подправим =)
<br />
&lt;?php defined('SYSPATH') or die('No direct script access.');</p>
<p>class Controller_Auth extends Page {</p>
<p>	public function action_index()<br />
	{<br />
	$this-&gt;title = 'Авторизация';</p>
<p>	$data = array();</p>
<p>		if($this-&gt;auth-&gt;logged_in()) {<br />
			Request::initial()-&gt;redirect(URL::site());<br />
		} else {<br />
			if ($_POST) {<br />
			$data = Arr::extract($_POST, array('username', 'password', 'save'));</p>
<p>                 if($this-&gt;auth-&gt;login($data['username'], $data['password'], (bool)$data['save'])) {<br />
					Request::initial()-&gt;redirect(URL::site());<br />
				 } else {<br />
				    page::error('Ошибка авторизации');<br />
				 }<br />
			 }<br />
		}<br />
		$this-&gt;template-&gt;content=View::factory('auth/main');<br />
	}</p>
<p>	public function action_logout()<br />
	{<br />
	$this-&gt;auth-&gt;logout();<br />
	Request::initial()-&gt;redirect(URL::site());<br />
	}</p>
<p>} // End Auth<br />

В самом начале статьи я писал о возможном интересном нюансе в авторизации при котором используется запоминание пользователя.
<br />
$this-&gt;auth-&gt;login($data['username'], $data['password'], $data['save']);<br />

Вроде все правильно и работать должно ).
Третий параметр функции auth->login принимает булевое значение и отвечает за запоминание пользователя.
Сам я если честно долго сидел и думал почему не работает ))
Проблема разрешилась после того как глянул исходной файл функции auth->login.
<br />
// Проверка<br />
if ($remember === TRUE)<br />
{</p>
<p>}<br />

Требуется строгое соблюдение типа! Поэтому нужно обязательно приводить к булевому типу
<br />
$this-&gt;auth-&gt;login($data['username'], $data['password'], (bool)$data['save']);<br />

Вот иногда такая мелочь ,а здорово стопорит работу и ставит в тупик )

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

Пару скринов:

Также напомню вам дорогие мои читатели что все изменения ,внешний вид ,функционал вы можете посмотреть и протестировать на сайте проекта http://cmspegas.ru

Исходники: Скачать исходники pegas_4

P.S По традиции прошу в комментарии при возникновении вопросов или пожеланий ))

Вам также может понравиться ...