Архив статей

Все статьи из текущего раздела

Slashdot? На PHP - халява!

Slashdot.org - популярный новостной портал с посещаемостью 50 млн. человек в месяц. Авторы проекта добились такого успеха, предоставляя пользователям свежие и интересные новости из мира IT, а также возможность оставлять под публикацией собственные комментарии. Это очень важное обстоятельство, поскольку со временем постоянные посетители любого такого проекта, выявляя общие интересы и привязываясь к месту общения, образуют единый социум. Ни e-mail, ни даже irc не могут им заменить такого ресурса, поскольку только здесь создана та неповторимая социо-информационная среда, от которой они просто тащатся. Отсюда и 50 миллионов посещений в месяц. Верный подход, хорошая реализация. К слову, насчет реализации - Slashdot написан на Perl. Мы же реализуем эту, в общем-то, несложную задачу, на PHP. Увидишь - это просто :).

Создание таблиц

Как я уже неоднократно отмечал, прежде чем приступать к написанию скриптов, надо продумать структуру информационной среды, в которой они будут работать. В нашем случае мы будем иметь дело с сервером баз данных mysql, а информация, стало быть, будет храниться в таблицах.

Таблица со статьями:

mysql> create table posts(

-> pid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,

-> aid INT NOT NULL,

-> cid INT NOT NULL,

-> text TEXT NOT NULL,

-> date DATE NOT NULL,

-> time VARCHAR(15) NOT NULL,

-> timest INT NOT NULL);

Query OK, 0 rows affected (0.01 sec)

Pid - уникальный идентификатор статьи, aid - автора, cid - рубрики, text - текст статьи, date/time - время, timest - время по unix-исчислению.

Таблица с информацией об авторах:

mysql> create table authors(

-> aid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,

-> fname VARCHAR(50) NOT NULL,

-> email VARCHAR(50) NOT NULL,

-> login VARCHAR(30) NOT NULL,

-> password VARCHAR(20) NOT NULL,

Query OK, 0 rows affected (0.01 sec)

aid - идентификатор автора, fname - его имя. Email - адрес электронной почты, login - логин для входа в административный интерфейс, password - пароль.

Таблица с комментариями:

mysql> create table comments(

-> coid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,

-> pid INT NOT NULL,

-> aname VARCHAR(50) NOT NULL,

-> aemail VARCHAR(50) NOT NULL,

-> comment TEXT NOT NULL,

-> date DATE NOT NULL,

-> time VARCHAR(15) NOT NULL,

-> timest INT NOT NULL);

Query OK, 0 rows affected (0.01 sec)

Coid - идентификатор комментария, pid - идентификатор статьи, к которой относится комментарий, aname - имя автора комментария, comment - текст, date/time - время, timest - время по unix-исчислению.

Таблица с рубриками:

mysql> create table categories(

-> cid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,

-> category VARCHAR(30) NOT NULL,

-> eids VARCHAR(50) NOT NULL);

Query OK, 0 rows affected (0.00 sec)

Cid - идентификатор рубрики, category - название рубрики, eids - идентификаторы редакторов рубрик.

Описание функций

Система будет представлять собой совокупность четырех скриптов:

index.php - главная страница сайта, скрипт для вывода статей, поиска по ним и т.д.

admin.php - административный скрипт.

config.php - скрипт конфигурации.

kernel.inc.php - ядро системы, файл, в котором хранятся все небазовые узкоспециализированные функции, написанные ранее программистом для использования в системе. Это очень эффективное и красивое решение. Во-первых, отпадает нужда многократно выписывать одни и те же куски кода - один раз описал функцию и все, юзай на здоровье. Во-вторых, следуя этому приему, ты создаешь красивые многоуровневые, хорошо масштабируемые приложения, легкие в отладке и дальнейшей модернизации. Внимательный читатель и просто дальновидный человек без особых проблем найдет еще не один десяток преимуществ такого подхода, мы же перейдем к описанию функций, используемых в создаваемом нами новостном движке.

connect(dbname) - возвращает указатель на активное соединение с БД dbname.

get_author_info_by_aid(aid) - позволяет получить информацию об авторе статьи по его универсальному идентификатору (aid). Он возвращает ассоциативный массив, ключами которого являются имена соответствующих полей таблицы.

showposts([category], [start], [howmuch]) - принимает три необязательных параметра. Первый указывает на раздел сайта, откуда выбираются статьи. Второй и третий параметры позволяют показывать определенное количество статей (сколько именно – указывает параметр howmuch), начиная со статьи, указанной параметром start. Для всех параметров предусмотрены значения по умолчанию.

showpost(pid) - показывает статью, производя выборку из БД по ее уникальному идентификатору pid.

showcomments(pid) - выводит комментарии пользователей к статье pid.

addcommentform(pid) - выводит форму для добавления комментария.

addcomment(aname, aemail, comment, pid) - добавляет комментарий к статье pid. Все параметры являются обязательными.

navigation - выводит навигационную строчку.

auth - выводит форму для аутентификации автора.

athinfo(login) - возвращает ассоциативный массив с информацией об авторе.

isadmin(login,passwd) - проверяет, есть ли в БД автор с такой комбинацией login/pass.

iseditor(aid, cid) - проверяет, указан ли автор с идентификатором aid в качестве редактора раздела cid.

Аналогичным образом определяются остальные блоки. При этом желательно соблюдать согласованность функций, т.е. все они должны работать на одном логическом уровне, и результаты работы одних будут входными параметрами для других. Все блоки принято сохранять в файле с расширением .inc.php, хотя, на самом деле, это абсолютно неважно. Важно лишь, чтобы вебсервер не позволял клиентам просматривать содержимое этого файла. Но с другой стороны, надо же как-то отличать выполняемый скрипт, обрабатывающий данные и генерирующий выходной поток, от модульного файла, в котором содержатся лишь блоки кода.

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

<? require(kernel.inc);

connect(db);

showposts(); ?>

Скрипты index.php и admin.php будут строиться следующим образом. В зависимости от передаваемого параметра do, скрипты будут при помощи уже написанных функций выполнять различные действия: либо показывать конкретную статью, либо осуществлять навигацию/поиск по архиву, выполнять административные задачи и т.п. Этим мы в следующий раз и займемся - свяжем написанные функции в единую систему, что в будущем поможет тебе сделать проект с посещаемостью не 50, а 150 млн. хостов в месяц.

<?

function connect($db)

{

$co=mysql_connect("localhost", "root","");//Подключаемся к серверу БД

if (!($co)) {echo "Не удалось подключиться к серверу БД!";} //Если не вышло…

else { mysql_select_db($db); return $co; } // Если все ок

}

function get_author_info_by_aid($aid)

{

$sql="select * from authors where aid=`$aid`"; //Составляем sql-запрос

$aut=mysql_query($sql); //посылаем его

$auth=mysql_fetch_array($aut); //Помещаем ответ в ассоциативный массив

return $auth; //возвращаем массив

}

function showposts($category=`no`,$start=1,$howmuch=20)

{

$sql="select * from posts";

if ($category!=`no`) {$sql.=" where cid=`$category`";} //Если в переменной $category находится значение не по умолчанию, т.е. она определена программистом, к составленному строчкой выше запросу присоединяется новое условие

$sql.=" order by timest desc limit $start,$howmuch"; // Это условие выборки статей по howmuch, начиная со start в порядке убывания поля timest

$re=mysql_query($sql); //отсылаем запрос

while ($res=mysql_fetch_array($re)) //цикл для прохода по всем возвращенным записям в БД

{

$author=get_author_info_by_aid($res[aid]); //получаем информацию об авторе по его идентификатору

$head=substr($res[text],0,99); //берем первые 100 знаков текста статьи

echo "Автор: <b>$author[fname]</b>

Дата: <b>$res[date]</b><br>

Время: <b>$res[time]</b><br>

$head<br>

<a href=`?do=read&pid=$res[pid]`>[more...]</a><br>"; //Выводим информацию о материале

}

}

function showpost($pid)

{

$sql="select * from posts where pid=`$pid`"; //Запрос на получение статьи pid

$po=mysql_query($sql);

$post=mysql_fetch_array($po);

$author=get_author_info_by_aid($post[aid]);

echo "$post[text]<br><p align=rigth><b>$author[fname] ($author[email])<br>$post[date], $post[time]</p>"; //Выводим статью

}

function showcomments($pid)

{

$sql="select * from comments where pid=`$pid` order by `timest` desc"; //Запрос на получение комментариев читателей к статье

$co=mysql_query($sql);

while($comm=mysql_fetch_array($co))

{

echo "$comm[comment]<br>$comm[aname]($comm[aemail])<br>$comm[date],$comm[time]<hr>"; //Выводим все комментарии

}

}

function addcommentform($pid)

{

echo "<form action=index.php method=post>

<input type=hidden name=pid value=`$pid`>

Имя: <input type=text name=aname><br>

E-mail: <input type=text name=aemail><br>

Комментарий: <textarea name=comment></textarea><br>

<input type=submit name=submit value=`Отправить`>";

} //Выводим форму для добавления комментария к статье

function addcomment($aname, $aemail, $comment, $pid)

{

$date=date("Y-m-d"); //Получаем сегодняшнюю дату (см. мануал по команде date)

$time=date("H:i"); //Получаем время

$timest=time(); //Время по unix-исчислению

$sql="insert into comments values(null, `$pid`, `$aname`, `$aemail`, `$comment`, `$date`, `$time`,`$timest`)"; //Запрос на добавление записи

$a=mysql_query($sql);

}

function navigation()

{

$sql="select * from categories";

$na=mysql_query($sql);

while ($nav=mysql_query($sql))

{

echo "<a href=`?do=view&cat=$nav[cid]`>$nav[category]</a> ";

}

}

#Admin interface`s functions are getting start

function auth()

{

echo "Authentification required!

<form action=admin.php method=post>

login: <input type=text name=login><br>

pass : <input type=passwd name=passwd><br>

<input type=submit name=tr value=`login`>

"; //Выводим форму для аутентификации администратора

}

function athinfo($login)

{

$sql="select * from authors where login=`$login`"; //Запрос на поиск информации об администраторе с логином $login

$re=mysql_query($sql);

$result=mysql_fetch_array($re);

return $result;

}

function isadmin($login,$passwd)

{

$result=athinfo($login);

if ($result[password]==$passwd) { return true; } else { return false; }

}

function iseditor($pid, $cid)

{

$sql="select * from categories where cid=`$cid`"; //Запрос на получение информации о разделе $cid

$ac=mysql_query($sql);

$acc=mysql_fetch_array($ac);

$access=$acc[access]; //Здесь перечислены через | редакторы раздела

$accs=explode("|",$access); //режем эту строчку в массив по символу |

for ($i=0; $i<=count($accs); $i++) //цикл по всем указанным редакторам

{

if($accs[$i]==$pid) { return true; } //Если администратор $aid указан в качестве редактора этого раздела

}

}

?>