© Cваял этот сайтик для вас и себя bes13.
-=2009-2013=-




природа однако)

⇐ туда | на память | сюда ⇒
Доллар - 98.4785
Евро   -  103.8680
Вторник
3 Октябрь 2023
‹‹ map ››
ПнВтСрЧтПтСбВс
      
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
     




Яндекс.Метрика Рейтинг@Mail.ru

гостевая книга в php

это уже можно применять. [2010-04-25]
Автор: не знаком с ним

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

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

Но все по порядку.

Шаг 2

Форма

Для того, что бы отправить информацию с Вашего компьютера на сервер, необходимо её как то упаковать. Делается это формой, есть такая штука. Выглядет так:

<formaction="?"method="post"></form> 
/*Всё, что находится между этими тегами,   
будет упаковано и отправлено на сервер. 
Не теги имеется ввиду, а данные, которые   
юзер введет в поля в этой форме. Делаем следующее:*/
<formaction="?"method="post"> 
<inputname="test"type="text"/><br/> 
<inputname="ok"type="submit"/> 
</form> 

Обратите внимание на:

1. action - это адрес скрипта, на который будут отправлены данные
2. method - метод передачи. Есть два меотда - GET и POST. При первом методе всё, что будет написано в поле, прилепится к адресу в адресной строке, при втором методе будут сформированы внутренние переменные. Предпочтительнее второй метод, так как при первом имеется ограничение по количеству передаваемых символов.
3. name - это имя элемента формы, в данном случае текстового поля. Что бы сервер мог знать, от куда именно пришли данные.
4. у кнопки тоже есть имя, для того, что бы знать, какая именно кнопка была нажата.
5. Тип кнопки - submit говорит о том, что при её нажатии данные будут отправлены на сервер.

Всё, как говориться "клиент дошел до нужной кондиции".

Теперь пишем обработчик, то есть собственно серверную программу, которая будет принимать и обрабатывать полученные данные. Небольшая хитрость - форму и обработчик желательно помещать в один файл, это поможет вернуть данные, если форма заполнена не верно. Знак вопроса в action направит запрос сам на себя. Но всё по порядку.

<?php header('Content-Type:text/html;charset=utf-8'); ?> <formaction="?"method="post"> <inputname="test"type="text"/><br/> <inputname="ok"type="submit"/> </form> <?php $test=!empty($_POST['test'])?$_POST['test']:null; echo$test; ?>

Готово.

Вот теперь в это поле можете написать Helo, World! и нажать кнопку. Что произошло.

1. Браузер отправил запрос из адресной строки на сервер.
2. Сервер сформировал вывод и отправил обратно.
4. Браузер получил ответ и "нарисовал" форму.
5. Вы ввели в эту форму данные и отправили обратно на сервер.
6. Сервер получил эти данные, на основании их изменил вывод и отправил обратно.
7. Вы получили новую страницу, на которой кроме формы есть еще результат обработки.
Теперь подробнее. При нажатии на кнопку браузер сформировал переменную name, в которую записал то, что было в поле, и отправил на сервер. Сервер принял эту переменную, идентифицировал её и функцией echo (можно использовать print, кому что нравится, это почти одно и то же) сформировал вывод. А теперь тонкости. Наберите в поле вот это: <Helo, World!> И нажмите кнопку. Видно что нибудь? Не видно. Но не потому, что нету, можете посмотреть исходный код страницы. Просто это интерпретируется как тег и не выводится на монитор. Чтоб избежать подобных казусов, необходимо закодировать спецсимволы. Делает это функция htmlspecialchars() Сделайте теперь так:
<?php 
header('Content-Type:text/html;charset=utf-8'); 
?> 
<formaction="?"method="post"> 
<inputname="test"type="text"/><br/> 
<inputname="ok"type="submit"/> 
</form> 
<?php
$test=!empty($_POST['test'])?$_POST['test']:null;
echohtmlspecialchars($test); 
?>
и почуствуйте разницу. Так вот, всё, что выводится в браузер (только туда, никуда иначе), нужно обрабатывать этой функцией. Теперь усложним задачу. При отправке данных запись в поле исчезает. А что, если что то не так? Бедный юзер должен всё заново переписывать? Будем вежливы и вернем ему форму с данными. Для этого немного изменим ход событий. Сначала примем переменную, потом выведем форму.
<?php 
header('Content-Type:text/html;charset=utf-8'); 
$test=!empty($_POST['test'])?$_POST['test']:null;
?> 
<formaction="?"method="post"> 
<inputname="test"type="text"value="<?phpechohtmlspecialchars($test)?>"/><br/> 
<inputname="ok"type="submit"/> 
</form> 
<?php;
echohtmlspecialchars($test);
 ?>
Обратите внимание, что в параметре value="" должны быть именно кавычки, а не апострофы, так как апостроф в тексте порвет тег. При вводе имени O'Rally случится примерно следующее:
<inputname="test"type="text"value='O'Rally'/>
 
