ПРЕДИСЛОВИЕ
Этот раздел написан по многочисленным просьбам тех, кто не смог разобраться в следующем разделе.
Представленный набор скриптов представляет из себя его облегченную, спартанскую версию настоящего ядра. Это просто попытка помочь более плавно адаптироваться в премудростях последующих скриптов.
Кто чувствует в себе силы сразу изучать более серьёзные вещи, может этот раздел пропустить.
В следующем придется начать все сначала. Хотя повторение - мать учения. Впрочем, выбирать Вам.
Шаг 1
Подготовительные работы.
С чего обычно начинается построение сайта? Вы думаете, что нужно сделать первый файл, допустим index.php, и пошло-поехало.
Ан нет.
Для того чтобы было быстрее и аккуратнее, доложна быть готовая рама, на которую мы и понавешаем нужный функционал, чтоб не повторяться.
Назвать это можно ядром, фреймворком, шаблоном, паттерном, горшком, чертом лысым или как душе угодно. Суть одна - все, что обычно повторяется в разных сайтах (структура и общие функции) должно быть готово. Как замороженные пельмени. Останется сварить и добавить специи.
Нужно сразу заметить, что ядром в нашем понимании, является не какие то догмы и рамки, которые обычно ставятся фреймворками и всевозможными CMS. У нас это просто структура, которая позволяет упорядочить скрипты и иные принадлежности сайта. Оставляя полную свободу выбора как и что реализовывать. И хотя "framework" и переводится как "основа" или "рабочая рама", в классическом понимании это больше язык программирования со своим синтаксисом и законами. Наша структура более точно подходит под определение "рама".
Вот сейчас и сделаем такую кухню. Приступим, помолясь.
Мы уже изучили структуру сайта, сейчас будет намного проще понять: что где и зачем. Возьмем этот скрипт и на его основе начнем разворачивать боевые действия.
Начнем с того, что обычно оставляется "на потом", так как это кажется не очень важным. И зачастую это "потом" так и не наступает.
А именно с конфигурации и сопутствующих фишек.
Начнем со страниц ошибок. В корневой директории нужно сделать, как минимум, три файла.
401.html
403.html
404.html
Оформлять их не нужно, это дело верстальщиков. Нам будет достаточно этого:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>404</title>
</head>
<body>
<h2 style="color:#FF0000">404</h2>
Запрашиваемая страница отсутствует на нашем сайте.
</body>
</html>
Еще там же в корне нужно сделать файл .htaccess с таким содержанием:
AddDefaultCharset UTF-8
php_flag magic_quotes_gpc Off
php_flag magic_quotes_runtime Off
php_flag register_globals Off
ErrorDocument 401 /401.html
ErrorDocument 403 /403.html
ErrorDocument 404 /404.html
Options -Indexes
Что тут.
1. Кодировка. Все сайты мы будем делать в кодировке UTF-8.
2, 3. Убиваем магические кавычки.
4. Отключаем глобальные переменные
5-8. Обработка ошибок запросов. Вот тут и пригодятся странички. Обратите внимание на строку
Options -Indexes
Эта строка запретит вывод списка файлов и директорий, если в папке не окажется индекса. А директива ErrorDocument перенаправляет запросы на подготовленные страницы в случае ошибки сервера. Допустим набран адрес несуществующей страницы. В таком случае откроется 404.html
А пока что на данный момент должны иметь:
1. Всю структуру с прошлого занятия.
К ней добавили:
2. Три страницы с ошибками.
3. Файл .htacces в корневой директории.
Это точка отправления.
Шаг 2
Инициализация внешних переменных
Итак, начало у нас положено.
Продолжим-с.
Теперь у нас стоит задача выставить текущие и глобальные настройки сайта.
Основные и незыблемые две - кодировку и уровень ошибок, они прописаны первыми строчками индекса.
<?php
/**
* We establish the charset and level of errors
* Устанавливаем кодировку и уровень ошибок
*/
header("Content-Type: text/html; charset=utf-8");
error_reporting(E_ALL);
Но понадобятся еще и текущие настройки. Их будет много, и чтобы не носиться по всему сайту в поисках вчерашнего дня, все настройки принято держать в одном месте, а именно в конфигурационном файле. Вот и мы не лыком шиты, у нас есть такой в корне - config.php
Еще в config.php добавим еще две константы (одна там уже есть). Обратите внимание на префиксы констант. Они нужны, чтобы невзначай не пересечься с предопределенными константами или константами сторонних скриптов, которые мы, может быть, будем интегрировать в систему.
<?php
/**
* Configuration file
* Конфигурационный файл
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
/**
* Choice of language of a site
* Выбор языка сайта
*/
define('IRB_LANGUAGE', 'ru');
/**
* Establishes a physical path to a root directory of a script
* Устанавливает физический путь до корневой директории скрипта
*/
define('IRB_ROOT', str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']) .'/');
/**
* Establishes a path to a script root for HTTP
* Устанавливает путь до корневой директории скрипта
* по протоколу HTTP
*/
define('IRB_HOST', 'http://'. $_SERVER['HTTP_HOST'] .'/');
Первая для указания полных физических путей, а вторая нужна для полных ссылок.
Для чего это нужно. А для того, чтобы скрипт можно было использовать не только в корне, а в отдельной папке, как дополнение или расширеник какого то готового сайта.
Для этого достаточно добавить в путь эту директорию.
/**
* Establishes a path to a script root for HTTP
* Устанавливает путь до корневой директории скрипта
* по протоколу HTTP
*/
define('IRB_HOST', 'http://'. $_SERVER['HTTP_HOST'] .'/my_site/');
Теперь нужно все пути (к картинкам, стилям и т.д.) начинать с этого
<?php echo IRB_HOST ?>
и не бояться, что в определенный момент нужно будет перенести скрипт в другое место. Просто меняем путь в конфиге и насвистываем веселенький мотивчик.
Теперь ссылки в меню можно написать так:
<!-- skins/tpl/menu.tpl begin -->
Сегодня <?php echo $date ?> года
<ul>
<li><a href="<?php echo IRB_HOST ?>?page=main">Главная страница</a></li>
<li><a href="<?php echo IRB_HOST ?>?page=second">Вторая страница</a></li>
</ul>
<!-- skins/tpl/menu.tpl end -->
А ссылки - это важно. Потому что на гет-параметрах этих ссылок и будет строиться вся навигация и переключение модулей, так как все внутренние ссылки будут вести только на один файл (точку входа) - index.php
Это значит, что нам нужно бережно принять эти параметры и обработать их.
У нас уже был такой прецидент, мы инициализировали переменную $page в файле variables.php как раз для переключения модулей. Еще нам потребуется переменная для переключения разделов модуля (контроллеров). Назовем её $rem. Еще пригодится переменная для постранички. $num И переменная идентификатора чего-либо. Соответственно $id. А чтобы нам не греть голову, откуда появились в скрипте переменные, сложим их все в один массив $GET (не путать с $_GET). И теперь в любом месте будет ясна их принадлежность.
Ну а за одно сразу установим значения по умолчанию. Лишним никогда не будет.
variables.php
/**
* Initialization of variables GET-parametres
* Инициализация переменных GET-параметров
*/
$GET['page'] = !empty($_GET['page']) ? $_GET['page'] : 'main';
$GET['rem'] = !empty($_GET['rem']) ? $_GET['rem'] : 'read';
$GET['num'] = !empty($_GET['num']) ? $_GET['num'] : 1;
$GET['id'] = !empty($_GET['id']) ? $_GET['id'] : 1;
В главном индексе нужно тоже изменить переменную, коль скоро они у нас все в массиве:
<?php
/**
* The switch of modules
* Переключатель страниц
*/
switch($GET['page'])
{
/**
* Подключаем модуль приветствия
* Includes the greeting module
*/
case 'main':
include './modules/main/router.php';
break;
Еще нам понадобятся $_POST переменные. Мы же будем делать интерактивные приложения. В файле с переменными нужно просто указать несколько таких про запас. Если не хватит, потом добавим еще.
variables.php
<?php
/**
* The block of initialization and processing of entering variables
* Блок инициализации и обработки переменных
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
/**
* Initialization of variables GET-parametres
* Инициализация переменных GET-параметров
*/
$GET['page'] = !empty($_GET['page']) ? $_GET['page'] : 'main';
$GET['rem'] = !empty($_GET['rem']) ? $_GET['rem'] : 'read';
$GET['num'] = !empty($_GET['num']) ? $_GET['num'] : 1;
$GET['id'] = !empty($_GET['id']) ? $_GET['id'] : 1;
/**
* Initialization of variables POST
* Инициализация переменных POST
*/
$ok = !empty($_POST['ok'])?true:false;
$delete = !empty($_POST['delete'])?true:false;
$POST['value1'] = !empty($_POST['value1']) ? $_POST['value1'] : NULL;
$POST['value2'] = !empty($_POST['value2']) ? $_POST['value2'] : NULL;
$POST['value3'] = !empty($_POST['value3']) ? $_POST['value3'] : NULL;
$POST['value4'] = !empty($_POST['value4']) ? $_POST['value4'] : NULL;
Обратите внимание, мы не знаем, какие понадобятся переменные. Если приложение большое, то их может оказаться огромное количество. По этому, не мудря, просто пронумеруем их и будем использовать по порядку.
Еще в этот же файл сразу добавим функцию для удаления магических кавычек.
Весь файл variables.php теперь такой:
<?php
/**
* The block of initialization and processing of entering variables
* Блок инициализации и обработки переменных
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
/**
* We kill magic inverted commas
* Убиваем магические кавычки
*/
function stripslashesDeep($data)
{
if(is_array($data))
$data = array_map("stripslashesDeep", $data);
else
$data = stripslashes($data);
return $data;
}
if(get_magic_quotes_gpc())
{
$_GET = stripslashesDeep($_GET);
$_POST = stripslashesDeep($_POST);
$_COOKIE = stripslashesDeep($_COOKIE);
$_REQUEST = stripslashesDeep($_REQUEST);
}
/**
* Initialization of variables GET-parametres
* Инициализация переменных GET-параметров
*/
$GET['page'] = !empty($_GET['page']) ? $_GET['page'] : 'main';
$GET['rem'] = !empty($_GET['rem']) ? $_GET['rem'] : 'read';
$GET['num'] = !empty($_GET['num']) ? $_GET['num'] : 1;
$GET['id'] = !empty($_GET['id']) ? $_GET['id'] : 1;
/**
* Initialization of variables POST
* Инициализация переменных POST
*/
$ok = !empty($_POST['ok'])?true:false;
$delete = !empty($_POST['delete'])?true:false;
$POST['value1'] = !empty($_POST['value1']) ? $_POST['value1'] : NULL;
$POST['value2'] = !empty($_POST['value2']) ? $_POST['value2'] : NULL;
$POST['value3'] = !empty($_POST['value3']) ? $_POST['value3'] : NULL;
$POST['value4'] = !empty($_POST['value4']) ? $_POST['value4'] : NULL;
/**
* Other variables
* Другие переменные
*/
$info = array();
Это основа всех наших дальнейших поползновений.
Шаг 3
Паттерн MVC. Модель.
Ну раз у нас есть гостевая книга - не пропадать же добру. Попробуем на её основе построить что то более менее приличное.
Начнем с данных. Как помнится, для этого у нас была организована директория data. Ну и тут сделаем тоже самое. Это будет частью модели, а именно хранилищем данных.
Вторая часть - скрипт получения этих данных из хранилища. У нас в гостевой книге за это отвечает функция сканирования директории.
Поместим её в файл libs/model.php
<?php
/**
* Model functions
* Функции модели
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
//////////////////////////////////////////////////////////////////
/**
* Function of reading of a directory
* Функция чтения директории
* @param string
* @return array
*/
function dirScan($dir)
{
static $files;
if(empty($files))
{
$files = scandir($dir);
$files = array_diff($files, array('.', '..'));
}
$files = count($files) ? $files : array('1');
return $files;
}
Ну и для полного счастья добавим туда же еще две функции. Получения и записи информации, хранимой в виде сериализованных массивов.
<?php
/**
* Model functions
* Функции модели
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
//////////////////////////////////////////////////////////////////
/**
* Function of reading of a directory
* Функция чтения директории
* @param string
* @return array
*/
function dirScan($dir)
{
static $files;
if(empty($files))
{
$files = scandir($dir);
$files = array_diff($files, array('.', '..'));
}
$files = count($files) ? $files : array('1');
return $files;
}
/**
* Function of reception of the information
* Функция получения информации
* @param string
* @return array
*/
function getData($file)
{
if(file_exists($file))
$string = trim(file_get_contents($file));
else
exit('No such file '. $file);
return !empty($string) ? unserialize($string) : array();
}
/**
* Data recording function
* Функция записи информации
* @param string
* @return array
*/
function setData($file, $array)
{
return file_put_contents($file, serialize($array));
}
Вот и вся модель. Тоесть хранилище (папка data в корне) и эти три функции, позволяющие с этими данными работать. То есть находить нужный файл, чтать его, десериализовать массив и выдавать результат. Ну или наоборот - сериализовать массив и складывать в файл по месту назначения.
Пока работы этих скриптов мы не увидим, это внутренняя кухня. А чтобы увидеть, нам потребуется продолжение банкета - вид и контроллер.
Шаг 4
Паттерн MVC. Контроллер
Начнем с контроллера. В нем, для наглядности, будет два блока. Один для вывода информации, другой для записи.
Гостевая книга, как ей и положено, будет находиться на второй странице.
Итак, открываем файл modules/second/read_controller.php и пишем туда это:
<?php
/**
* The controller of a conclusion of the information
* Контроллер вывода информации
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
/**
* We connect a file of the model functions
* Подключаем файл функций модели
*/
include './libs/model.php';
/**
* The block of reading of the information
* Блок чтения информации
*/
$posts = getData('./data/'. $GET['num']);
include './libs/bb_tags.php';
$rows = '';
foreach($posts as $id => $post)
{
$date = $post['date'];
$name = htmlspecialchars($post['name']);
$mess = nl2br(bbTags(htmlspecialchars($post['mess'])));
$rows .= '<div class="guest_post">'. $date .' / <strong>
'. $name .'</strong><hr width="30%" align="left" />
'. $mess .'</div>';
}
Всё это мы уже проходили в гостевой книге, просто сейчас пытаемся привести в удобоваримый вид. По этому на самом функционале акцентироваться не будем.
Но несколько важных момента отметить надо.
1. Не все страницы и модули будут работать с данными. А значит файл с функциями модели мы будем подключать непосредственно в контроллер.
2.Весь вывод мы поместим в переменную $rows, а не отправим тут же в поток. За вывод отвечает часть паттерна MVC "вид", так что не будем нарушать принципов. И хоть у нас там затесались предательские html-теги, это будет идеологически верно. А с тегами мы разберемся чуть позже.
3. Теперь нет необходимости в контроллере проверять наличие файла, это сделает функция чтения, которую мы поместили в модель. Она нам пригодиться в той же админке или в другом модуле. Допустим можно сделать блок комментариев к статьям или даже модуль новостей. Принцип работы с данными останется прежним.
4. Функция bb-тегов нам понадобится и в админке. Поэтому мы вынесем её в отдельный файл и будем подключать там, где потребуется. Чтобы не переписывать одно и тоже по 10 раз.
libs/bb_tags.php
<?php
/**
* Replacement function bb-tags and smilies
* Функция замены bb-тегов и смайликов
* @param string
* @return string
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
function bbTags($text)
{
$bb = array(
'[B]',
'',
'
',
'',
'
',
'',
'
',
'',
'[:)]',
'[:(]',
'[;)]',
'[:D]'
);
$tag = array(
'<b>',
'</b>',
'<i>',
'</i>',
'<s>',
'</s>',
'<u>',
'</u>',
'<img src="'. IRB_HOST .'skins/images/smiles/1.gif" />',
'<img src="'. IRB_HOST .'skins/images/smiles/2.gif" />',
'<img src="'. IRB_HOST .'skins/images/smiles/3.gif" />',
'<img src="'. IRB_HOST .'skins/images/smiles/4.gif" />'
);
return str_ireplace($bb, $tag, $text);
}[/PHP]
Ну скучно же делать что то, не получая тут же результата. Так давайте веселиться. Для начала выведем переменную $rows в шаблон:
<!-- skins/tpl/second/show.html begin -->
<div style="padding:10px; background-color:#e6e6e6;">
<?php echo $rows ?>
</div>
<!-- skins/tpl/second/show.tpl end -->
Потом сделаем файл стилей и поместим на свое законное место: skins/css/style.css
/* CSS Document */
.guest_post{
border:1px solid;
width:70%;
background-color:#66FFFF;
min-height:100px;
margin:5px;
padding:5px;
}
Подключим его к главному шаблону: skins/tpl/index.tpl
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Мой сайт</title>
<link href="<?php echo IRB_HOST ?>skins/css/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<?php echo $content ?>
</body>
</html>
И - на старт! Внимание! Мааааарш!
Запускаем.
Вот так и будет работать дебаггер, если вдруг не окажется нужного файла с данными. Ну откуда ему взяться, если мы еще не сделали контроллер записи?
А вот отсюда можно взять пока прямо всю папку data
Теперь работает? Если нет, вот тут точно работает.
Ну а мы продолжим. Исправим ситуацию и соорудим блок записи.
Шаг 5
Контроллер. Продолжение.
Итак, нам нужно срочно добавить записей. Для этого нужен блок записи, но для начала разберемся с формой.
Вообще, форма - это тоже вещь, касаемая данных. И её тоже можно, с небольшой натяжкой, отнести к модели. Но суть в том, что как бы мы её не обзывали, формой она быть от этого не перестанет. Я вообще противник каких-либо ярлыков и рамок. Если комуто понравилось назвать это все MVC, ну и Бог ему судья. Нам же гораздо важнее, чтобы все безупречно работало. А назвать можно хоть MVC, хоть VCM, хоть Семен Семенычем, хоть крылатой ракетой "Першинг".
Итак, форма. Добавим её в шаблон модуля:
<!-- skins/tpl/second/show.html begin -->
<div style="padding:10px; background-color:#e6e6e6;">
<strong style="color:#FF0000"><?php echo getInfo($info); ?></strong>
<?php echo $rows ?>
<form action="" name="post" id="post" method="post">
Имя:<br />
<input name="value1" type="text" value="<?php echo $POST['value1'] ?>"/>
<br />
<img style="cursor:pointer" src="<?php echo IRB_HOST ?>skins/images/smiles/bold.gif"
alt="Жирный" onclick="tag('[b]','')">
<img style="cursor:pointer" src="<?php echo IRB_HOST ?>skins/images/smiles/italics.gif"
alt="Курсив" onclick="tag('
','')">
<img style="cursor:pointer" src="<?php echo IRB_HOST ?>skins/images/smiles/underline.gif"
alt="Подчеркнутый" onclick="tag('
','')">
<img style="cursor:pointer" src="<?php echo IRB_HOST ?>skins/images/smiles/strikethrough.gif"
alt="Зачеркнутый" onclick="tag('
','
')">
<img style="cursor:pointer" src="<?php echo IRB_HOST ?>skins/images/smiles/1.gif" onclick="tag('[:)]','')">
<img style="cursor:pointer" src="<?php echo IRB_HOST ?>skins/images/smiles/2.gif" onclick="tag('[:(]','')">
<img style="cursor:pointer" src="<?php echo IRB_HOST ?>skins/images/smiles/3.gif" onclick="tag('[;)]','')">
<img style="cursor:pointer" src="<?php echo IRB_HOST ?>skins/images/smiles/4.gif" onclick="tag('[:D]','')">
<br />
Сообщение:<br />
<textarea name="value2" id="value2" cols="40" rows="10"><?php echo $POST['value2'];?></textarea><br />
<input name="ok" type="submit" />
</form>
</div>
<!-- skins/tpl/second/show.tpl end -->[/PHP]
Форма нам знакомая, изменились только названия полей и добавилась функция вывода ошибок. Для красоты.
<?php
/**
* Information conclusion
* Вывод информации
*/
function getInfo($info)
{
if(count($info))
return '<br>' . implode('<br>', $info);
else
return ' ';
}
Добавилась она, как можно догадаться, в файл с общими функциями (libs/default.php)
И еще нужно взять смайлики и поместить их в папку skins/images
А вот для того, чтобы заработали эти смайлики и bb-теги, нужно в папку skins/js положить этот скрипт:
skins/js/script.js
function tag(text1, text2)
{
if ((document.selection))
{
document.getElementById('value2').focus();
document.post.document.selection.createRange().text =
text1+document.post.document.selection.createRange().text + text2;
} else if(document.forms['post'].elements['value2'].selectionStart != undefined) {
var element = document.forms['post'].elements['value2'];
var str = element.value;
var start = element.selectionStart;
var length = element.selectionEnd - element.selectionStart;
element.value = str.substr(0, start) + text1 + str.substr(start, length)
+ text2 + str.substr(start + length);
}
}
и подключить в главный шаблон:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Мой сайт</title>
<link href="<?php echo IRB_HOST ?>skins/css/style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" language="javascript" src="<?php echo IRB_HOST ?>skins/js/script.js"></script>
</head>
<body>
<?php echo $content ?>
</body>
</html>
Вот теперь пора сделать и сам блок записи. Функционал его практически не изменился, такой же и был в гостевой книге.
modules/second/read_controller.php
<?php
/**
* The controller of a guestbook
* Контроллер гостевой книги
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
/**
* We connect a file of the model functions
* Подключаем файл функций модели
*/
include './libs/model.php';
/**
* The block of recording of the information
* Блок записи информации
*/
if($ok)
{
if(!$POST['value1'])
$info[] = IRB_LANG_NO_NAME;
if(!$POST['value2'])
$info[] = IRB_LANG_NO_TEXT;;
if(count($info) == 0)
{
$file = max(dirScan('data'));
$posts = getData('data/'. $file);
if(count($posts))
{
$keys = array_keys($posts);
$id = max($keys) + 1;
$num = count($posts);
}
else
$num = $id = 1;
if($num >= IRB_NUM_POSTS)
{
++$file;
unset($posts);
}
$posts[$id]['date'] = date('d-m-Y');
$posts[$id]['name'] = $POST['value1'];
$posts[$id]['mess'] = $POST['value2'];
setData('./data/'. $file, $posts);
header('location: '. IRB_HOST .'?page=second&num='. $file);
exit();
}
}
/**
* The block of reading of the information
* Блок чтения информации
*/
$posts = getData('./data/'. $GET['num']);
include './libs/bb_tags.php';
$rows = '';
foreach($posts as $id => $post)
{
$date = $post['date'];
$name = htmlspecialchars($post['name']);
$mess = nl2br(bbTags(htmlspecialchars($post['mess'])));
$rows .= '<div class="guest_post">'. $date .' / <strong>
'. $name .'</strong><hr width="30%" align="left" />
'. $mess .'</div>';
}
Разница только в методах получения и записи информации (теперь это осуществляют специальные функции) и в редиректе. Мы в него подставили константу.
Кстати, о константах. Нужно добавить еще одну в конфигу. Она будет определять количество постов на странице.
<?php
/**
* Configuration file
* Конфигурационный файл
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
/**
* Choice of language of a site
* Выбор языка сайта
*/
define('IRB_LANGUAGE', 'ru');
/**
* Quantity of posts on page
* Количество постов на странице
*/
define('IRB_NUM_POSTS', 5);
/**
* Establishes a physical path to a root directory of a script
* Устанавливает физический путь до корневой директории скрипта
*/
define('IRB_ROOT', str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']) .'/');
/**
* Establishes a path to a script root for HTTP
* Устанавливает путь до корневой директории скрипта
* по протоколу HTTP
*/
define('IRB_HOST', 'http://'. $_SERVER['HTTP_HOST'] .'/');
и еще парочку в языковой файл - для валидации данных формы:
language/ru.php (en.php)
<?php
/**
* Варианты модуля приветствия
* Variants of the module of a greeting
*/
define('IRB_WHO_FIRST', 'Мир');
define('IRB_WHO_SECOND','Солнце');
define('IRB_WHO_THIRD', 'Небо');
define('IRB_WHO_FOURTH','Вася');
define('IRB_WHO_FIFTH', 'Петя');
/**
* Массив месяцев
* The month array
*/
$month = array(
'01' => 'января',
'02' => 'февраля',
'03' => 'марта',
'04' => 'апреля',
'05' => 'мая',
'06' => 'июня',
'07' => 'июля',
'08' => 'августа',
'09' => 'сентября',
'10' => 'октября',
'11' => 'ноября',
'12' => 'декабря'
);
/**
* Check data
* Валидация
*/
define('IRB_LANG_NO_NAME', 'Нет имени');
define('IRB_LANG_NO_TEXT', 'Текстовая область не заполнена.');
Ну вот теперь кажется и все, контроллер готов к бою. Можно пробовать.
Шаг 6
Паттерн MVC. Вид.
Ну а теперь займемся приведением в порядок отображения. У нас с ним далеко не все в порядке. Начнем с того, что уже проходили. А именно с возврата данных. Самые наблюдательные могли заметить, что у нас пропала обработка данных, которыен выводятся в элементы формы. Напомню:
<input name="value1" type="text" value="<?php echo $POST['value1'] ?>"/>
Тут отсутствует функция htmlspecialchars(). Это все неспроста.
Дело в том, что данные у нас хранятся не в разрозненных переменных, а в массиве $POST (не путать с $_POST). А раз они в массиве, то и обработать их можно одним махом. Для этого сочиним специальную функцию-обертку, которая заставит htmlspecialchars() работать с массивами.
Поместим её в файл libs/view.php, так как данные нужно обрабатывать всегда и повсеместно.
<?php
/**
* Library of the views functions
* Библиотека функций отображения
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////<br />
/**
* Function of processing of variables for a conclusion in a stream
* Функция обработки переменных для вывода в поток
*/
function htmlChars($data)
{
if(is_array($data)) // Если данные - массив, вызываем эту же функцию.
$data = array_map("htmlChars", $data);
else // Если нет, обрабатываем htmlspecialchars()
$data = htmlspecialchars($data);
// На выход
return $data;
}
/**
* Date formatting
* Форматирование даты
*/
$date = formatDate(date("Y-m-d"), false);
А теперь просто открываем вьюшку модуля и добавляем туда всего одну строчку:
modules/second/view.php
<?php
/**
* View
* Вид
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
$POST = htmlChars($POST);
/**
* Подключаем шаблон
* Includes a templates
*/
include './skins/tpl/second/show.tpl';
Все, теперь ни одна мышь не проскочит незамеченной. Все данные будут обязательно обработаны. Это мало того, что удобно, так еще и повышает безопасность.
Только один момент, эта обработка должна производиться непосредственно перед подключением шаблона, как не был велик соблазн обработать все сразу на входе. Это приведет к искажению данных.
Поехали дальше. Блок чтения информации. Тут точно также можно обработать сразу весь массив:
/**
* The block of reading of the information
* Блок чтения информации
*/
$posts = getData('./data/'. $GET['num']);
include './libs/bb_tags.php';
$rows = '';
foreach($posts as $id => $post)
{
$post = htmlChars($post);
$date = $post['date'];
$name = $post['name'];
$mess = nl2br(bbTags($post['mess']));
$rows .= '<div class="guest_post">'. $date .' / <strong>
'. $name .'</strong><hr width="30%" align="left" />
'. $mess .'</div>';
}
Это удобно, но не столь важно. А важно то, что вот и попались нам эти бессовестные html теги, которым совсем не место в контроллере. Их нужно немедленно поместить в шаблон. Вот так:
<!-- skins/tpl/second/rows.html begin -->
<div class="guest_post">
<?php echo $date; ?> / <strong><?php echo $name; ?></strong>
<hr width="30%" align="left" />
<?php echo $mess; ?>
</div>
<!-- skins/tpl/second/rows.tpl end -->
А вот сам этот шаблон запихать в переменную $rows . Но как это сделать, ведь там переменные, и они должны меняться в каждом витке цикла... А для этого сочиним функцию, которая нам в этом поможет. Поместим её в файл libs/view.php
<?php
/**
* Library of the views functions
* Библиотека функций отображения
* @author IT studio IRBIS-team
* @copyright © 2009 IRBIS-team
*/
/////////////////////////////////////////////////////////
/**
* Function of analysis of a template
* Функция разбора шаблона
*/
function parseTpl($file, $data = array())
{
extract($data);
ob_start();
include $file;
$cont = ob_get_contents();
ob_end_clean();
return $cont;
}
/**
* Function of processing of variables for a conclusion in a stream
* Функция обработки переменных для вывода в поток
*/
function htmlChars($data)
{
if(is_array($data)) // Если данные - массив, вызываем эту же функцию.
$data = array_map("htmlChars", $data);
else // Если нет, обрабатываем htmlspecialchars()
$data = htmlspecialchars($data);
// На выход
return $data;
}
/**
* Date formatting
* Форматирование даты
*/
$date = formatDate(date("Y-m-d"), false);
Что это за зверь такой. Ну вопервых, сразу оговорочка. Так делать вообще то нежелательно, потому что мы при каждой интерации (витке) цикла вынуждены обращаться к файловой системе. В следующем разделе я покажу, как этого избежать. А пока для наглядности так.
Но по порядку. Функция extract() разбирает массив на переменные. Теперь (хоть их и не видно) у нас внутри функции определены переменные с названиями, эдентичными ключам массива, и значениями соответственно. Тоесть, если мы передадим в неё массив
array(
'name' => 'Вася',
'mess' => 'Привет!'
)
то внутри нашей функции, после обработки extract() образуются переменные
$name = 'Вася';
$mess = 'Привет!';
которые мы и подставим в подключенный шаблон. А дальше вступает в силу буферизация, и мы получаем шаблон с нужными значениями в виде строки. Которую и выдаем, как результат работы функции. Теперь нужно немного изменить контроллер (блок чтения) и все будет в порядке. Весь вывод - в шаблонах. А логика в контроллере.
/**
* The block of reading of the information
* Блок чтения информации
*/
$posts = getData('./data/'. $GET['num']);
include './libs/bb_tags.php';
$rows = '';
foreach($posts as $id => $post)
{
$post = htmlChars($post);
$post['mess'] = nl2br(bbTags($post['mess']));
$rows .= parseTpl('./skins/tpl/second/rows.tpl', $post);
}
Вот и всё. Основные принципы я показал. Если есть желание достроить эту гостевуху до полного ажура - теперь Вы знаете, как это делать.
Добавить в общую вьюшку функцию формирования ссылок постранички и организовать такой же модуль админки к примеру.
Лично я не стал бы на Вашем месте тратить на это время и перешел бы к более серьёзным занятиям - следующему разделу.
А вот итог этого занятия.