Автор: Kuzya
Заранее извиняюсь перед модераторами если я перепутал форум для публикации статьи. Я долго выбирал между форумом "Статьи" и "PHP, PERL...." и выбрал последний. Переместите пожалуйста тему если я ошибся
файлы приложенные к статье:
http://kuzya59.narod.ru/gb_sql.zip
http://kuzya59.narod.ru/gb_files.zip
http://kuzya59.narod.ru/gallery.zip
Официальный сайт: http://codeigniter.com/
Сайт русскоязычной поддержки: http://code-igniter.ru/
Версия на время написания статьи: 1.7 (но документация использовалась для версии 1.6.3)
Введение
Для хорошего понимания этой статьи Вам желательно ознакомиться с документацией к данному фреймворку. Не обязательно со всей полностью, хотя бы с «Общими темами». Также вам нужно знать архитектуру MVC (Модель-Вид-контроллер) и что именно делает каждая из этих трёх частей. Я бы мог описать базовые этапы работы с CI, но мне кажется, что авторы документации и переводчики её русской версии отлично это сделали. Документация к рассматриваемому фреймворку действительно очень проста и понятна. Плюс ко всему – сам CI спроектирован с максимальным удобством для его будущего изучения, поэтому если у Вас будут возникать какие-либо вопросы по ходу прочтения статьи, то не ленитесь и обращайтесь к документации. Всё, что я здесь буду описывать в ней есть. Также я постарался подробно комментировать весь описываемый код и объяснять каждое действие, относящееся к приложению, дабы у читателя не возникло лишних вопросов.
Ниже мы рассмотрим создание простейших приложений с помощью базовых возможностей CI. Приложений этих будет два — гостевая книга и фотогаллерея. В процессе их написания я постарался задействовать как можно больше классов, хэлперов и прочего инструментария CI для того чтобы Вы могли на практике увидеть как они используются и какую пользу могут принести.
И ещё кое-что прежде чем приступить непосредственно к программированию. Установите CI на отдельный домен. Писать каждое новое приложение мы будем на «чистом» домене, который не содержит посторонних скриптов. У меня этот хост называется «ci», далее по тексту я буду использовать именно это имя, поэтому будьте внимательны, если Вы назовёте хост по-другому. Фреймворк мы тоже всегда будем использовать «чистый». Для каждого нового приложения мы будет устанавливать CI заново. Нужно это для того чтобы не возникло путаницы между контроллерами, моделями и прочими скриптами разных приложений. В корень хоста положите файл «.htaccess» со следующим текстом:
Код:
RewriteEngine on
RewriteCond $1 !^(index\.php|images|styles\.css|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
Это позволит нам при обращениях к сайту убрать из адресной строки «index.php». А так же здесь записано игнорирование обращений к файлам «index.php»,«styles.css»,«robots.txt» и к директории «images». Запросы обращённые к ним переписываться не будут. И последнее. Откройте файл «application/config/config.php» и измените в нём параметр «base_uri» с «http://your-site.com/» на «http://ci/» (или на название Вашего хоста, если он у Вас назван по другому).
1. Гостевая книга
Сейчас мы напишем гостевую книгу, обладающую минимальным функционалом. Она будет показывать отзывы, делить их на страницы и позволять посетителю оставлять сообщения. При написании этих трёх действий мы постараемся задействовать как можно больше инструментов встроенных в CI, чтобы рассмотреть их на практике.
Начнём с дизайна. Шаблон гостевой книги Вы можете взять в файле «template.zip» приложенному к статье. Если Вы хотите посмотреть шаблон отдельно от приложения, то поместите его на какой-либо хост, потому что при открытии шаблона браузером локально не отобразятся изображения и не загрузятся стили, поскольку путь к ним начинается с «/». Скопируйте папку «images» и файл стилей в корень хоста с CI. Теперь откройте Вашим редактором файл index.html, содержащий код шаблона. Ниже я буду приводить куски html-кода для того, чтобы не возникло путаницы, и Вы случайно не вынесли в шаблоны ненужный код. Верхнюю часть, до тега «</head>», нужно вынести в файл header.php и сохранить в папке видов «application/views/» (информация по видам: http://code-igniter.ru/user_guide/general/views.html). Вот она:
Код:
<HTML>
<HEAD>
<TITLE>71</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<link rel="stylesheet" href="/styles.css" type="text/css">
</HEAD>
Нижней частью (footer.php) будет то что идёт после таблицы отзывов:
Код:
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td background="/images/bgd.gif" height="26"> </td>
</tr>
</table>
<p><img src="/images/str.gif" width=26 height=27 alt="" hspace="20"></p>
<p> </p>
<a href="http://templatemonster.com"></a><a href="http://inverse-logic.com"></a>
</BODY>
</HTML>
Всё что осталось, а именно центральную часть шаблона, сохраните в папке видов как «answers_list.php». По ходу разработки мы будем вносить изменения в основном в этот шаблон. Также нам нужно создать форму ввода сообщений. Вот её код:
Код:
<br /><br />
<form action='/guestbook/make_answer/' method='POST' name='answer_form'>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="81" valign="top"><img src="/images/rc.gif" width=55 height=24 alt=""></td>
<td>
<span class='stylesbold'>Ваше имя:</span>
</td>
<td>
<input type='text' name='author' value=''/>
</td>
</tr>
<tr>
<td width="81" valign="top"><img src="/images/rc.gif" width=55 height=24 alt=""></td>
<td>
<span class='stylesbold'>E-mail:</span>
</td>
<td>
<input type='text' name='email' value=''/>
</td>
</tr>
<tr>
<td width="81" valign="top"><img src="/images/rc.gif" width=55 height=24 alt=""></td>
<td>
<span class='stylesbold'>Ваш отзыв:</span>
</td>
<td>
<textarea name='text' cols='20' rows='5'></textarea>
</td>
</tr>
<tr>
<td width="81" valign="top"><img src="/images/rc.gif" width=55 height=24 alt=""></td>
<td colspan='2'>
<input type='submit' value='Отправить' />
</td>
</tr>
</table>
</form>
Сохраните этот шаблон под именем «answer_form.php».
С отображениями разобрались, начнём разработку кода приложения. Создадим основной контроллер (информация по контроллерам: http://code-igniter.ru/user_guide/general/controllers.html) «Guestbook». В нём объявим всего один метод - «index». Этот метод используется контроллерами по умолчанию. То есть если при обращении к приложению в URI не указан вызываемый метод то будет вызван именно «index». В конце всей разработки он будет выводить список имеющихся отзывов, но сейчас введём лишь отображение дизайна. По очереди загрузим шаблоны «header», «answers_list»,«answer_form» и «footer».
PHP код:
class Guestbook extends Controller
{
function index()
{
// Обрабатываем шаблоны
$this->load->view('header');
$this->load->view('answer_form');
$this->load->view('answers_list');
$this->load->view('footer');
}
}
Если всё правильно, то при открытии ссылки http://ci/guestbook/ Вы должны увидеть страницу с одним сообщением от пользователя Dmitriy и формой отправки отзывов:
Теперь нам нужно сделать этот контроллер загружаемым по умолчанию для того чтобы не приходилось постоянно его явно указывать в URI. Для этого откройте файл «application/config/routes.php» и пропишите имя контроллера в ячейке «default_controller»:
PHP код:
$route['default_controller'] = "Guestbook";
Сохранив изменения пройдите по ссылке http://ci/ и Вы увидите результат, который ранее получался при обращении к адресу http://ci/guestbook/.
Сейчас нам нужно поработать с базой данных. Создайте отдельную БД для нашей гостевой книги (я назвал её аналогично хосту - «ci»). В этой базе выполните нижеприведённый SQL-код (он создаст таблицу «guestbook»):
Код:
CREATE TABLE `guestbook` (
`id` int(11) NOT NULL auto_increment,
`author` varchar(50) character set utf8 NOT NULL,
`email` varchar(50) character set utf8 NOT NULL,
`pub_date` int(11) NOT NULL,
`text` text character set utf8 NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 PACK_KEYS=0 AUTO_INCREMENT=0 ;
Здесь «id» — номер записи в таблице, «author» — автор отзыва, «email» — электронный почтовый адрес автора, «pub_date» — время публикации комментария в формате «unix-time» и «text» — сам отзыв. Также выполните один запрос на вставку данных в таблицу. Это будет единственный отзыв.
Код:
INSERT INTO `guestbook` VALUES (NULL, 'Anna', '1@1.ru', '1230443834', 'This is my first answer!');
Далее настроим подключение к MySQL в конфигурационном файле приложения. Откройте файл «application/config/database.php» и укажите в массиве «db» данные для соединения с БД. Пример:
PHP код:
$db['default']['hostname'] = "localhost";
$db['default']['username'] = "root";
$db['default']['password'] = "";
$db['default']['database'] = "ci";
Остальные ячейки массива «db» нам не нужны. Затем нам нужно организовать автоматическое подключение к базе данных при запуске приложения. Можно несколько раз вызывать это подключение прямо из кода, но намного удобнее, когда оно происходить само при каждом обращении пользователя к приложению. Чтобы это сделать откройте файл «application/config/autoload.php» и в массив $autoload['libraries'], содержащий имена библиотек загружаемых при старте приложения, добавьте ячейку «database»:
PHP код:
$autoload['libraries'] = array('database');
Сейчас обратитесь снова к корню нашего сайта. Если Вы где-то ошиблись, или какие-то данные были не верно указаны в конфигурационном файле, CI выведет ошибку о подключении к БД в тексте которой подробно опишет её причину.
Для работы с MySQL у нас всё готово. С этой целью в CI можно использовать класс «Database» предназначенный специально для работы с базами данных (информация по нему: http://code-igniter.ru/user_guide/database/index.html). Сейчас мы создадим модель (информация по моделям: http://code-igniter.ru/user_guide/general/models.html) для обращения к БД. Вообще, нам нужны лишь 3 функции — функция, которая бы брала сообщения из базы (для их показа на главной странице), функция получения общего количества отзывов (понадобится при разбиении на страницы), ну и функция добавления записи в таблицу. Пока мы опишем одну функцию — получения всех сообщений из базы. Для этого создадим пустую модель Querys и сохраним её в папке моделей «application/models/»под именем Querys.php.
PHP код:
class Querys extends Model
{
}
Теперь добавим в неё метод «getLastAnswers()», который будет брать из базы все сообщения и возвращать их в виде массива.
PHP код:
function getLastAnswers()
{
$sql = "SELECT * FROM guestbook ORDER BY id DESC";
$query = $this->db->query($sql);
$answers = Array();
// Используем метод result_array() который возвращает строку результата в виде массива
foreach($query->result_array() as $answer)
$answers[] = $answer;
return $answers;
}
Подключать модель мы будем при запуске контроллера. Для этого объявим в нём конструктор следующего содержания:
PHP код:
function __construct()
{
// Вызываем конструктор предка
parent::Controller();
// Подключаем модель "Querys"
$this->load->model('Querys');
}
Обратите внимание на то что мы вызвали конструктор класса-предка (Controller). Делается это из-за того что объявлением собственного конструктора мы перекрываем конструктор предка и поэтому он не выполнится самостоятельно.
Для проверки работоспособности модели впишите в метод «index» контроллера дамп результатов работы метода «getLastAnswers()»:
PHP код:
var_dump($this->Querys->getLastAnswers());
Теперь при обновлении страницы в самом верху должен появиться дамп массива содержащий информацию о единственном отзыве. Если всё правильно, то удалите строку дампа, если нет - еще раз проверьте все свои действия.
Массив с отзывами мы должны передать только соответствующему шаблону («answers_list»). Для этого в метод «index» перед обработкой шаблонов добавим объявление массива «answers» с полученными ответами:
PHP код:
$answers = $this->Querys->getLastAnswers();
Сформируем массив данных «data» для передачи в шаблон:
PHP код:
$data = Array();
$data['answers'] = $answers;
и при обработке шаблона с отзывами передадим эти данные обработчику «view» вторым параметром.
PHP код:
$this->load->view('answers_list',$data);
В итоге в методе «index» у Вас должен содержаться следующий код:
PHP код:
// Получаем массив отзывов
$answers = $this->Querys->getLastAnswers();
// Создаём массив данных для передачи в шаблон
$data = Array();
$data['answers'] = $answers;
// Обрабатываем шаблоны
$this->load->view('header');
// Передаём в шаблон данные
$this->load->view('answers_list',$data);
$this->load->view('answer_form');
$this->load->view('footer');
Сделаем небольшое отступление от основной темы. Поскольку мы сейчас будем выводить дату каждого отзыва, а она у нас содержится в формате «unix-time», нужно все эти даты как-то преобразовать в понятный человеку вид. Для этого мы воспользуемся функцией «unix_to_human» хелпера «Date» (информация по хелперам: http://code-igniter.ru/user_guide/general/helpers.html, информация по хелперу «Date»: http://code-igniter.ru/user_guide/helpers/date_helper.html). Саму функцию преобразования мы вызовем в шаблоне, а подключаться к хелперу будем в самом начале метода «index». Для этого в начало кода этого метода добавьте строку:
PHP код:
$this->load->helper('date');
Далее нам стоит изменить шаблон «answers_list» таким образом, чтобы он обрабатывал массив сообщений и выводил их на экран. Делать мы это будем с помощью альтернативного синтаксиса PHP (информация по нему: http://code-igniter.ru/user_guide/general/alternative_php.html). Найдите в шаблоне код самого отзыва:
Код:
<p> </p>
<p align="left" class="stylesbold">Dmitriy/<a class='stylesbold' href='mailto:1@1.ru'>email</a> (08:28:10-28.12.2008)</p>
<p align="left">This is my answer!</p>
Добавим в него обработку массива «answers» с помощью цикла «foreach» и заменим все части отзыва (автор, дата и т.д.) на соответствующие ячейки массива.
Код:
<? foreach($answers as $answer): ?>
<p> </p>
<p align="left" class="stylesbold"><?=$answer['author'];?>/<a href='mailto:<?=$answer['email'];?>'>email</a> (<?=unix_to_human($answer['pub_date']);?>)</p>
<p align="left"><?=$answer['text'];?></p>
<? endforeach; ?>
В этом коде на самом деле нет ничего страшного. Здесь мы заменили имя «Dmitriy» на «<?=$answer['author'];?>», почтовый адрес «1@1.ru» на «<?=$answer['email'];?>», дату отзыва на «<?=unix_to_human($answer['pub_date']);?>» и текст сообщения на «<?=$answer['text']?>».
Да, с виду, конечно, выглядит не очень, но при тщательном рассмотрении Вы увидите что всё легко и понятно, особенно если у Вас редактор с подсветкой кода. Для проверки работоспособности нашего шаблона и метода обратитесь к главной странице. На ней Вы должны увидеть отзыв из базы данных за место того, который был в шаблоне с самого начала.
Теперь приступим к написанию метода, добавляющего сообщения от пользователей. Если Вы обращали внимание на код формы отзыва, то наверное заметили что имя этого метода - «make_answer». В нём мы организуем все нужные данные и передадим методу «addAnswer» находящемуся в нашей модели, и его работа будет заключаться во вставке переданной ему информации в таблицу. Для получения внешних данных в CI имеется библиотека input (информация по ней: http://code-igniter.ru/user_guide/libraries/input.html). Для получения значений всех нужных полей мы будем использовать метод «post» этой библиотеки. Методу добавления записи мы будем передавать три параметра — имя автора, его e-mail, текст отзыва.
PHP код:
$author = $this->input->post('author',true);
$email = $this->input->post('email',true);
$text = $this->input->post('text',true);
$this->Querys->addAnswer($author,$email,$text);
Вторым параметром методу «post» передаётся «true» для того, чтобы полученные данные сразу прошли фильтрацию от XSS-вставок. Согласитесь - это очень удобно. Какой-либо обработки для усечения попыток sql-инъекций мы пока не делаем, они будут произведены в модели встроенными в CI механизмами. Ну и под конец вызываем из модели функцию добавления записи в базу:
PHP код:
$this->Querys->addAnswer($author,$email,$text);
Вот сам код этой функции:
PHP код:
function addAnswer($author,$email,$text)
{
$pub_date = time();
$sql = "INSERT INTO `guestbook` VALUES(NULL,?,?,?,?)";
$this->db->query($sql,Array($author,$email,$pub_date,$text));
}
Как видите, внешние данные передаются методу «query» отдельным массивом. В этом случае все параметры автоматически проходят фильтрацию и обрамляются кавычками, что автоматически делает невозможным проведение sql-инъекций.
Ну и добавим в конец кода «make_answer» - вызов метода «index», чтобы сразу после добавления информации вывелся весь список отзывов, включая последний.