то есть часть имени (Rally) выйдет в тело тега. Это грозит как минимум искажением данных, как худший вариант - XSS атакой. Теперь усложним еще больше. Не просто выведем данные, а изменим содержание страницы в зависимости от.
<?php 
header('Content-Type:text/html;charset=utf-8'); 
$test=!empty($_POST['test'])?$_POST['test']:null;
?> 
<formaction="?"method="post"> 
<inputname="test"type="text"value="<?phpechohtmlspecialchars($test)?>"/><br/> 
<inputname="ok"type="submit"/> 
</form> 
<?php 
if(isset($_POST['ok']));
echohtmlspecialchars($test); 
else 
echo'Напишитечтонибудь'; ?>
То есть: Если существует переменная ok (нажата кнопка), выводим текст сообщения. Если нет, то дефолтную (по умолчанию) надпись. Это и есть оператор if... else, основа логической составляющей программы. Еще больше усложним:
<?php 
header('Content-Type:text/html;charset=utf-8'); 
$test=!empty($_POST['test'])?$_POST['test']:null;
?> 
<formaction="?"method="post"> 
<inputname="test"type="text"value="<?phpechohtmlspecialchars($test)?>"/><br/> 
<inputname="ok"type="submit"/> 
</form> 
<?php 
if(isset($_POST['ok'])&&!$test) 
echo'Поленезаполнено.'; 
elseif(isset($_POST['ok'])) 
echohtmlspecialchars($test); 
else 
echo'Напишитечтонибудь'; 
?>
Обратите внимание на логику. Если есть переменная $ok и переменная $test пуста (функция empty() и знак инверсии !), выводим сообщение об ошибке, еще если нажата кнопка, выводим текст, еще выводим дефолтную надпись. Выполняться программа будет до первого соответствия, то есть если удовлетворяется первое условие (isset($_POST['ok']) && !$test), то второе и третье выполняться не будут. Теперь попробуем текст побольше:
<?php 
header('Content-Type:text/html;charset=utf-8'); 
$test1=!empty($_POST['test1'])?$_POST['test1']:null;
$test2=!empty($_POST['test2'])?$_POST['test2']:null; 
?> 
<formaction="?"method="post"> 
<inputname="test1"type="text"value="<?phpechohtmlspecialchars($test1)?>"/><br/> 
<textareaname="test2"cols="40"rows="10"><?phpechohtmlspecialchars($test2);?></textarea><br/> 
<inputname="ok"type="submit"/> 
</form> 
<?php 
if(isset($_POST['ok'])) 
{ 
if(!$test1) 
echo'Текстовоеполенезаполнено.'; 
elseif(!$test2) 
echo'Текстоваяобластьнезаполнена.';;
else 
echohtmlspecialchars($test1), '<br>',   htmlspecialchars($test2); 
} 
else 
{ 
echo'Напишитечтонибудь'; 
} 
?>
Тут, как видите, появились блоки. Сначала проверяем нажата ли кнопка. Потом, если нажата, проверяем заполнение. А если не нажата, сразу выводим дефолтную надпись, игнорируя проверки в первом блоке. Теперь нюансы. Наберите в текстарее текст с переносами, используя enter. Видите, на выводе текст оказался без переносов. Это потому, что браузеру нужен не просто перенос, а тег <br />. Заменить переносы на этот тег поможет функция nl2br()
<?php 
header('Content-Type:text/html;charset=utf-8'); 
$test1=!empty($_POST['test1'])?$_POST['test1']:null;
$test2=!empty($_POST['test2'])?$_POST['test2']:null; 
?> 
<formaction="?"method="post"> 
<inputname="test1"type="text"value="<?phpechohtmlspecialchars($test1)?>"/><br/> 
<textareaname="test2"cols="40"rows="10"><?phpechohtmlspecialchars($test2);?></textarea><br/> 
<inputname="ok"type="submit"/> 
</form> 
<?php 
if(isset($_POST['ok'])) 
{ 
if(!$test1) 
echo'Текстовоеполенезаполнено.'; 
elseif(!$test2) 
echo'Текстоваяобластьнезаполнена.';;
else 
echohtmlspecialchars($test1), '<br>',   nl2br(htmlspecialchars($test2)); 
} 
else 
{ 
echo'Напишитечтонибудь'; 
} 
Именно в таком порядке
nl2br(htmlspecialchars($test2)); 
не наоборот. И использовать её имеет смысл только в текстовых областях (<textarea>), так как текстовые поля (<input>)не предусматривают переносов. Ну вот и весь принцип в двух словах. Советы: 1. Используйте "прозрачные" имена переменных, то есть имя должно отражать суть. 2. Используйте сквозные имена. То есть они должны быть везде одинаковые, и в форме, и в php и в базе данных (об этом позже). Примерно так:
<?php 
header('Content-Type:text/html;charset=utf-8'); 
$login=!empty($_POST['login'])?$_POST['login']:null; 
$message=!empty($_POST['message'])?$_POST['message']:null; 
?> 
<formaction="?"method="post"> 
Логин:<br/> 
<inputname="login"type="text"value="<?phpechohtmlspecialchars($login)?>"/><br/> 
Сообщение:<br/> 
<textareaname="message"cols="40"rows="10"><?php   echohtmlspecialchars($message);?></textarea><br/> 
<inputname="ok"type="submit"/> 
</form> 
if(isset($_POST['ok'])) 
{ 
if(!$login) 
echo'Текстовоеполенезаполнено.'; 
elseif(!$message) 
echo'Текстоваяобластьнезаполнена.';;
else 
echohtmlspecialchars($login), '<br>',   nl2br(htmlspecialchars($message)); 
} 
else 
{ 
echo'Напишитечтонибудь'; 
}
?> 

Шаг 3

То, что мы сделали - игрушка, не более того. Для нормальной работы приложения часто необходимо запомнить данные и использовать их потом по назначению. Для этого используется запись в файл или в базу данных. Здесь мы рассмотрим вариант с использованием MySQL. Что это такое. Это отдельный сервер, который работает с реляционными базами данных. Он позволяет предоставлять доступ к данным сразу нескольким пользователям, быстро и эффективно обрабатывать эти данные. Работает этот сервер на специальном языке - SQL (Structured Query Language - язык структурированных запросов). Общение с этим сервером из php осуществляется набором специальных функций. Начнем по порядку. Создайте файл с названием config.php и поместите его в корень сайта (папку my_site). Напишите в него следующее:

<?php 
#Настройкиподключения 
define('MYSQL_SERVER','localhost'); 
define('MYSQL_DATABASE','guest'); 
define('MYSQL_USER','root'); 
define('MYSQL_PASSWORD',''); 
define('PREFIX',   'guest_');
?> 
Теперь по порядку. Вот тут мы определяем сервер. Если Вы используете Денвер, то сервер по умолчанию - localhost. На хостингах по разному, эту информацию дают при регистарации хостинга
define('MYSQL_SERVER','localhost');
Это название базы данных. Базу нужно создать, об этом позже.
define('MYSQL_DATABASE','guest');
Это пользователь. То есть по другому - юзер, от лица которого php будет делать запросы в БД. Его тоже надо создать, то есть зарегистрироваться в MySQL.
define('MYSQL_USER','root');
Ну а это соответственно пароль нашего юзера.
define('MYSQL_PASSWORD','');
Для того, что бы не бегать по всей базе в поисках таблиц приложения, используйте префикс. Тогда они всегда будут рядышком. То есть таблицы надо называть к примеру guest_users, guest_posts и так далее.
define('PREFIX', 'guest_');
Дальше идет подключение к серверу MySQL : mysql_connect.php
<?php 
#СоединениесMysql 
$db_irbis=mysql_connect(MYSQL_SERVER,MYSQL_USER,MYSQL_PASSWORD)ordie(NO_CONNECT); 
define('CONNECT',$db_irbis); 
#Выборбазы 
mysql_select_db(MYSQL_DATABASE,CONNECT)ordie(NO_DB_SELECT); 
;
#Установкапараметровсоединения 
query('SETNAMESutf8',__FILE__,__LINE__);;
query('SETCHARACTERSETutf8',__FILE__,__LINE__); 
query('SETCOLLATION_CONNECTION="utf8_general_ci"',__FILE__,__LINE__);
?> 

Функция mysql_connect() устанавливает соединение. При неудачной попытке мы останавливаем скрипт (die()).

Дальше определяем константу с указателем на открытое соединение.

Следом выбор нужной базы данных:

А еще дальше мы выставляем кодировку соединения. То есть язык, на котором будут общаться PHP и MySQL

Вот тут важный момент. Запрос, написанный на языке SQL, PHP отправляет на сервер баз данных функцией mysql_query(). Аргументами она принимает текст запроса и указатель на соединение. Кстати говоря, если второй аргумент не указывать, будет использовано последнее, успешно открытое соединение.

А мы, для диагностики ошибок и остановки скрипта в таком случае, будем пользоваться своей функцией с созвучным названием query(), в которую и поместим штатную. Расположим её в этот же файл, чтоб не искать где попало.

<?php;
#Функциязапроса в MySQL 
functionquery ($sql,$file,$line) 
{ 
$res=mysql_query($sql,CONNECT); 
;
if($res) 
{ 
return$res; 
} 
else 
{ 
die('<bstyle="color:red">Musqlerror:</b>'.mysql_error().'<br><b>Query:</b>'.$sql.'<br>
<b>File:</b>'.$file.'<br><b>Line:</b>'.$line); 
header('location:error.html'); 
exit; 
} 
};
#СоединениесMysql 
$db_irbis=mysql_connect(MYSQL_SERVER,MYSQL_USER,MYSQL_PASSWORD)ordie(NO_CONNECT); 
define('CONNECT',$db_irbis); 
#Выборбазы 
mysql_select_db(MYSQL_DATABASE,CONNECT)ordie(NO_DB_SELECT); 
;
#Установкапараметровсоединения 
query('SETNAMESutf8',__FILE__,__LINE__);;
query('SETCHARACTERSETutf8',__FILE__,__LINE__); 
query('SETCOLLATION_CONNECTION="utf8_general_ci"',__FILE__,__LINE__);
?> 

А для удобства передадим в неё аргументами название файла и линию, на которой находится запрос. Это очень удобно, потому что сразу видно где виновник безобразий. А еще мы выведем ответ интерпретатора MySQL и текст запроса. Что бы совсем было все понятно. А когда скрипт отладим, закомментируем строчку от греха по дальше. Порядочному юзеру это совсем не нужно, а хакер может извлечь полезную для себя информацию.

Не пытайтесь запустить скрипт: базы данных пока нет, её нужно создать.

Ну вот, подготовительные работы закончены. Теперь приступим к изготовлению самой базы. Для работы с MySQL в Денвере установлено специальное проложение - phpMyAdmin. Наберите в адресной строке http://localhost/Tools/phpMyAdmin, оно и откроется. В поле "Создать новую БД" раздела MySQL напишите guest (это название нашей базы), а из списка "Сравнение" выберите "utf8_general_si". В соседнем разделе phpMyAdmin соответственно "Russian (ru-utf8)" и "utf8_general_si". Нажмите кнопку "создать".

Поздравляем - теперь у Вас есть собственная база данных. В верхнем меню найдите "Сервер: localhost" и вернитесь в начало. Нам нужно создать пользователя. Ссылка "Привилегии". Заполните форму, отметьте все превилегии и зарегистрируйте юзера на сервере MySQL, то есть создайте пользователя. Имя и пароль соответственно test или поставьте свои, только не забудьте изменить их в нашем конфигурационном файле config.php.

Теперь слева найдите Вашу новую базу (guest) и в поле "Создать новую таблицу в БД guest:" напишите guest_posts, а ниже (Поля:) поставьте 4. Ну и соответственно "Пошел". Заполните таблицу так, как показано на образце:

и нажмите "Сохранить". Всё, теперь у Вас есть таблица. Пока правда пустая. Выглядет она по аналогии с EXCEL примерно так:

id date login text

Тут у нас:
1. id - идентификатор записи. Это не порядковый номер, запомните, это важно. Это уникальный ключ. Присваивается он автоматически при появлении новой записи, за это отвечает auto_increment (Вы выбрали его из списка при формировании таблицы). Суть его такова, что буде присвоернным единожды он будет неизменен. Мало того, если запись удалена, то id этой записи сохраняется и не будет повторно использоваться. Можно со спокойной совестью искать нужную запись по id, это как паспорт.
2. date - соответственно дата записи. Тип поля timestamp, что говорит о том, что запись будет автоматически проштампована датой создания.
3. user - логин юзера, оставившего сообщение. Тип поля varchar используется для хранения данных в строчку
4. text - текст сообщения. Тип поля mediumtext используется для хранения данных в с переносами.
Давайте попробуем что нибудь в таблицу записать. Для этого организуем запрос.
<?
query("INSERTINTO`".PREFIX."posts`
SET`login`='ВасяПупкин',
`text`='МояперваязаписьвБД'"
,__FILE__,__LINE__); 
?>
Команды в SQL регистронезависимы, но для хорошей читабельности кода рекомендуем писать их большими буквами. Названия полей лучше обрамлять обратными кавычками, хотя работает запрос и без них. Для чего это делать. Дело в том, что если имя поля по трагическому стечению обстоятельств совпадет с каким нибудь служебным словом (допустим count) , то запрос будет ошибочным. А обрамленное обратными кавычками слово воспринимается только как имя поля. Строковые (не числовые) значения, передаваемые в запросе, нужно обрамлять апострофами. Команды, выполняемые при запросе, мы рассмотрим постепенно. А сейчас соединим всё в кучу и попробуем посмотреть результат: index.php
<?php 
#Подключаемконфигурационныйфайл 
include'./config.php';
;
#Подключаембазуданных 
include'./libs/mysql_connect.php';;
;
query("INSERTINTO`".PREFIX."posts`;
SET`login`='ВасяПупкин',;
`text`='МояперваязаписьвБД'" 
,__FILE__,__LINE__);
?> 
Запустим скрипт. Ничего на первый взгляд не произошло. Но. Зайдите в phpMyAdmin, слева найдите нашу базу (guest) и нажмите вкладку "ОБЗОР". Вашему взору предстанет первая запись в таблице. Теперь еще одна тонкость. Перепишите запрос таким образом, призвав на помощь нашего старого знакомого:
<?
query("INSERTINTO`".PREFIX."posts`;
SET`login`='O'Rally',;
`text`='МояперваязаписьвБД'" 
,__FILE__,__LINE__);
?>
и запустите скрипт еще раз. Эта запись не появится в базе, а появится ошибка, потому что нарушен синтаксис запроса. Это основа так называемых SQL-инъекций. Получается, что в поле мы пишем только О, а Rally попадает в сам запрос. Если туда написать всяких гадостей(несанкционированных команд), то MySQL может их выполнить и наделать разных неприятностей. Мы не станем рассматривать виды этих нехороших медикаментозных средств, а просто сразу покажем, как от них нужно защищаться. Часто можно встретить такую рекомендацию:
<? 
$text=trim(htmlspecialchars($text));
?> 
Никогда так не делайте. Это абсолютно безграмотно. А: Во первых, обязательно нужно экранировать спецсимволы в строковых значениях. Для этого существуют функции mysql_escape_string() и mysql_real_escape_string(). Нужно сразу отметить, что работают они только при открытом соединениии с сервером MySQL. Во вторых числовые значения, допустим id при выборке, приводить в соответствие функциями (int) или intval(). Важный момент: еще есть директива magic_quotes_gpc (магические кавычки), которая зачастую включена по умолчанию. Эта штука автоматически экранирует входящие данные GET, POST И COOKIE. По этому можно получить двойное экранирование. Её можно отключить в настройках либо в .htaccess Но для того, что бы не запутаться при переносе скрипта на другой хостинг, лучше делать это непосредственно в самом сценарии. Делается это так:
<?php 
functionstripslashes_deep($data);
{;
if(is_array($data));
$data=array_map("stripslashes_deep",$data);;
else 
$data=stripslashes($data);

return$data;;
}
//Теперь, узнав   предварительно, включены ли магические кавычки, мы сможем раз и на всегда   избавиться от нежелательных бэкслэшей:
if(get_magic_quotes_gpc()) 
{ 
$_GET=stripslashes_deep($_GET);;
$_POST=stripslashes_deep($_POST);;
$_COOKIE=stripslashes_deep($_COOKIE); 
} 

Кстати говоря, абривеатура gpc в названии функции get_magic_quotes_gpc() Обозначает $_GET $_POST и $_COOKIE Что в данном случае сделала наша функция? Об этом чуть позже, когда узнаем что такое массив. А пока поместим этот код в файл с коннектом. Теперь приведем всё в порядок. Добавим наш запрос в файл с формой и подключим новые файлы: index.php

<?php header('Content-Type:text/html;charset=utf-8'); $test1=!empty($_POST['test1'])?$_POST['test1']:null; $test2=!empty($_POST['test2'])?$_POST['test2']:null; #Подключаемконфигурационныйфайл include'./config.php'; ; #Подключаембазуданных include'./libs/mysql_connect.php'; ?> <formaction="?"method="post"> <inputname="test1"type="text"value="<?phpechohtmlspecialchars($test1)?>"/><br/> <textareaname="test2"cols="40"rows="10"><?phpechohtmlspecialchars($test2);?></textarea><br/> <inputname="ok"type="submit"/> </form> <?php if(isset($_POST['ok'])) { if(!$test1) echo'Текстовоеполенезаполнено.'; elseif(!$test2) echo'Текстоваяобластьнезаполнена.';; else #Авотинашзапрос.; query("INSERTINTO`".PREFIX."posts`; SET`login`='". mysql_real_escape_string($login) ."', `text`='". mysql_real_escape_string($message) ."'" ,__FILE__,__LINE__);; }; else; {; echo'Напишитечтонибудь';; }; ?>

Попробуйте что нибудь написать в полях и отправить на сервер. В phpMyAdmin (вкладка "Обзор") можно увидеть изменения таблицы. Для того, что бы вывести содержимое на экран, нужен еще один запрос, на выборку. Дополните код этим:
<?php 
.;
.;
#Авотинашзапрос.;
query("INSERTINTO`".PREFIX."posts`;
SET`login`='".mysql_real_escape_string($login)."',;
`text`='".mysql_real_escape_string($message)."'" 
,__FILE__,__LINE__); 
};
else;
{;
echo'Напишитечтонибудь';;
};
#Запроснавыборку;
$result=query("SELECT*FROM`".PREFIX."posts`";
 ,__FILE__,__LINE__);

echomysql_result($result,0,"date");;
echo'/';;
echohtmlspecialchars(mysql_result($result, 0, 'login'));;
echo'<br>';;
echonl2br(htmlspecialchars(mysql_result($result, 0, 'text'))); 

Если сейчас запустить скрипт, то мы увидим последнюю запись из нашей таблицы. Как Вы поняли, выборка осуществляется оператором SELECT. Звездочка обозначает - все поля, FROM соответственно "ИЗ". Далее результат запроса обрабатывается соответствующими функциями, которые позволяют получить желаемое. Вот самый основной принцип работы с базами данных MySQL.

Шаг 4

А мы пока подумаем о флудерах.

Если Вы сейчас еще раз нажмёте кнопку, или обновите страничку (кнопка F5), сообщение запишется еще раз. Что бы надавать флудерам по рукам, нужно сбросить пост данные в случае удачной записи. Делается это формированием новой страницы. Для этого используем хидер. Вспомните, нельзя отправлять заголовок раньше вывода, по этому меняем структуру.

<?php; header('Content-Type:text/html;charset=utf-8');; $test1=!empty($_POST['test1'])?$_POST['test1']:null; $test2=!empty($_POST['test2'])?$_POST['test2']:null;; #Подключаемконфигурационныйфайл; include'./config.php';; #Подключаембазуданных; include'./libs/mysql_connect.php'; ; if(isset($_POST['ok'])); {; if(!$test1) {; echo'Текстовоеполенезаполнено.'; }; elseif(!$test2) {; echo'Текстоваяобластьнезаполнена.'; }; else {; #Авотинашзапрос.; query("INSERTINTO`".PREFIX."posts`; SET`login`='".mysql_real_escape_string($test1)."',; `text`='".mysql_real_escape_string($test2)."'" ,__FILE__,__LINE__);; #ПеренаправлениедлясбросаPOST; header('location:'.$_SERVER['PHP_SELF'].'?rnd='.time());; exit();; } }; else; {; echo'Напишитечтонибудь';; } ?>; <formaction="?"method="post">; <inputname="test1"type="text"value="<?phpechohtmlspecialchars($test1)?>"/><br/>; <textareaname="test2"cols="40"rows="10"><?phpechohtmlspecialchars($test2);?></textarea><br/>; <inputname="ok"type="submit"/>; </form>; <?php; #Запроснавыборку; $result=query("SELECT*FROM`".PREFIX."posts`"; ,__FILE__,__LINE__); $row=mysql_fetch_assoc($result) echo$row['date'];; echo'/';; echohtmlspecialchars($row['login']);; echo'<br>';; echonl2br(htmlspecialchars($row['text'])); ?>

Обратите внимание на дополнительный параметр ?rnd='. time() Сам по себе он не несет ни какой информации, но появление в адресной строке браузера нового адреса даст команду на формирование новой страницы, на которой уже не будет данных в полях. Для информации - $_SERVER['PHP_SELF'] - это адрес Вашего файла со скриптом, то есть того, в котором это написано. Функция time() выдаст ткущее время в секундах, а значит число никогда не повториться. Так как мы изменили структуру, то вывод ошибок теперь выше формы, что не всегда интересно. Особенно когда необходимо разделить логику и вывод. По этому делаем так (а за одно выведем сразу оба сообщения об ошибках):
<?php;
header('Content-Type:text/html;charset=utf-8');;
$test1=!empty($_POST['test1'])?$_POST['test1']:null; 
$test2=!empty($_POST['test2'])?$_POST['test2']:null;
$array_error=array();;
#Подключаемконфигурационныйфайл;
include'./config.php';;

#Подключаембазуданных;
include'./libs/mysql_connect.php'; 
;
if(isset($_POST['ok']));
{;
if(!$test1) 
{;
$array_error[]='Текстовоеполенезаполнено.'; 
};
elseif(!$test2) 
{;
$array_error[]='Текстоваяобластьнезаполнена.'; 
};
else 
{;
#Авотинашзапрос.;
query("INSERTINTO`".PREFIX."posts`;
SET`login`='".mysql_real_escape_string($test1)."',;
`text`='".mysql_real_escape_string($test2)."'" 
,__FILE__,__LINE__);;
#ПеренаправлениедлясбросаPOST;
header('location:'.$_SERVER['PHP_SELF'].'?rnd='.time());;
exit(); 
};
};
else;
{;
echo'Напишитечтонибудь';;
} 
?>;
;
<formaction="?"method="post">;
<inputname="test1"type="text"value="<?phpechohtmlspecialchars($test1)?>"/><br/>;
<textareaname="test2"cols="40"rows="10"><?phpechohtmlspecialchars($test2);?></textarea><br/>;
<inputname="ok"type="submit"/>;
</form>;
<?php;
#Выводошибок 
echoimplode('<br>',$array_error).'<br>';;
#Запроснавыборку;
$result=query("SELECT*FROM`".PREFIX."posts`";
,__FILE__,__LINE__);
$row=mysql_fetch_assoc($result)
echo$row['date'];;
echo'/';;
echohtmlspecialchars($row['login']);;
echo'<br>';;
echonl2br(htmlspecialchars($row['text']));
?>
 

Теперь у нас вся логика вверху, а вывод внизу. Заметили, у переменной появилось [ ]?

Шаг 5

Ну вот мы и добрались до массива.

Массив, это та же переменная, только в неё можно записать несколько раздельных значений. Сделать это можно сразу:

<?php 
$array_error=array('Первоезначение',   'Второезначение', 'Третьезначение');
 ?>

или прибавляя их по очереди:

<?php 
$array_error[]='Первоезначение'; 
$array_error[]='Второезначение'; 
$array_error[]='Третьезначение';
 ?>

Суть этого такова, что в одной переменной находится несколько других. Обратиться к ним (получить их значения) можно либо по порядковому номеру элемента, если это простой массив (заметьте, что нумерация начинается с нуля, а не с единицы):

<?php 
$array_error=array('Первоезначение',   'Второезначение', 'Третьезначение'); 
$value1=$array_error[0]; 
$value2=$array_error[1]; 
$value3=$array_error[2]; 

echo$value1, '<br>', $value2, '<br>',   $value3;
 ?>

либо по ключу (как бы названию переменной), если массив ассоциативный:

<?php 
$array_error=array('Один'=>'Первоезначение','Два'=>'Второезначение','Три'=>'Третьезначение'); 
$value1=$array_error['Один']; 
$value2=$array_error['Два']; 
$value3=$array_error['Три']; 
echo$value1, '<br>', $value2, '<br>',   $value3; 
?>

Что бы не переписывать все переменные для их вывода, используется функция implode(), где первым параметром указывается разделитель между выводом значений. В нашем случае это <br>. То есть что мы сделали: 1. Объявили переменную массивом. 2. Записали в массив все ошибки (их может быть гороаздо больше) 3. Разобрали массив в нужном месте и выдали ошибки на вывод.

Вспомним функцию обработки входящих данных. Что мы сделали в нашей функции.

<?php 
functionstripslashes_deep($data);
{;
if(is_array($data));
$data=array_map("stripslashes_deep",$data);;
else 
returnstripslashes($data);;
}
?> 

is_array() проверяет, является ли переменная массивом. Если это так, то вызываем эту же самую функцию, пока не закончатся все элементы. Это назывется рекурсия - вызов функцией самой себя. А когда переменная не является массивом (добрались до самых глубин) обрабатываем её функцией stripslashes(), которая удаляет экранирующие бэкслэши \ . Дальше, уже девственно очищеные данные мы можем смело использовать в скрипте.

Ну вот, зная что такое массив, тепеперь мы сможем вывести все сообщения, не только последнее. Так как результат запроса на выборку приходит из MySQL в виде массива, состоящего из рядов и ячеек. Разобрать массив на составляющие поможет функция mysql_fetch_assoc() и цикл while. Цикл, это маленькая программка, которая выполняется по кругу столько раз, сколько определено в условиях цикла. Выглядеть это будет так:

<?php 
$result=query("SELECT*FROM`".PREFIX."posts`
ORDERBY`id`DESC"
,__FILE__,__LINE__);
while($row=mysql_fetch_assoc($result)) 
echo$row['date'] .'/'. htmlspecialchars($row['login'])   .'<br>'. nl2br(htmlspecialchars($row['text'])) .'<hr>';
?> 

			

Звучит это примерно вот что: Если запрос прошел успешно, проходим по массиву, который сформировала функция mysql_fetch_assoc() взяв данные на основании идентификатора запроса ($result) и по очереди присваивая переменной $row элементы этого массива и выводим каждый элемент (ряд таблицы) отдельно. Оператор ORDER BY в запросе производит сортировку по заявленному полю (у нас по id). DESC означает - обратная. Это нужно, чтоб сообщения выводились сверху вниз. Если хотите наоборот, поставьте ASC. Засуньте это в свой скрипт и полюбуйтесь результатом.

<?php 
$result=query("SELECT*FROM`".PREFIX."posts`
ORDERBY`id`DESC"
,__FILE__,__LINE__);
$i=0;
while($row=mysql_fetch_assoc($result)) 
{
++$i;
if($i==1 && $page==1 )
echo'<spanstyle="color:red" >'; 
echo$row['date'] .'/'. htmlspecialchars($row['login']) .'<br>'. nl2br(htmlspecialchars($row['text']));
if($i==1 && $page==1 )
echo'</span>';
echo'<hr>'; ;
}
?> 

Шаг 6

Ну а теперь совсем не составит труда снабдить эту цацку ВВ тегами и смайликами.

<?php
$bb=array('|/color|"',
'[B]',
'[/B]',
'[I]',
'[/I]',
'[S]',
'[/S]',
'[U]',
'[/U]',
'[:)]',
'[:(]',
'[;)]',
'[:D]'
); 
$tag=array('</span>',
'<b>',
'</b>',
'<i>',
'</i>',
'<s>',
'</s>',
'<u>',
'</u>', 
'<imgsrc="smailes/1.gif"/>',
'<imgsrc="smailes/2.gif"/>', 
'<imgsrc="smailes/3.gif"/>',
'<imgsrc="smailes/4.gif"/>'
);
$result=query("SELECT*FROM`".PREFIX."posts`
ORDERBY`id`DESC"
,__FILE__,__LINE__);
$i=0;
while($row=mysql_fetch_assoc($result)) 
{
++$i;
if($i==1 && $page==1)
echo'<spanstyle="color:red" >';

$text=nl2br(htmlspecialchars($row['text'])); 
$text=str_replace($bb, $tag, $text); 
;
echo$row['date'] .'/'. htmlspecialchars($row['login']) .'<br>'. $text;
if($i==1 && $page==1)
echo'</span>';
echo'<hr>';;
}
?> 

Поможет сделать это функция str_replace(), которая заменяет то, что задано первым аргументом на то, что задано вторым в строке, заданной третьим аргументом. К счастью эта функция умеет работать с массивами, заменяя соответствующие элементы.

Шаг 7

Для полного счастья снабдим её постраничным выводом. Для этого нам нужно выводить информацию из базы не всю сразу, а порциями. Это делается оператором SQL LIMIT.

<?php 
$result=query("SELECT*FROM`".PREFIX."posts`
ORDERBY`id`DESC 
LIMIT   0, 5 "
,__FILE__,__LINE__);
?> 

Первая цифра обозначает начало отсчета, вторая - конец. То есть этот запрос выведет пять последних записей. (Последних, потому что стоит сортировка в обратном порядке). На основании этого и сделаем постраничку. Сначала функция, определяющая нужный диапазон:

<?php 
functionlist_page() 
{ 
$num=10;;
;
$page=!empty($_GET['page'])?$_GET['page']:1;;
;
$result=query("SELECTCOUNT(*) AS   `cnt`
FROM`".PREFIX."posts`"
,__FILE__,__LINE__);
;
$posts=mysql_result($result,   0);;
$total=intval(($posts-1)/$num)+1;;
$page=intval($page);;
if(empty($page)or$page<0);
$page=1;;
if($page>$total);
$page=$total;;
$start=$page*$num-$num; 
return$start; 
} 
Задаем количество выводимых на странице сообщений ($num = 10). Считаем, сколько сообщений (строк) всего в таблице. Сделать это позволяет оператор COUNT(*) и функция mysql_result(). Она выводит результат запроса, который до этого был прсвоен псевдониму `cnt`. Дословно запрос звучит так: вывести количество рядов, удовлетворяющих условию, как значение поля cnt. Так как такого поля в нашей таблицы нет, MySQL создает так называемый алиас или псевдоним. То есть временное поле. Дальше немного арифметики, что бы не пропустить пустых значений и определить начальное положение. В результате мы имеем стартовую позицию, сформированную в зависимости от того, какая страница выбрана в параметре GET. Теперь нужно сформировать этот параметр, то есть вывести меню постраничной навигации.
functionlist_mehu() 
{ 
$page=!empty($_GET['page'])?$_GET['page']:1; 

for($i=1;$i<=$total;$i++) 
{ 
$for=$i*$num-$num+1; 
$end=$i*$num; 
;
if($page==$i) 
$menu.='<b>['.   $for .'-'. $end .']</b>'; 
else;
$menu.='<ahref="?page='.$i.'"   >['. $for .'-'. $end .']</a>'; 
} 
return$menu; 
} 
Вот тут одна особенность. Для работы нам понадобятся значения переменных $num и $total, а их не видно внутри функции. Первую переменную меняем на константу и выносим в конфигурационный файл:
define("NUM",10); ?>
Соответственно в функциях меняем $num на NUM. А переменную $total объявим глобальной, то есть видимой внутри функций. Тут есть одна тонкость. Дело в том, что если такая переменная встретится в последующем коде, то она будет уже определена, то есть получившая значение. Это может несколько запутать дело, по этому в больших приложениях не злоупотребляйте глобализацией. Ошибки такого плана очень трудно диагностировать. Теперь это выглядет так:
$total=""; 
functionlist_page() 
{ 
global$total;;
;
$page=!empty($_GET['page'])?$_GET['page']:1;;
;
$result=query("SELECTCOUNT(*) AS   `cnt`
FROM`".PREFIX."posts`"
,__FILE__,__LINE__);
;
$posts=mysql_result($result,   0);;
$total=intval(($posts-1)/NUM)+1;;
$page=intval($page);;
if(empty($page)or$page<0);
$page=1;;
if($page>$total);
$page=$total;;
$start=$page*NUM-NUM; 
return$start; 
} 

functionlist_mehu() 
{ 
global$total; 

$page=!empty($_GET['page'])?$_GET['page']:1; 

for($i=1;$i<=$total;$i++) 
{ 
$for=$i*NUM-NUM+1; 
$end=$i*NUM; 
;
if($page==$i) 
$menu.='<b>['.   $for .'-'. $end .']</b>'; 
else;
$menu.='<ahref="?page='.$i.'"   >['. $for .'-'. $end .']</a>'; 
} 
return$menu; 
} 
Вообще, что бы не плясать с бубнами, можно упаковать это всё в класс, но это уже ООП, а мы пока ограничимся простыми функциями. Осталось привести в порядок главный запрос:
$result=query("SELECT*FROM`".PREFIX."posts`
ORDERBY`id`DESC 
LIMIT".   list_page() ."," .NUM
,__FILE__,__LINE__); ?>
А теперь пора привести в порядок и весь скрипт.

Шаг 8

Теперь пора приводить в порядок структуру приложения, так как накопилось уже изрядное количество кода. Так как этот скрипт планировался, как модуль для рассмотренного раньше ядра сайта, то так мы его и представим. У нас будут функции, которые можно использовать не только в гостевой книге. Допустим та же функция форматирования даты . Вывод смайликов тоже определим сюда же, мало ли что. Для них сделаем отдельный, дефолтный файл в библиотеках (libs) default.php

<?php 

#Функцияbb-теговисмайликов 
functionbb_tag($text);
{ 
$bb=array('|/color|"',
'[B]',
'[/B]',
'[I]',
'[/I]',
'[S]',
'[/S]',
'[U]',
'[/U]',
'[:)]',
'[:(]',
'[;)]',
'[:D]'
);

$tag=array('</span>', 
'<b>', 
'</b>', 
'<i>', 
'</i>', 
'<s>', 
'</s>', 
'<u>', 
'</u>', 
'<imgsrc="'.SKIN_PATH.'/images/smailes/1.gif"/>', 
'<imgsrc="'.SKIN_PATH.'/images/smailes/2.gif"/>', 
'<imgsrc="'.SKIN_PATH.'/images/smailes/3.gif"/>',;
'<imgsrc="'.SKIN_PATH.'/images/smailes/4.gif"/>' 
); 
;
returnstr_replace($bb,$tag,$text); 
};
;
#Функцияпереводадатыизазиатскогоформатавпрописной;
functionformat_date($date);
{;
global$string_month;;
$day=substr($date,8,2);;
$month=$string_month[substr($date,5,2)];;
$year=substr($date,0,4);;
;
return$day.''.$month.''.$year;;
} 


//Выводошибок 
functionerror_info($array_error) 
{ 
if(!empty($array_error)) 
{ 
$error=implode('<br>',$array_error); 
return$error; 
} 
else 
{ 
returnfalse; 
} 
} 

Туда же, в директорию libs поместим файл коннекта и вынесем функции постраничного режима:

connect.php

<?php;
#Функциязапроса в MySQL 
functionquery($sql,$file,$line) 
{ 
$res=mysql_query($sql,CONNECT); 
;
if($res) 
{ 
return$res; 
} 
else 
{ 
die('<bstyle="color:red">Musqlerror:</b>'.mysql_error().'<br><b>Query:</b>'.$sql.'<br>
<b>File:</b>'.$file.'<br><b>Line:</b>'.$line); 
header('location:error.html'); 
exit; 
} 
};
#Борьба с магическими кавычками ;
functionstripslashes_deep($data);
{;
if(is_array($data));
$data=array_map("stripslashes_deep",$data);;
else 
returnstripslashes($data);;
} 
if(get_magic_quotes_gpc()) 
{ 
$_GET=stripslashes_deep($_GET);;
$_POST=stripslashes_deep($_POST);;
$_COOKIE=stripslashes_deep($_COOKIE); 
} 
#СоединениесMysql 
$db_irbis=mysql_connect(MYSQL_SERVER,MYSQL_USER,MYSQL_PASSWORD)ordie(NO_CONNECT); 
define('CONNECT',$db_irbis); 
#Выборбазы 
mysql_select_db(MYSQL_DATABASE,CONNECT)ordie(NO_DB_SELECT); 
;
#Установкапараметровсоединения 
query('SETNAMESutf8',__FILE__,__LINE__);;
query('SETCHARACTERSETutf8',__FILE__,__LINE__); 
query('SETCOLLATION_CONNECTION="utf8_general_ci"',__FILE__,__LINE__);
?> 
listiner.php
<?php 
$total="";;
functionlist_page($table);
{;
global$total;;
;
$page=!empty($_GET['page'])?$_GET['page']:1;;
;
$result=query("SELECTCOUNT(*)AS`cnt` 
FROM`".PREFIX.$table."`" 
,__FILE__,__LINE__); 
;
$posts=mysql_result($result,0);;
$total=intval(($posts-1)/NUM)+1;;
$page=intval($page); 
;
if(empty($page)or$page<0);
$page=1; 
;
if($page>$total);
$page=$total; 
;
$start=$page*NUM-NUM; 
;
return$start;;
};
functionlist_menu($mod=NULL);
{;
global$total;;
$page=!empty($_GET['page'])?$_GET['page']:1;;
;
if($mod);
$mod='&mod='.$mod; 
for($i=1;$i<=$total;$i++);
{;
$for=$i*NUM-NUM+1;;
$end=$i*NUM;;
;
if($page==$i);
$menu.='<b>['.$for.'-'.$end.']</b>';;
else;
$menu.='<ahref="?page='.$i.$mod.'"">['.$for.'-'.$end.']</a>';;
};
return$menu;;
}
?> 
Заметьте, мы передали аргументом в первую функцию название таблицы, а во вторую название модуля. И теперь этот функционал (постраничку) можно использовать не только в гостевой книге, но и при выводе новостей к примеру. Или еще где нибудь. Затем вынесем все служебные слова в языковой файл language/ru.php
<?php;
define('NO_CONNECT','Произошлаисключительнаяситуация.Сервербазданныхнедоступен.
Приносимсвоиизвинения.Попробуйтеповторитьпопыткупозже');;
define('LOGIN_ERROR','Текстовоеполенезаполнено.'); 
define('MESS_ERROR','Текстоваяобластьнезаполнена.'); 
define('NEW_MESS','Напишитечтонибудь'); 
;
;
$language=array( 
'title'=>'Мойсайт', 
'login'=>'Логин:',;
'message'=>'Сообщение:', 
'back'=>'Вернутьсянасайт', 
); 
;
;
$string_month=array(;
'01'=>'января',;
'02'=>'февраля',;
'03'=>'марта',;
'04'=>'апреля',;
'05'=>'мая',;
'06'=>'июня',;
'07'=>'июля',;
'08'=>'августа',;
'09'=>'сентября',;
'10'=>'октября',;
'11'=>'ноября',;
'12'=>'декабря';
);
?> 
Настройки вынесем в конфигурационный файл, он у нас уже есть в корне config.php
<?php 
#Логин=>Парольдлядоступавадмин-панель;
$admins=array(;
"root"=>"root",;
"Petia"=>"54321";
);;
#Выборскина 
define('SKIN','default'); 
#Выборязыка 
define('LANGUAGE','ru'); 
#Количество сообщений на странице 
define("NUM",10);
#Настройкиподключения 
define('MYSQL_SERVER','localhost'); 
define('MYSQL_DATABASE','guest'); 
define('MYSQL_USER','root'); 
define('MYSQL_PASSWORD',''); 
define('PREFIX',   'guest_'); 
#Путьдоскина;
define('SKIN_PATH','http://'.$_SERVER['HTTP_HOST'].'/skins/'.SKIN); 
?>
А инициализацию переменных в свой - vars.php
<?php;
#Переключениемодулей 
$mod=!empty($_GET['mod'])?$_GET['mod']:NULL; 
#Переключениеразделов 
$rem=!empty($_GET['rem'])?$_GET['rem']:NULL; 
#Постраничка;
$page=!empty($_GET['page'])?$_GET['page']:NULL; 
#Форма;
$login=!empty($_POST['login'])?$_POST['login']:NULL;;
$message=!empty($_POST['message'])?$_POST['message']:NULL; 
#Удаление;
$delet=isset($_POST['delet'])?$_POST['delet']:array(); 
#Кнопка;
$ok=isset($_POST['ok'])?true:false; 
#Массивошибок 
$array_error=array(); 
#Дефолтнаянадпись 
$default='';
#Переменная   сообщений 
$body_mess=''; 
#Ключвходавадминку;
$key=false; 
?>
Еще, для полного счастья, в файл .htaccess добавим несколько директив
AddDefaultCharsetUTF-8 
php_flagmagic_quotes_gpcOff 
php_flagmagic_quotes_runtimeOff 
php_flagregister_globalsOff 
ErrorDocument401/401.html 
ErrorDocument403/403.html 
ErrorDocument404/404.html 
Здесь первая (уже проходили) - кодировка; Вторая и третья - отключаем магические кавычки, что бы при возврате данных в форму небыло лишних бэкслэшей; Четвертая - отключаем глобальные переменные, это не безопасно; Пятая - седьмая - страницы ошибок. Их тоже нужно сделать и положить в корень. Выглядеть они должны как угодно, но что бы было понятно, что юзер ошибся в наборе адреса к примеру. Все ссылки и пути на этих страницах должны быть абсолютными. Вот не мудрствуя лукаво (404.html):
<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<htmlxmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/> 
<title>404</title> 
</head> 
<body> 
<h1>404</h1> 
</body> 
</html> 
Теперь организуем шаблоны. Директория skins/default и в ней два файла header.html
<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<htmlxmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/> 
<title><?phpecho$title;?></title> 

<linkhref="<?phpechoSKIN_PATH;?>/css/style.css"rel="stylesheet"type="text/css"/> 
</head> 
<body> 
<divclass="content"> 
и footer.html
</div> 
</body> 
</html> 
Теперь тут же организуем еще четыре директории - css images js и саму папку для гостевой книги guestbook Как можно уже догадаться, в них мы будем размещать стили, картинки, скрипты и непосредственно шаблоны гостевой книги. Впрочем последний у нас всего один, вот он: show.html
<?php echo $default ?>
<br/><formaction=""method="post">;
<?php echo $language ['login']; ?>
<br/>;<inputname="login"type="text"value="<?phpecho$login?>"/><br/>;
<?php
echo $language ['message'];
?>
<br/>;<textareaname="message"cols="40"rows="10">
<?php echo $message; ?>
</textarea><br/>;
<inputname="ok"type="submit"/>;</form> 
<spanstyle="color:red"><b>
<?php echo $error;?>
</b></span><br/> 
<?phpecho$body_mess;?> 
<?phpecho$list_menu;?> 
А теперь самое главное - главный индексный файл. Тот самый диспетчер, который будет переключать модули: index.php
<?php;
ob_start();;
;
#Установкаопределенияошибок;
error_reporting(E_ALL&~E_NOTICE); 
;
#Заголовокскодировкойиконтент-типом 
header('Content-Type:text/html;charset=utf-8'); 
;
#Подключаемконфигурационныйфайл 
include'./config.php'; 

#Подключаемязыковойфайл 
include'./language/'.LANGUAGE.'.php'; 
;
#Подключаемфайлинициализациипеременных 
include'./vars.php';
#Подключаембазу данных 
include'./libs/mysql_connect.php';
;
#Подключаемобщиефункции 
include'./libs/default.php';
#Подключаемшапку 
include'./skins/'.SKIN.'/header.html'; 
;
switch($mod) 
{ 
case'admin': 
#Подключаемадмин-панель 
include'./admin/index.php';;
break; 
;
default:;
#Подключаеммодульгостевойкниги 
include'./modules/guestbook/index.php';;
break; 
;
} 
;
#Подключаемподвал 
include'./skins/'.SKIN.'/footer.html'; 
$buffer=ob_get_contents(); 
ob_end_clean(); 
echo $buffer;
?> 

Ну вот, все расставили по полочкам, пора сделать и сам модуль.

Шаг 9

Продолжаем разговор. В корне у нас есть директория modules, если Вы делали структуру сайта в прошлом разделе. Ну а нет, так сделайте сейчас же. В ней нужно организовать еще один каталог - guestbook. Вот в нем и будет все управление модулем. Сначала индекс модуля, локальный диспетчер. index.php

<?php;

#Подключаемфункциипостраничного режима 
include'./libs/listiner.php'; 
#Контроллердобавлениясообщений;
include_once'./modules/guestbook/add_controller.php'; 
#Контроллерчтениясообщений;
include_once'./modules/guestbook/read_controller.php'; 
#Приводимвыводвпорядок 
include_once'./modules/guestbook/view.php'; 
#Подключаемшаблон 
include_once'./skins/'.SKIN.'/guestbook/show.html';
?> 
Затем по порядку. Контроллер добавления сообщений: add_controller.php
<?php;
;
if($ok);
{;
if(!$login);
{;
$array_error[]=LOGIN_ERROR;;
};
elseif(!$message);
{;
$array_error[]=MESS_ERROR;;
};
else;
{;
#Авотинашзапрос.;
query("INSERTINTO`".PREFIX."posts`;
SET`login`='".mysql_real_escape_string($login)."',;
`text`='".mysql_real_escape_string($message)."'";
,__FILE__,__LINE__);;
#ПеренаправлениедлясбросаPOST;
header('location:'.$_SERVER['PHP_SELF'].'?rnd='.time());;
exit();;
};
};
else;
{;
$default=NEW_MESS;;
}
?> 
Контроллер чтения сообщений read_controller.php
<?php
$result=query("SELECT*FROM`".PREFIX."posts`
ORDERBY`id`DESC 
LIMIT".   list_page('posts')   .","   .NUM
,__FILE__,__LINE__);

$count=mysql_num_rows($result);

while($row=mysql_fetch_assoc($result)) 
{

if($row['id']==$count) 
$body_mess.='<spanstyle="color:red" >';
;
$body_mess.='<divclass="header_mess">'. format_date($row['date']) .'/'. htmlspecialchars($row['login']). '</div>';
$text=nl2br(htmlspecialchars($row['text']));
$body_mess.='<divclass="body_mess">'.bb_tag($text).'</div>';
if($row['id']==$count) 
$body_mess.='</span>';
;
}
?> 
И файл view.php, в котором мы приведем в порядок переменные вывода:
<?php;
;
$login=htmlspecialchars($login); 
$message=htmlspecialchars($message); 
$error=error_info($array_error); 
$list_menu=list_menu();
?> 

Осталось накрасить губы: cделать верстку шаблона (или нескольких). Вот собственно и всё. Готов модуль. Можно смело ждать хороших отзывов и пожеланий (Сам себя не похвалишь - сидишь как оплеванный). Ну и админка на закуску в следующем разделе.

Шаг 10

Админка

Ну какая уважающая себя гостевая книга без модерации? Снабдим её админкой. Тем более почти всё для этого уже готово. В корне сделаем еще одну директорию - admin Бытует мнение, что админки нужно маскировать экзотическими именами, но это дело на любителя. Если поставить нормальную защиту, то эта операция и не понадобится вовсе. Вот и сама защита sequrity.php

<?php 

if(empty($_SERVER['PHP_AUTH_USER']));
{;
header('WWW-Authenticate:Basicrealm="AdminPage"');;
header('HTTP/1.0401Unauthorized');;
exit();;
};

$key=false;

foreach($adminsas$admin=>$password);
if($_SERVER['PHP_AUTH_USER']===$admin&&$_SERVER['PHP_AUTH_PW']===$password);
$key=true;
if(!$key);
exit('Нетураздавать.'); 
Как видите, мы не мудрствуя лукаво использовали бэйсик - авторизацию. Обратите внимание на === Это не опечатка, это оператор "строго равно". Он отличается от просто "равно" тем, что не преобразует типы данных. То есть строковые переменные приравнивает только к строковым, а числовые только к числовым. Защита готова. Поместите этот модуль в папку admin в корень сайта Теперь сама админка. Метод POST дает возможность передавать данные массивом. Воспользуемся этим и присвоим им уникальные имена Сделаем отдельный контроллер для админки гостевой книги, нам могут понадобиться и другие контроллеры, что бы управлять всем сайтом. За основу возьмем контроллер чтения и маленько его модернизируем. Метод POST дает возможность передавать данные массивом. Воспользуемся этим и присвоим им нужные имена: guest_controller.php
<?php;
$result=query("SELECT*FROM`".PREFIX."posts`
ORDERBY`id`DESC 
LIMIT".   list_page('posts')   .","   .NUM
,__FILE__,__LINE__);
while($row=mysql_fetch_assoc($result));
{
;
$body_mess.='<divclass="header_mess">
<inputname="delet['. $row['id']. ']"value="'. $row['id'] .'"type="checkbox"/>'
.   format_date($row['date']) .'/'. htmlspecialchars($row['user']). '</div>';
$text=nl2br(htmlspecialchars($row['text']));
$body_mess.='<divclass="body_mess">'.bb_tag($text).'</div>';
;
}
Ну а теперь нужно удалить отмеченные:
if($ok);
{ 

$id_arr=isset($_POST['delet']) ?   array_map("intval",$_POST['delet']) : array(); 

query("DELETEFROM`".PREFIX."posts`
   WHERE`id`IN(".implode(",",$id_arr).")"
,__FILE__,__LINE__);
}
?> 
Оператор DELETE удаляет строку таблицы, указанную в условии WHERE. Так как строк может быть много, используем оператор IN, который позволяет перечислять нужные элемены через запятую.А составить такой список можно собрав в строку элементы массива, используя рвзделитель - запятую. Делает это функция implode() Всё, теперь контроллер админки гостевой книги будет выглядеть так:
<?php
;
if($ok);
{ 

$id_arr=isset($_POST['delet']) ?   array_map("intval",$_POST['delet']) : array(); 

query("DELETEFROM`".PREFIX."posts`
   WHERE`id`IN(".implode(",",$id_arr).")"
,__FILE__,__LINE__);
}

$result=query("SELECT*FROM`".PREFIX."posts`
ORDERBY`id`DESC 
LIMIT".   list_page('posts')   .","   .NUM
,__FILE__,__LINE__);
while($row=mysql_fetch_assoc($result));
{
;
$body_mess.='<divclass="header_mess">
<inputname="delet['. $row['id']. ']"value="'. $row['id'] .'"type="checkbox"/>'
.   format_date($row['date']) .'/'. htmlspecialchars($row['login']). '</div>';

$text=nl2br(htmlspecialchars($row['text']));
$body_mess.='<divclass="body_mess">'.bb_tag($text).'</div>';
;
}
?>
Теперь опять приводим все в порядок в файле view.php:
<?php;
;
$error=error_info($array_error);;
$list_menu=list_menu('admin');
?> 
и собираем всю конструкцию в индекс админки:
<?php 
include'./admin/sequrity.php'; 
switch($rem) 
{ 
case'guestbook': 
#Подключаемфункциипостраничного режима 
include'./libs/listiner.php'; 
#Подключаемконтроллергостевойкниги;
include'./admin/guest_controller.php';;
break; 
#Поумолчанию;
default: 
#Подключаемфункциипостраничного режима 
include'./libs/listiner.php'; 
#Подключаемконтроллергостевойкниги;
include'./admin/guest_controller.php';;
break;;
} 
;
include'./admin/view.php'; 
;
include_once'./skins/'.SKIN.'/admin/guest.html'; 
Теперь в папку со скинами добавим директорию для админки admin, а в неё шаблон guest.html
<ahref="index.php?page=<?phpecho$page?>"><?phpecho$language['back'];?></a><br/> 
<?phpecho$error?> 
<formaction="?mod=admin&page=<?phpecho$page?>"method="post"> 
<?phpecho$list_menu;?><br/> 
<?phpecho$body_mess?><br/> 
<inputname="ok"type="submit"value="Удалить"/><br/> 
<?phpecho$list_menu;?> 
</form> 

Всё. Теперь нужно набрать в адресной строке примерно следующее: http://my-site.ru/?mod=admin, написать в открывшемся окне логин - пароль, который предварительно указать в конфигурационном файле и смело бороться с флудерами и матершинниками.

PS Не забудьте закомментировать строку диагностики в файле коннекта:
<?php
#ФункциязапросавMySQL;
functionquery($sql,$file,$line);
{;
$res=mysql_query($sql,CONNECT);
if($res);
{;
return$res;;
};
else;
{;
//die('<bstyle="color:red">Musqlerror:</b>'.mysql_error().'<br><b>Query:</b>'.$sql.'<br>
<b>File:</b>'.$file.'<br><b>Line:</b>'.$line);;
header('location:error.html');;
exit;;
};
}
?> 

скопированно с сайта http://irbis-team.ru


• • •
6


  3 2 1 0 1 2 3