Поле
|
Тип
|
Длина
|
Описание
|
Id
|
INT
|
11
|
Уникальный
номер пользователя
|
Login
|
INT
|
11
|
Имя
пользователя в системе
|
Password
|
INT
|
11
|
Пароль
в зашифрованном виде
|
Salt
|
VARCHAR
|
30
|
Случайная
строка, используется для шифрования пароля
|
Status
|
TEXT
|
65535
|
Статус
пользователя (обычный, администратор, заблокирован)
|
Описание пользовательского
интерфейса и программных модулей
При разработке пользовательского интерфейса необходимо
учитывать следующие требования:
1) интерфейс должен быть максимально удобен
и интуитивно прост;
2) пользователь должен иметь «под рукой»
все необходимые средства для типовой работы с данными;
) информация должна в зависимости от
выполняемых задач разбита на логические подгруппы в пределах одной формы (так,
кнопки «назад» и «вперед» должны размещаться рядом)
) информации не должно быть слишком
много, чтобы в ней было легко ориентироваться;
) для визуального оформления и
эстетически приятного восприятия информации следует вводить графические
элементы - фоновые картинки и прочую графику, использовать различные шрифты;
) однако шрифтами не стоит злоупотреблять
- следует избегать убористого текста, вычурных и трудночитаемых начертаний,
цветов, которые плохо воспринимаются, сильного различия в размерах шрифтов в
пределах одной формы (желательно в пределах всего проекта).
Исходя из этих требований, необходимо создавать
интерфейс программы. Когда проектирование интерфейса и компоновки элементов
закончено, идет собственно верстка, когда при помощи средств JavaScript,
CSS и HTML
создается законченный интерфейс. После отладки макета верстки в различных
браузерах идет собственно написание программного кода продукта, его отладка и
выдача окончательного варианта в виде совокупности сверстанных страниц и
результатов выполнения серверных скриптов.
При входе в систему пользователь видит перед
собой форму, показанную на рисунке 6. Пользователь может ввести данные в поля
ввода и войти в систему под своим аккаунтом. Если у него еще нет учетной
записи, то он может зарегистрироваться в системе или воспользоваться гостевым
входом, просматривая профили пользователей, их закладки и имея возможность
поиска. Если пользователь при входе поставит галочку «запомнить», то сценарий запишет
на его ПК cookies
(cookie-набор), в котором
в зашифрованном виде будет сохранен пароль и логин. При следующем входе в
систему пользователю не нужно будет их вводить заново. Запоминание пользователя
длится две недели.
Рис. 6
Код аутентификации на сайте выглядит следующим
образом:
<?php_start();('mysql.php');(isset($_GET['logout']))
{(isset($_SESSION['user_id']))
{($_SESSION['user_id']);($_SESSION['adm']);
}('login', '', 0,
"/");('password', '', 0, "/");
// и переносим его на главную('Location:
index.php');
exit;
}(isset($_SESSION['user_id']))
{
// юзер уже залогинен, перекидываем его отсюда
на закрытую страницу
header('Location: profile.php');;
}
$error = false;
$ert = '';(!empty($_POST))
{
$login = (isset($_POST['login'])) ?
mysql_real_escape_string($_POST['login']) : '';
$query = "SELECT
`salt``users``login`='{$login}'1";
$sql = mysql_query($query) or
die(mysql_error());(mysql_num_rows($sql) == 1)
{
$row = mysql_fetch_assoc($sql);
// итак, вот она соль, соответствующая этому
логину:
$salt = $row['salt'];
// теперь хешируем введенный пароль как надо и
повторям шаги, которые были описаны выше:
$password =
md5(md5($_POST['password']) . $salt);
// и пошло поехало...
// делаем запрос к БД
// и ищем юзера с таким логином и паролем
$query = "SELECT `id`,
`status``users``login`='{$login}' AND `password`='{$password}'1";
$sql = mysql_query($query) or
die(mysql_error());
// если такой пользователь
нашелся(mysql_num_rows($sql) == 1)
{
// то мы ставим об этом метку в сессии (допустим
мы будем ставить ID пользователя)
$row = mysql_fetch_assoc($sql);
$_SESSION['user_id'] =
$row['id'];($row['status'] == 1)
$_SESSION['adm'] = 1;if
($row['status'] >= 20)
{
$error = true;
$ert .= 'Вы
заблокированы';($_SESSION['user_id']);($_SESSION['adm']);
}
// если пользователь решил "запомнить
себя"
// то ставим ему в куку логин с хешем
пароля(!$error)
{
$time = 86400*7*2; // ставим куку на 2 недели
if (isset($_POST['remember']))
{('login', $login, time()+$time,
"/");('password', $password, time()+$time, "/");
}
// и перекидываем его на закрытую страницу
header('Location:
profile.php?id='.$_SESSION['user_id']);
exit;
}
// не забываем, что для работы с сессионными
данными, у нас в каждом скрипте должно присутствовать session_start();
}
{
$ert .= 'Пользователь не найден';
$error = true;
}
}
{
$error = true;
$ert .= 'Пользователь не найден';
}
}
include
'header.php';
?>
<script
type="text/javascript" language="JavaScript">
<!--roll(obj, n)
{(n).style.backgroundImage =
'url("html-bg-hover.gif")';.style.backgroundImage =
'url("html-bg-normal.gif")';
}
//-->
</script>
<?'
<form
action="login.php" method="post">
<b
style="position:relative;top:15px;left:5px;">Вход
в
систему</b>
<div
style="position:relative;top:30px;left:10px;">
<div
style="position:relative;top:10px;">Логин: <input
type="text" name="login"
style="position:absolute;left:60px;width:130px;" /></div>
<div
style="position:relative;top:20px;">Пароль: <input
type="password" name="password"
style="position:absolute;left:60px;width:130px;"/></div>
<div
style="position:relative;top:30px;">Запомнить: <input
type="checkbox" name="remember" /></div>
<div
style="position:relative;top:40px;left:40px;">
<div
style="cursor:pointer;cursor:hand;background:url(\'html-bg-normal.gif\')
no-repeat;color:#fff;width:70px;height:24px;text-align:left;line-height:24px;padding-left:15px;"
onClick="f.submit()"onMouseOver="roll(this, 1)" onMouseOut="roll(this,
0)">
Вход
</div>
<div
style="position:relative;left:100px;top:-20px;"><a
href="register.php">регистрация</a></div>
</div>
</div>
</form>';($error)
{'<div
style="position:relative; top:
20px;">';nl2br($ert);'</div>';
}'footer.php';
?>
Форма регистрации нового пользователя показана
на рисунке 7. Из-за простоты системы и ограничений пакета Denwer,
на котором представляется система, подтверждение по e-mail
не реализовано.
Рис. 7
Код регистрации приведен далее.
<?php_start();('mysql.php');
/*
** Функция для генерации соли, используемоей в
хешировании пароля
** возращает 3 случайных символа
*/GenerateSalt($n=3)
{
$key = '';
$pattern =
'1234567890abcdefghijklmnopqrstuvwxyz.,*_-=+';
$counter = strlen($pattern)-1;($i=0;
$i<$n; $i++)
{
$key .= $pattern{rand(0,$counter)};
}$key;
}'header.php';(empty($_POST))
{
?>
<script
language="JavaScript" type="text/javascript"
src="jquery.js"></script>
<script
language="JavaScript" type="text/javascript"
src="jquery.corner.js"></script>
<script language="JavaScript"
type="text/javascript">
<!--
$("document").ready(function()
{
$("#reg").corner("round");
});
//-->
</script>
<div style="margin:100px
auto;width:300px;background:#ccc;padding-left:15px;padding-bottom:10px;"
id="reg">
<h3>Регистрация</h3>
<form
action="register.php" method="post">
<table>
<tr>
<td>Логин:</td>
<td><input
type="text" name="login" /></td>
</tr>
<tr>
<td>Пароль:</td>
<td><input
type="password" name="password" /></td>
</tr>
<tr>
<td>Повторите пароль:</td>
<td><input type="password"
name="repassword" /></td>
</tr>
<tr>
<td colspan="2"
align="center"><input type="submit" value="Зарегистрироваться"
/></td>
</tr>
</table>
</form>
</div>
<?php
}
{
// обрабатывае
пришедшие
данные
функцией
mysql_real_escape_string перед вставкой
в
таблицу
БД
$error = false;
$errort = '';
$login = (isset($_POST['login'])) ?
mysql_real_escape_string($_POST['login']) : '';
$password =
(isset($_POST['password'])) ? mysql_real_escape_string($_POST['password']) :
'';
$repassword =
(isset($_POST['repassword'])) ? mysql_real_escape_string($_POST['repassword'])
: '';( !empty( $login ) and !preg_match( "#^[A-Za-z][-
_0-9A-Za-z]+$#i", $login ) )
{
$errort = $errort.'Поле "Логин"
содержит недопустимые символы<br />';
$error = true;
}( !empty( $password ) and !preg_match(
"#^[-_!@0-9A-Za-z]+$#i", $password ) )
{
$errort = $errort.'Поле "Пароль"
содержит недопустимые символы<br />';
$error = true;
}($password !== $repassword)
{
$error = true;
$errort.='Введенные пароли не совпадают<br
/>';
}
// проверяем на наличие ошибок (например, длина
логина и пароля)
if (strlen($login) < 2)
{
$error = true;
$errort .= 'Длина логина должна быть не менее 2х
символов.<br />';
}(strlen($password) < 6)
{
$error = true;
$errort .= 'Длина пароля должна быть не менее 6
символов.<br />';
}
// проверяем, если юзер в таблице с таким же
логином
$query = "SELECT
`id``users``login`='{$login}'1";
$sql = mysql_query($query) or
die(mysql_error());(mysql_num_rows($sql)==1)
{
$error = true;
$errort .= 'Пользователь с таким логином уже
существует в базе данных, введите другой.<br />';
}
// если ошибок нет, то добавляем юзаре в
таблицу(!$error)
{
// генерируем соль и пароль
$salt = GenerateSalt();
$hashed_password =
md5(md5($password) . $salt);
$query = "INSERT`users`
`login`='{$login}',
`password`='{$hashed_password}',
`salt`='{$salt}'";
$sql = mysql_query($query) or
die(mysql_error());
$i = mysql_insert_id();
$query = "insert into
user_details values($i, '','',0,'','','',0)";
//echo $query;
$sql = mysql_query($query);'<div>Поздравляем,
Вы
успешно
зарегистрированы!<br
/><a href="login.php">Авторизоваться</a></div>';
}
{'<div>Возникли
следующие
ошибки<br
/>' . nl2br($errort).'<br /><a href="register.php">попробуйте
еще
раз</a></div>';
}
}'footer.php';
?>
После успешной авторизации пользователь попадает
в свой личный кабинет. На рисунке 8 показан личный кабинет администратора, а на
рисунке 9 - обычного пользователя системы.
Рис. 9
Рис. 10
Код личного кабинета выглядит так:
<?_start();
$guest =
false;(!isset($_SESSION['user_id']))
{
// header('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
$guest = true;
//die('Доступ
закрыт,
даём
ссылку
на
авторизацию.
- <a href="login.php">Авторизоваться</a>');
}'mysql.php';
$id = (int)$_GET['id'];(empty($id))
{(!$guest) $id =
$_SESSION['user_id']; else $id = 0;
}
$same_user = false;($id ==
$_SESSION['user_id']) $same_user = true;
//echo 'user: '.$same_user.'
id'.$id.' sessid '.$_SESSION['user_id'];
$no_user = false;
//echo "select nick, fio,
birth, hobbie, job, icq, filename from `user_details`, `avatars` where id={$id}
and avatars.avatar_id=user_details.avatar_id";
$q = "select login from users
where id = {$id}";
$r =
mysql_query($q);(mysql_num_rows($r) == 0) $no_user = true;
$r = mysql_query("select nick,
fio, birth, hobbie, job, icq, avatar_id from `user_details` where
id={$id}");(mysql_num_rows($r) > 0) $ud = mysql_fetch_array($r,
MYSQL_ASSOC); else
{
$ud = array('nick'=>'',
'fio'=>'',
'birth'=>0,
'hobbie'=>0,
'job'=>'',
'icq'=>'',
'avatar_id'=>0);
}(!$no_user)
{($ud as $k => $v)
{
//echo
$ud[$k-1].'+'.empty($ud[$k-1]);(empty($v)) $ud[$k] = 'Нет
данных';
}
$ud['avatar_id'] = (int)$ud['avatar_id'];
// хитрый
план(isset($ud['avatar_id']))
{
$q = "select filename from
avatars where avatar_id = {$ud['avatar_id']}";
//echo $q;
$r =
mysql_query($q);(mysql_num_rows($r) > 0)
$ava = mysql_fetch_row($r);$ava[0] =
'avatars/anon.jpg'; }
}'head.php';'menu.php';
?>
<div id="rightCol">
<? if (!$no_user) { ?>
<h3><?if ($ud['fio']!='Нет
данных')
echo $ud['fio']; else echo 'Пользователь
'.$id ?></h3>
<table>
<tbody>
<tr>
<td colspan="2">
Общая информация
</td>
</tr>
<tr>
<td>Никнейм</td>
<td><?echo
$ud['nick'];?></td>
</tr>
<tr>
<td>Дата
рождения</td>
<td><?if ($ud['birth']!='Нет
данных')
echo date('d.m.Y', $ud['birth']);else echo 'не
указана';?></td>
<tr>
<td colspan="2">
Контактная информация
</td>
</tr>
<tr>
<td>
<td><?echo
$ud['icq'];?></td>
</tr>
<tr>
<td colspan="2">
Персональная информация
</td>
</tr>
<tr>
<td>
<td
width="300"><? echo $ud['job']; ?></td>
</tr>
<tr>
<td>Интересы</td>
<td
width="300"><? echo $ud['hobbie']; ?></td>
</tr>
</tbody>
</table>
</div>
<? } else {
echo '<div>
}?>
<div
id="bottom"></div>
</div>
<?'foot.php';
?>
Пользователь имеет возможность работы с личными
сообщениями. Просматривая страницы пользователей, он может написать им. Следует
отметить, что предусмотрена фильтрация пользовательского ввода. Форма ввода
нового сообщения показана на рисунке 11.
Рис. 11
Код отправки личного сообщения приведен ниже:
<?_start();(!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на
авторизацию. - <a href="login.php">Авторизоваться</a>');
}'../mysql.php';
$tid = (int)$_POST['tid'];
$title = trim($_POST['title']);
$message = trim($_POST['message']);
//echo 'Message: '.$message.'<br
/>';
//echo 'AFTER
mysql_real_escape_string: '.$message.'<br />';
$message = strip_tags($message,
'&');
//echo 'NOW: '.$message.'<br
/>';
$title = strip_tags($title,
'&');
$id = $_SESSION['user_id'];
$same_user = true;
$no_user =
false;'../head.php';'../menu.php';
$error = false;
$ert = '';($id == $tid)
{
$error = true;
$ert .= 'Вы не можете послать сообщение самому
себе';
}(empty($message))
{
$error = true;
$ert .= 'Не введен текст сообщения';
}(empty($tid))
{
$error = true;
$ert .= 'Не заполнено поле получателя';
}
{
$q = "select login from users
where id={$tid}";
$r =
mysql_query($q);(mysql_num_rows($r) == 0)
{
$error = true;
$ert .= 'Пользователя с введенным Вами id не
существует';
}
}
?>
<div id="rightCol">
<?(!$error)
{
// отсылка
сообщения
$query = "INSERT INTO pm
(,
{$id},
{$tid},
'".mysql_real_escape_string(
$title )."',
'".mysql_real_escape_string(
$message )."',(),
)";$query;
$r = mysql_query($query);
echo '<div>
}{'<div>
}
?>
</div>
<div
id="bottom"></div>
</div>
<?'../foot.php';
?>
Пользователь имеет возможность просмотра
отправленных и полученных сообщений. Для примера приведен фрагмент формы
просмотра входящих сообщений на рисунке 12. С помощью AJAX
данные подгружаются без перезагрузки страницы.
Рис. 12
Код просмотра входящих сообщений практически
полностью идентичен просмотру входящих. Просмотр списка
в
целом
выглядит
так:
<?_start();(!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на
авторизацию. - <a href="login.php">Авторизоваться</a>');
}'../mysql.php';
$id = $_SESSION['user_id'];
$same_user = true;
$no_user =
false;'../head.php';'../menu.php';
?>
<div id="rightCol">
<h3>Входящие</h3>
<script
language="JavaScript" type="text/javascript">
<!--see_mail(id)
{
$("#showMail").load("message.php",
{'mess_id':id});
}
//-->
</script>
<table>
<tr>Получатель</td><td>Сообщение</td><td>Отправлено</td><td>Действия</td></tr>
<?my_str_word($text, $counttext =
10, $sep = ' ') {
$words = split($sep, $text);(
count($words) > $counttext )
$text = join($sep,
array_slice($words, 0, $counttext)).'...';$text;
}
$query = "SELECT a.id_mess,
a.title, a.message, DATE_FORMAT(a.dt,'%d.%m.%Y %H:%i:%s'), b.nick, a.fidpm a
INNER JOIN user_details ba.fid=b.ida.tid={$id}rid<>{$id}BY dt DESC";
//echo $query;
$res =
mysql_query($query);(mysql_num_rows($res) == 0)
{"<tr>
<td colspan=\"4\">В этой папке
нет сообщений</td>
</tr>";
}{($mess = mysql_fetch_row($res))
{
$cuttext =
my_str_word($mess[2]);"<tr><td>
<a
href=\"/soc/profile.php?id=$mess[5]\">$mess[4]</a>
</td>
<td>
<div>
<div>
</td>
<td>
$mess[3]
</td>
<td>
<div><a
href=\"write.php?tid=$mess[5]&message=$mess[2]&title=$mess[1]\">Ответить</a></div>
<div><a
href=\"del.php?id=$mess[0]\">Удалить</a></div>";"</tr>";
}
}
?>
</table>
<div
id="showMail"></div>
</div>
<div
id="bottom"></div>
</div>
<?'../foot.php';
?>
Просмотр текущего сообщения делается так:
<?_start();(!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на
авторизацию. - <a href="login.php">Авторизоваться</a>');
}'../mysql.php';
$id = $_SESSION['user_id'];
$mess_id = (int)$_POST['mess_id'];
$query = "SELECT a.tid, a.fid,
a.title, a.message, DATE_FORMAT(a.dt,'%d.%m.%Y %H:%i:%s') as dt,.fio AS
to_user_name, c.fio AS from_user_namepm a INNER JOIN user_details
ba.tid=b.idJOIN user_details
ca.fid=c.idid_mess=".$mess_id."(a.tid=".$id." OR
a.fid=".$id.")a.rid<>".$id;
//echo $query;
$res = mysql_query($query);
$m =
mysql_fetch_array($res);'<table border="0"
cellspacing="0"
cellpadding="3">';'<tr>';'<td><b>Отправитель:</b></td><td><a
href="/soc/profile.php?id='.$m['fid'].'">'.$m['from_user_name'].'</a></td>';'</tr>';'<tr>';'<td><b>Получатель:</b></td><td><a
href="/soc/profile.php?id='.$m['tid'].'">'.$m['to_user_name'].'</a></td>';'</tr>';'<tr>';'<td>Дата:</td><td>'.$m['dt'].'</a></td>';'</tr>';'<tr>';'<td>Тема:</td><td>'.$m['title'].'</a></td>';'</tr>';'<tr>';'<td
valign="top"><b>Сообщение:</b></td><td>'.nl2br(wordwrap($m['message'],
75, "\n", 1)).'</td>';
echo '</tr>';
?>
Теперь рассмотрим возможность работы с
закладками. Пользователь может просматривать список своих закладок. Удаление
реализовано при помощи AJAX,
при изменении он попадает в ту же форму, что и при добавлении. На рисунке 13
приведена форма списка закладок, а на рисунке 14 - форма добавления новой
закладки.
Рис. 13
Рис. 14
Код просмотра списка закладок представлен ниже:
<?_start();
$guest =
false;(!isset($_SESSION['user_id']))
{
$guest = true;
}'mysql.php';'bm_fns.php';
$id = (int)$_POST['id'];
//echo $id;
$page =
(int)$_POST['page'];_bms_links($id, $page, 3);
?>
<div id="cont">
<script
language="JavaScript" type="text/javascript">
<!--
$("document").ready(function()
{
$(".acts>a").click(function()
{($(this).attr('t') == '1')
return;(!confirm("Удалить
ссылку?"))
return;i = $(this).parent().parent().attr('id');
$.get("del.php", {'linkid':
i }, function(data)
{
//alert(data);s = "#"+i;
//$("#bm").children().find(s).remove();
$.post("list.php",{id:<?
echo $id; ?>, page: <? echo $page; ?>}, function(data){
$("#tt").html(data);
//alert(data);
});
});
//alert($(this).parent().parent().attr('id'));
});
});
//-->
</script>
<table>
<?php($page<=0) $page=1;
$r = get_user_bms($id, $page);($r) {
$n = mysql_num_rows($r);
if ($n<1) echo 'Нет закладок';
else {
$same_user = false;($id ==
$_SESSION['user_id']) $same_user = true;($m = mysql_fetch_array($r, MYSQL_NUM))
{"<tr id=\"$m[4]\">";"<td><a
href=\"$m[1]\">$m[0]</a><br />";(!empty($m[2]))
echo nl2br(wordwrap($m[2], 40, "\n", 1))."<br
/>";"<b>Категория:</b>
$m[3]<br />Адрес:
<a
href=\"$m[1]\">".htmlspecialchars($m[1])."</a></td>";($same_user)
{"<td>Изменить</a><br
/><a href=\"#\" t=\"0\">Удалить</a></td>";
}{(!$guest) echo "<td>Добавить
к
себе</a></td>";
}'</tr>';
}
}
}
?>
</table>
</div>
Основные функции из подключаемого файла
приведены далее:
<?php($bm_count);
$bm_count = 5;get_bms_links($userid,
&$page, $links)
{$bm_count;
$q = "SELECT COUNT(*) FROM
bookmark WHERE bookmark.user_id = $userid";
//echo $q;
$r = mysql_query($q);
$res = mysql_fetch_row($r);($pages);
//echo $res[0];
$pages =
ceil($res[0]/$bm_count);($page < 1) $page = 1;($page > $pages) $page =
$pages;
//echo $page;
// links - число ссылок рядом
if ($page > $links)
$starttext = "<a
href=\"$PHP_SELF?page=1&id=$userid\">«</a>";
$starttext = '';($page <
($pages-$links+1))
$endtext = "<a
href=\"$PHP_SELF?page=$pages&id=$userid\">»</a>";
$endtext = '';
$nearpages = '';($i =
$page-($links-1); $i <= $page+($links-1); $i++)
{( ($i>0) &&
($i<=$pages) )
{
$nearpages.="<a
href=\"$PHP_SELF?page=$i&id=$userid\"";($i == $page)
$nearpages.='style="font-weight:bold;"';
$nearpages.=">$i</a> ";
}
}'<div
style="text-align:right;">'.$starttext.' '.$nearpages.'
'.$endtext.'</div>';
}get_user_bms($userid, $page)
{$bm_count;
$l1 = ($page-1)*$bm_count;
$q = "SELECT bm.title, bm.url,
bm.descr, cat.name, bm.link_id from bookmark bm, categories cat WHERE.user_id =
$userid AND cat.catid = bm.catid ORDER BY bm.url LIMIT $l1, $bm_count";
$r = mysql_query($q);
//echo $q;(!$r) return false;$r;
}delete_bm($userid, $linkid)
{
//echo $userid;
//echo "delete from bookmark
where user_id={$userid} and url='$url'";
$linkid = (int)$linkid;
$q = "select url from bookmark
where user_id=$userid and link_id=$linkid";
$res = mysql_query($q);
$u =
mysql_fetch_row($res);(!mysql_query("delete from bookmark where
user_id=$userid and link_id=$linkid"))false;$u[0];
}upd_bm($userid, $url, $title,
$description, $cat_id, $linkid)
{
$title =
mysql_real_escape_string($title);
$title = htmlspecialchars($title);
$description =
mysql_real_escape_string($description);
$description =
htmlspecialchars($description);($url{(strlen($url)-1)} == '/') $url =
substr($url,0,(strlen($url)-1));
$url = mysql_escape_string($url);
$cat_id = (int)$cat_id;
$linkid = (int)$linkid;
$q = "UPDATE bookmark SET
title='$title', url='$url', descr='$description', catid=$cat_id WHERE ";
$q = $q."user_id=$userid AND
link_id=$linkid";
//echo
$q;(!mysql_query($q))false;true;
}add_bm($userid, $newurl, $title,
$description, $cat_id)
{
//есть
ли
такая
закладка
$title =
mysql_real_escape_string($title);
$description =
mysql_real_escape_string($description);
$description =
htmlspecialchars($description);
$title = htmlspecialchars($title);
//echo $newurl; // - тут
все
корректно($newurl{strlen($newurl)}
== '/') $newurl = substr($newurl,0,strlen($url)-2);
$newurl =
mysql_real_escape_string($newurl);
$cat_id = (int)$cat_id;
$q = "select * from bookmark
where user_id=$userid and url='$newurl'";
//echo $q;
$r =
mysql_query($q);(mysql_num_rows($r) > 0) throw new Exception('Такая
закладка
уже
есть!');
$q = "insert into bookmark
values(NULL, $userid, '$title', '$newurl', '$description',
$cat_id)";(!mysql_query($q)) throw new Exception('Не
удается
добавить
закладку!');true;
}recommend_urls($userid, $popularity
= 1)
{
$query="SELECT SUBSTRING_INDEX(
a.url, '/', 3 ) , count( a.url )bookmark aa.user_id(DISTINCT (.user_id
)bookmark b1, bookmark b2b1.user_id
= $useridb1.user_id != b2.user_idSUBSTRING_INDEX( b1.url, '/', 3 ) =
SUBSTRING_INDEX( b2.url, '/', 3 )
)SUBSTRING_INDEX( a.url, '/', 10 )
NOT(SUBSTRING_INDEX( url, '/', 10 )bookmarkuser_id = $userid
)BY SUBSTRING_INDEX( url, '/', 3 )
LIMIT 5";// having count(SUBSTRING_INDEX(url, '/', 3 ))>1";
//echo nl2br($query).'<br
/><hr>';
$r = mysql_query($query);(!$r)
throw new Exception('Не удается найти закладки
для рекомендации.');
if (mysql_num_rows($r)==0)
throw new Exception('Не удается найти закладки
для рекомендации.');$r;
}
?>
Пользователь может воспользоваться сервисом
рекомендации ссылок, его вид приведен на рисунке 15.
Рис. 15
Подгрузка рекомендаций выполнена при помощи AJAX.
Список рекомендаций реализован следующим образом:
<?_start();(!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
}'mysql.php';
$id = $_SESSION['user_id'];
$same_user = true;
$no_user =
false;'../head.php';'../menu.php';
?>
<div id="rightCol">
<script
type="text/javascript" src="jquery.js"></script>
<script>
<!--oldurl = '';see_details(url)
{
//alert(url)(oldurl == url)
{
$("#d").slideUp("fast");=
'';;
}$("#d").hide();
$.get("details.php",
{'url' : url}, function(data) {
//alert(data)
$("#d").html(data);= url;
})
$("#d").animate({: 50,
opacity: 'show'
}, 500);
}
//-->
</script>
<?_once('bm_fns.php');
{
$r = recommend_urls($id,1);
echo '<i>Рекомендовано:</i> '
?>
<table border="1"
bordercolor="#abcabc" cellspacing="0" cellpadding="5">
<tr><th>URL</th><th>Количество
рекомендаций</th></tr>
<?
$i = 0;($m=mysql_fetch_array($r,
MYSQL_NUM))
{'<tr>';"<td><a
href=\"javascript:void(0)\"
onClick=\"see_details('$m[0]')\">$m[0]</a></td><td>$m[1]</td>";'</tr>';
}
}(Exception $e)
{$e->getMessage();
}
?>
</table>
<div id="d"
style="border:1px #ccc dashed;display:none;"></div>
</div>
<div
id="bottom"></div>
</div>
<?'../foot.php';
?>
Вывод данных по рекомендациям сделан так:
<?_start();(!isset($_SESSION['user_id']))
{('Location: /soc/index.php?page='.$_SERVER["PHP_SELF"]);
}_once('mysql.php');('Content-type:
text/html; charset=utf-8');
$id = $_SESSION['user_id'];
$q = "SELECT substring_index(
url, '/', 10 ), count(user_id), b.fio, b.idbookmark INNER JOIN user_details b
ON b.id=bookmark.user_iduser_id !=$idsubstring_index( url, '/', 3 ) =
substring_index( '$url', '/', 3 )url NOT IN (select url from bookmark where
user_id=$id) group by substring_index( url, '/', 10 )";
//echo $q;
$res =
mysql_query($q);'<table>';($m = mysql_fetch_array($res))
{'<tr>';
$s = 'рекомендаци';($m[1]
== 1) $s.='я';if ($m[1] > 1
&& $m[1] < 10) $s.='и';
else $s.='й';"<td><a
href=\"$m[0]\">$m[0]</a></td><td>$m[1]
$s</td><td>";
if (empty($m[2])) $m[2] = 'Пользователь '.$m[3];
if ($m[1] > 1) $s = ' ';
else $s = '<a
href="/soc/profile.php?id='.$m[3].'">'.$m[2].'</a>';$s.'</td>';'</tr>';
}'</table>';
?>
Пользователь может сменить данные своего
профиля. Для этого ему нужно зайти в «Мои настройки-Анкета». Вид формы
заполнения анкеты представлен на рисунке 16. В момент заполнения открыт
календарь, который можно скрыть и ввести данные в текстовое поле обычным
способом.
Рис. 16
Вспомогательные функции для выбора информации
профиля пользователя из БД и записи туда приведены ниже:
function upd_user($id, $nick, $fio,
$birth, $hobbie, $job, $icq)
{
$id = (int)$id;
$nick =
mysql_escape_string(substr(trim($nick),0,19));
$fio =
mysql_escape_string(substr(trim($fio),0,79));
$hobbie =
mysql_escape_string($hobbie);
$job=mysql_escape_string(substr(trim($job),0,49));
$icq = str_replace('-','',$icq);
$icq=mysql_escape_string(substr(trim($icq),0,8));
$birth = explode('.',$birth);
$birth =
mktime(0,0,0,(int)$birth[1], (int)$birth[0], (int)$birth[2]);
$q = "UPDATE user_details SET
nick='$nick', fio='$fio',=$birth, hobbie='$hobbie', job='$job',
icq='$icq'id={$id}";
//echo $q;(mysql_query($q)) return
true; else return false;
}get_user_details($id)
{
$ud = array();
$q = "select nick, fio, birth,
hobbie, job, icq from user_details where id={$id}";
$r =
mysql_query($q);(mysql_num_rows($r) > 0)
{
$ud = mysql_fetch_array($r);
$ud['birth'] = date('d.m.Y',
$ud['birth']);
return $ud;
}
{0;
}
}
Пользователь может также сменить пароль. Новый
пароль будет зашифрован и при необходимости записан в cookie-набор
пользователя. Вид формы смены пароля приведен на рисунке 17.
Рис. 17
Исходный код сценария выглядит следующим
образом:
<?_start();(!isset($_SESSION['user_id']))
{('Location: index.php?page='.$_SERVER['PHP_SELF']);
}'../mysql.php';
$id = $_SESSION['user_id'];
$query = "SELECT `password`,
`salt``users``id`='{$id}'1";
$sql = mysql_query($query) or die('Невозможно
найти
этот
ID');(!empty($_POST))
{(mysql_num_rows($sql) > 0)
{
$row = mysql_fetch_assoc($sql);
// берем
соль
$salt = $row['salt'];
$p = $row['password'];
$error = false;
$errort = '';
$oldpassword =
(isset($_POST['oldpassword'])) ?
mysql_real_escape_string($_POST['oldpassword']) : '';
$newpass =
(isset($_POST['password'])) ? mysql_real_escape_string($_POST['password']) :
'';( !empty( $newpass) and !preg_match( "#^[-_!0-9A-Za-z]+$#i",
$newpass ) )
{
$errort = $errort.'Поле "Пароль"
содержит недопустимые символы<br />';
$error = true;
}(strlen($newpass) < 6)
{
$error = true;
$errort .= 'Длина нового пароля менее шести
символов';
}
$oldpassword = md5(md5($oldpassword)
. $salt);($p !== $oldpassword)
{
$error = true;
$errort
.= 'Введенный вами старый пароль неверен';
}(!$error)
{
$newpass = md5(md5($newpass) .
$salt);
$q = "update users set
`password`='{$newpass}' where `id`={$id}";
$r = mysql_query($q);
$time = 86400*7*2;('password',
$newpass, time()+$time, "/");
//echo $q;'<div>Пароль
успешно
изменен
на</div>';
}
{'<div>Возникли
следующие
ошибки<br
/>' . nl2br($errort).'</div>';
}
}
}
$no_user = false;
$same_user=true;
$id =
$_SESSION['user_id'];'../head.php';'../menu.php';
?>
<div id="rightCol">
<form
action="reset.php" method="post">
<table>
<tr>
<td>Старый пароль:</td>
<td><input
type="password" name="oldpassword" /></td>
</tr>
<tr>
<td>Новый пароль:</td>
<td><input
type="password" name="password" /></td>
</tr>
<tr>
<td></td>
<td><input
type="submit" value="Сменить
пароль"
/></td>
</tr>
</table>
</form>
</div>
<div
id="bottom"></div>
</div>
<?'../foot.php';
?>
При желании пользователь может сменить свой
аватар. При этом он будет уменьшен до максимально возможных размеров
пропорционально. Форма загрузки аватара приведена на рисунке 18.
Рис. 18
Код, сохраняющий информацию о новом аватаре в БД
и выполняющий всю работу по проверке загружаемого файла на корректность и его
уменьшению приведен ниже:
<?php_start();(!isset($_SESSION['user_id']))
{('Location: /soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на
авторизацию. - <a href="login.php">Авторизоваться</a>');
}
$id =
$_SESSION['user_id'];GenerateName($n=10)
{
$key = '';
$pattern =
'1234567890abcdefghijklmnopqrstuvwxyz';
$counter = strlen($pattern)-1;($i=0;
$i<$n; $i++)
{
$key .= $pattern{rand(0,$counter)};
}$key;
}resize_image($max_w, $max_h, $img,
$fname)
{
$size = GetImageSize($img);
$w = $size[0];
$h = $size[1];
$x_ratio = $max_w / $w;
$y_ratio = $max_h / $h;( ($w <=
$max_w) && ($h <= $max_h) )
{
$dstw = $w;
$dsth = $h;
}if ( ($x_ratio * $h) < $max_h)
{
$dstw = $max_w;
$dsth = ceil($x_ratio * $h);
}
{
$dsth = $max_h;
$dstw = ceil($y_ratio * $w);
}
$src = ImageCreateFromJpeg($img);
$dst = imagecreatetruecolor($dstw,
$dsth);($dst, $src, 0, 0, 0, 0, $dstw, $dsth, $w, $h);
//$fname = substr($img, 0,
strpos($img, '.')).'-thumb.jpg';
/*print nl2br("$img:: $w,: $h,
Сжатие по
x: $x_ratio,
Сжатие по у: $y_ratio
Новое имя: $fname,
Новая ширина: $dstw,
Новая высота: $dsth
"); */($dst, $fname, 100);
}'../mysql.php';
$error = false;
$ert =
'';($_FILES['userfile']['error'] > 0)
{
$error =
true;($_FILES['userfile']['error'])
{1: $ert.='размер
файла
больше
upload_max_filesize\n'; break;2: $ert.='размер
файла
больше
max_file_size\n'; break;
case 3: $ert.='загружена только часть файла\n';
break;4: $ert.='файл не загружен\n'; break;
}
}
// Проверка, имеет ли файл правильный MIME-тип
$blacklist = array(".php",
".phtml", ".php3", ".php4",
"pl");($blacklist as $item) {(preg_match("/$item\$/i", $_FILES['userfile']['name']))
{
$ert.="Вы попытались загрузить вредоносный
файл.\n";
$error = true;
}
}
$imageinfo =
getimagesize($_FILES['userfile']['tmp_name']);($imageinfo['mime'] !=
'image/jpeg') {
$ert.="Можно загружать только изображения
формата JPEG\n";
$error = true;
}
// помещаем файл туда, куда нужно
$upfile =
'uploads/'.$_FILES['userfile']['name'];($_FILES['userfile']['tmp_name'])
{
$z =
$_FILES['userfile']['tmp_name'];(!move_uploaded_file("$z", $upfile))
{
$ert.='Проблема: невозможно переместить файл в
каталог назначения\n';
$error = true;
}(!$error)
{
$fn =
'../avatars/'.GenerateName().'.jpg';_image(240, 320, $upfile, $fn);
$fn = substr($fn,3);
$q = "insert into avatars
values(NULL, '$fn')";_query($q);
$avid = mysql_insert_id();
$q = "update user_details set
avatar_id=$avid where id={$id}";_query($q);($upfile);
}
}
{
$ert.='Проблема: возможна атака через загрузку
файла.\n';
$error = true;
}'../head.php';
$no_user = false;
$same_user =
true;'../menu.php';'<div id="rightCol">';($error)
{nl2br('<div>Возникли
следующие
проблемы:<br>'.$ert.'</div>');
}
{'<div>Файл
успешно
загружен</div>';
}'</div>';'<div
id="bottom"></div></div>';
include '../foot.php';
?>
Если пользователь желает найти какую-либо
информацию, он может воспользоваться поиском. Форма поиска приведена на рисунке
19.
Рис. 19
Как видно из рисунка, можно разделять ключевые
слова точкой с запятой, писать лишь обрывки слов, однако поиск будет
произведен. Скрипт, выполняющий логику поиска, приведен ниже:
<?
include_once('mysql.php');
session_start();
$guest =
false;(!isset($_SESSION['user_id']))
{
// header('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
$guest = true;
//die('Доступ
закрыт,
даём
ссылку
на
авторизацию.
- <a href="login.php">Авторизоваться</a>');
}(!$guest) $id =
$_SESSION['user_id']; else $id = 0;
//echo
$_GET['type'];(isset($_GET['type']))
{($_GET['type'] == 'cat')
{
$cid = (int)$_GET['cid'];
$q = "SELECT u.id, b.title,
b.url, b.descr, c.namebookmark b, users u, categories cc.catid =$cidb.user_id
!= $idb.user_id=u.idc.catid = b.catid";
//echo $q;
}if ($_GET['type'] == 'kw')
{
$descr = $_GET['descr'];
$descr = trim($descr);
$descr =
mysql_escape_string($descr);
$descr_a = explode(';', $descr);
$title = $_GET['title'];
$title = trim($title);
$title =
mysql_escape_string($title);
$title_a = explode(';', $title);
//echo 'Title is empty?
'.empty($title).' '.$title.' ';
$q = "SELECT u.id, b.title,
b.url, b.descr, c.namebookmark b, users u, categories c(";
$b = false;(!empty($descr))
{($i=0;$i<count($descr_a);$i++)
{
$q = $q." b.descr LIKE
'%$descr_a[$i]%' OR";
}
$b = true;
$q = substr($q, 0,
strlen($q)-3).")";
}(!empty($title))
{($b) $q = $q.' AND
(';($i=0;$i<count($title_a);$i++)
{
$q = $q." b.title LIKE
'%$title_a[$i]%' OR";
}
$b = true;
$q = substr($q, 0,
strlen($q)-3).")";
}(!$b) {
$p = strpos($q, '(');$p;
$q = substr($q, 0, $p);
}($b) $q.=' AND ';
$q.="b.user_id
!=$idb.user_id=u.idc.catid = b.catid";
//echo $q;
}
$r =mysql_query($q);
}'<table
border=1>';'<tr><th>Пользователь</th><th>Название</th><th>URL-адрес</th><th>Описание</th><th>Категория</th></tr>';($m=mysql_fetch_array($r,
MYSQL_NUM))
{'<tr>';
$q = "select nick from
user_details where id={$m[0]}";
$rr = mysql_query($q);
$u=mysql_result($rr,0,0);
if (empty($u)) $u = 'Пользователь '.$m[0];
//echo $u;"<td><a
href=\"/soc/profile.php?id=$m[0]\">$u</a></td><td>$m[1]</td><td><a
href=\"$m[2]\">$m[2]</a></td><td>$m[3]</td><td>$m[4]</td>";'</tr>';
}'</table>';
?>
Если пользователь является администратором, то
ему доступны дополнительные функции. Так, администратор может редактировать
шаблоны сайта. Нужно обратить внимание, что пользователь без прав на доступ к
администрированию не сможет туда зайти. Редактирование шаблонов показано на
рисунке 20.
Рис. 20
Код редактирования шаблонов предельно прост и
использует возможности визуального JavaScript-редактора
кода Edit
Area.
Администратор может также работать с
пользователями: удалять их, блокировать, разблокировать, редактировать их
анкетные данные. Работа с пользователями реализована посредством AJAX.Содержимое
всех небольших вспомогательных файлов приведено ниже.
Блокировка:
<?_start();(!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на
авторизацию. - <a href="login.php">Авторизоваться</a>');
}
$id = (int)$_POST['id'];($id ==
$_SESSION['user_id']) {
echo 'Себя нельзя банить';;
}'../mysql.php';
$q = "update users set
status=status+20 where id={$id}";(mysql_query($q)) echo 'Успешно
забанен';
else echo 'Невозможно забанить';
?>
Разблокировка:
<?_start();(!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на авторизацию.
- <a href="login.php">Авторизоваться</a>');
}
$id = (int)$_POST['id'];($id ==
$_SESSION['user_id']) {
echo 'Себя нельзя банить';;
}'../mysql.php';
$q = "update users set
status=status-20 where id={$id}";(mysql_query($q)) echo 'Успешно
разбанен';
else echo 'Невозможно разбанить';
?>
Редактирование анкеты:
<?_start();(!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на
авторизацию. - <a href="login.php">Авторизоваться</a>');
}
$id =
(int)$_POST['id'];'../mysql.php';'../options/user_fns.php';
$ud = get_user_details($id);($ud !=
0)
{
?>
<script
language="JavaScript" type="text/javascript">
<!--get_mess()
{= $('form').serialize();
$("#mu").load('ch_p.php',
data);
}
//-->
</script>
<h3>Редактирование анкеты</h3>
<form name="an_f">
<input type="hidden"
name="id" value="<? echo $id; ?>">
<table>
<tbody>
<tr>
<td colspan="2">
Общая информация
</td>
</tr>
<tr>
<td>Никнейм</td>
<td><input
type="text" name="nick" value="<? echo $ud['nick'];
?>"></td>
</tr>
<tr>
<td>ФИО</td>
<td><input
type="text" name="fio" size="40"
value="<? echo $ud['fio']; ?>"></td>
</tr>
<tr>
<td>Дата
рождения</td>
<td><input
type="text" name="birth" value="<? echo
$ud['birth']; ?>"></td>
</tr>
<tr>
<td colspan="2">
Контактная информация
</td>
</tr>
<tr>
<td>
<td><input
type="text" name="icq" value="<? echo $ud['icq'];
?>"></td>
</tr>
<tr>
<td colspan="2">
Персональная информация
</td>
</tr>
<tr>
<td>
<td
width="300"><textarea rows="5" cols="30"
name="job"><? echo $ud['job'];
?></textarea></td>
</tr>
<tr>
<td>Интересы</td>
<td
width="300"><textarea rows="5" cols="30"
name="hobbie"><? echo $ud['hobbie'];
?></textarea></td>
</tr>
</tbody>
</table>
</form>
<?
}
?>
Удаление пользователя:
<?
session_start();
if (!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на
авторизацию. - <a href="login.php">Авторизоваться</a>');
}
$id = (int)$_POST['id'];($id ==
$_SESSION['user_id']) {
echo 'Себя нельзя удалить';;
}'../mysql.php';
$q = "delete from users where
id={$id}";
$q1 = "delete from bookmark
where user_id={$id}";
$q2 = "delete from user_details
where id={$id}";( mysql_query($q) && mysql_query($q2))
{_query($q1);'Удалено
успешно';
}
{'Невозможно удалить';
}
?>
Важнейшей функцией администратора является
просмотр логов, отфильтрованных специально для системы. Форма просмотра
изображена на рисунке 21. Как видно из рисунка, фильтруются различные запросы,
в том числе потенциально опасные.
Рис. 21
Код сценария представлен ниже:
<?_start();(!isset($_SESSION['user_id']))
{('Location:
/soc/index.php?page='.$_SERVER["PHP_SELF"]);
//die('Доступ закрыт, даём ссылку на
авторизацию. - <a href="login.php">Авторизоваться</a>');
}'../mysql.php';'../head.php';
if ($_SESSION['adm'] != 1)
{'<div>
echo '</div>';'../foot.php';;
}
$id = $_SESSION['user_id'];
$same_user = true;
$no_user = false;'../menu.php';
$pages = $_POST['pages'];(empty($pages))
$pages = 20;
//echo
$pages;replace_month($path){(eregi('jan',$path)){$path='1';}(eregi('feb',$path)){$path='2';}(eregi('mar',$path)){$path='3';}(eregi('apr',$path)){$path='4';}(eregi('may',$path)){$path='5';}(eregi('jun',$path)){$path='6';}(eregi('jul',$path)){$path='7';}(eregi('aug',$path)){$path='8';}(eregi('sep',$path)){$path='9';}(eregi('oct',$path)){$path='10';}(eregi('nov',$path)){$path='11';}{$path='12';}$path;
}
$filename =
'z:/usr/local/apache/logs/access.log';
$fd = $pages; // 1 строка
100 bytes - 20 строк
$fp =
filesize($filename)-$fd*100;($pages == 'all') $fp = 0;
$fh = fopen($filename, 'r');($fh,
$fp);
$arr = array();
$i = 0;
$a = 0;(!feof($fh))
{
$line = trim(fgets($fh,
1024));(!eregi('.jpg',$line) and !eregi('.gif',$line) and !eregi('.js',$line)
and !eregi('.css',$line))
{
//echo 'b';(strstr($line, '/soc'))
{
$arr[$i] = $line;
//echo 'a';
$i++;
}
}
}($fh);
?>
<div id="rightCol">
<form action='access.php'
method='post'>
<select
name="pages">
<?
$pp = array(20,50,100,200,500);($pp
as $p)
{"<option value=$p";($p
== $pages) echo " selected";">Последние
$p</option>";
}
?>
<option value="all"
<? if ($pages == 'all') echo 'selected'; ?>>Все</option> <input
type="submit" value="Просмотреть">
</form>
<br />
<table border="1">
<?($arr as $v)
{_match("/^(\S+)\s+(\S+)\s+(\S+)\s+\[(.*)\]\s+\"(.*)\"\s+(\S+)\s+(\S+)$/x",$v,$matches);
array_shift($matches); // так как 0 элемент
содержит всю строку
$ip = $matches[0];
$time = $matches[3];
$url = $matches[4];
$succes = $matches[5];
$bytes =
$matches[6];_match("@(..)/(...)/(....):(..):(..):(..)@",$time,$matches);_shift($matches);
$matches[1] =
replace_month($matches[1]);
$time =
mktime($matches[3],$matches[4],$matches[5],$matches[1],$matches[0],$matches[2]);(eregi("(\%27)|(
or )|( and )|( union )",$url)) { $hack[$h++] = array($ip, $time, $url,
$bytes); }_match("/\S+\s+(\S+)/",$url,$matches);
$url = $matches[1];
$url =
urlencode($url);($succes=='200') {
$success[$i++] = array (
$ip,$time,$url,$bytes );
}{
$failure[$x++] = array (
$ip,$time,$url,$bytes );
}
}
?>
<tr>
<td align="center"
colspan="4">Корректные
запросы</td>
</tr>
<?(!empty($success))
{
$success =
array_reverse($success);($success as $k=>$v)
{'<tr>';($v as $key=>$val)
{($key == 1) { $val = date('d.m.Y
H:i:s',(int)$val); }($key == 2) {
$val = urldecode($val);
$val = nl2br(wordwrap($val, 40,
"\n", 1));
}"<td>$val</td>";
}'</tr>';
}
}
{'<tr><td
colspan="4">Не обнаружены</td>';
}
?>
<tr>
<td align="center"
colspan="4">Некорректные
запросы</td>
</tr>
<?(!empty($failure))
{
$failure =
array_reverse($failure);($failure as $k=>$v)
{'<tr>';($v as $key=>$val)
{($key == 1) { $val = date('d.m.Y
H:i:s',(int)$val); }($key == 2) { $val = urldecode($val); $val =
nl2br(wordwrap($val, 40, "\n", 1)); }"<td>$val</td>";
}'</tr>';
}
}
{'<tr><td
colspan="4">Не обнаружены</td>';
}
?>
<tr>
<td align="center"
colspan="4">Подозрительные
запросы</td>
</tr>
<?(!empty($hack))
{
$hack = array_reverse($hack);($hack
as $k=>$v)
{'<tr>';($v as $key=>$val)
{($key == 1) { $val = date('d.m.Y
H:i:s',(int)$val); }($key == 2) { $val = urldecode($val); $val =
nl2br(wordwrap($val, 40, "\n",
1));}"<td>$val</td>";
}'</tr>';
}
}
{'<tr><td
colspan="4">Не обнаружены</td>';
}
?>
</table>
</div>
<div
id="bottom"></div>
</div>
<?'../foot.php';
?>
Нажав «Справка», пользователь может прочесть
справку по использованию системы, а по нажатию «О сайте» можно увидеть
следующую страницу, изображенную на рисунке 22.
Рис. 22
Инструкции по эксплуатации системы.
Инструкции пользователя
Перед началом работы пользователь обязан:
) осмотреть и привести в порядок рабочее
место;
) отрегулировать освещенность на рабочем
месте, убедиться в достаточности освещенности, отсутствии отражений на экране,
отсутствии встречного светового потока;
) проверить правильность подключения
оборудования в электросеть;
) убедиться в наличии защитного
заземления и подключения экранного проводника к корпусу процессора;
) протереть специальной салфеткой
поверхность экрана ;
) убедиться в отсутствии дискет в
дисководах персонального компьютера;
При включении компьютера пользователь обязан
соблюдать следующую последовательность включения оборудования:
) включить блок питания;
) включить периферийные устройства
(принтер, монитор, сканер и др.);
) включить системный блок.
Пользователь во время работы обязан:
) в течение всего рабочего дня содержать
в порядке и чистоте рабочее место;
) держать открытыми все вентиляционные
отверстия устройств;
) внешнее устройство "мышь"
применять только при наличии специального коврика;
) при необходимости прекращения работы на
некоторое время корректно завершать все активные задачи;
) выполнять санитарные нормы и соблюдать
режимы работы и отдыха;
) соблюдать правила эксплуатации
вычислительной техники в соответствии с инструкциями по эксплуатации;
) соблюдать расстояние от глаз до экрана
в пределах 60-80 см.
Пользователю во время работы запрещается:
) прикасаться к задней панели системного блока
при включенном питании;
) переключать разъемов интерфейсных кабелей периферийных
устройств при включенном питании;
) загромождать верхние панели устройств бумагами
и посторонними предметами;
) допускать захламленность рабочего места
бумагой в целях недопущения накапливания пыли;
) производить отключение питания во время выполнения
активной задачи;
) допускать попадание влаги на поверхность
системного блока, монитора, рабочую поверхность клавиатуры, дисководов,
принтеров и др.устройств;
) производить самостоятельно вскрытие и ремонт
оборудования;
По окончании работ оператор обязан соблюдать
следующую последовательность выключения вычислительной техники:
) произвести закрытие всех активных
задач;
) убедиться, что в дисководах нет дискет;
) выключить питание системного блока;
) выключить питание всех периферийных
устройств;
) отключить блок питания.
Для начала работы в системе необходимо зайти по
адресу http://localhost/soc/. При наличии запущенного и корректно настроенного
веб-сервера вы либо попадете на страницу авторизации, либо, если вы уже были
запомнены в системе, автоматически переместитесь в свой личный кабинет. В
случае попадания на страницу авторизации введите свой логин и пароль либо
нажмите ссылку «регистрация» для регистрации нового аккаунта в системе.
Поставив галочку «запомнить», вы две недели сможете не вводить свой логин и
пароль при заходе с текущего компьютера в систему.
При успешной авторизации вы попадете в личный
кабинет. Выбирайте пункты меню, при наличии подменю оно будет автоматически
развернуто. Для добавления новой закладки выберите пункт меню «Мои закладки». В
нем вы можете выбрать «Добавить закладку» либо просмотреть их список и при
необходимости удалить или обновить их. При добавлении закладки введите краткое
описание, наименование, URL-адрес,
выберите подходящую категорию из списка.
При просмотре списка ссылок они выводятся по
десяти на странице, поэтому вы можете пользоваться элементом управления
навигации по страницам списка. Возле каждой ссылки вы можете нажать «обновить»
либо «удалить», при обновлении вы должны будете ввести те же данные, что и при
добавлении, однако текущие данные уже будут находиться в полях ввода, поэтому
их можно просто отредактировать.
Если вам хочется узнать что-то новое, вы можете
воспользоваться сервисом рекомендации ссылок. Появится список из пяти доменов
(имена доменов будут ограничены их корневыми директориями), при нажатии на
которые во всплывающем окне появятся полные адреса, которые вы можете добавить
в свой список закладок.
Если вам нужно найти закладку в вашем списке,
нажмите «Мой поиск» и выберите категорию или введите ключевые слова через точку
с запятой. Для нахождения ссылок у других пользователей выберите пункт «Поиск»,
открывшаяся страница имеет идентичный интерфейс.
Для обмена сообщениями выберите пункт меню «Мои
сообщения». Вы можете написать сообщение, зная ID адресата. Введите данные в
форму, тему заполнять не обязательно. Для просмотра списка входящих и исходящих
сообщения и просмотра сообщений в них выберите в меню нужную папку и
пользуйтесь элементами управления в списке. Среди них есть «Ответить», позволяющий
быстро написать ответное сообщение и «Удалить». Для просмотра сообщения просто
щелкните по нему в списке.
Для смены личных настроек откройте меню «Мои
настройки». Вы можете загрузить личный аватар вместо стандартного - просто
выберите JPEG или GIF-файл и нажмите «Загрузить». Для смены пароля введите
старый пароль и новый. Для заполнения анкеты выберите «Моя анкета» и заполните
поля в ней, ни одно из них не является обязательным.
Инструкции по сопровождению
К установке и настройке системы допускаются лица,
прошедшие курс основ сетевого и системного администрирования, имеющие навыки
работы с веб-сервером и сервером БД, владеющие базовыми навыками
программирования в Интернет.
Установка системы производится следующим
образом:
устанавливается и настраивается веб-сервер с
поддержкой PHP 4.5+ . На
прилагаемом компакт-диске имеется пакет Denwer,
который решает первые две задачи;
устанавливается и настраивается сервер БД с СУБД
MySQL 5+. Она
устанавливается в составе пакета;
в конфигурационных файлах системы администратор
вводит и сохраняет настройки доступа к серверу БД;
посредством прилагаемого файла создается
структура таблиц БД soc, создается «главный администратор». Для этого в папку /usr/local/mysql5/data
переносится папка с БД;
распаковываются в папку веб-документов
веб-сервера файлы системы;
запускается веб-браузер и тестируется корректная
работа установленной системы.
Файлы, входящие в состав системы, перечислены в
таблице 12.
Таблица 12
Имя
файла
|
Тип
|
Размер,
Кб
|
Header.php
|
Шапка
страницы
|
1
|
Head.php
|
Шапка
для внутренних страниц
|
2
|
Footer.php
|
Низ
страницы
|
1
|
Foot.php
|
Низ
внутренних страниц
|
1
|
Mysql.php
|
Конфигурационный
файл для соединения с БД
|
1
|
About.php
|
«О
сайте»
|
1
|
Search.php
|
Форма
поиска
|
2
|
Search_processing.php
|
Логика
поиска
|
3
|
Index.php
|
Вспомогательная
страница
|
3
|
Menu.php
|
Меню
в личном кабинете
|
3
|
Profile.php
|
Личный
кабинет
|
4
|
Register.php
|
Скрипт
регистрации
|
4
|
Login.php
|
Скрипт
авторизации
|
4
|
Formbg.gif
|
Фон
формы
|
2
|
Jquery.corner.js
|
Библиотека
для создания закругленных углов
|
7
|
Jquery.js
|
Библиотека
jquery
|
54
|
I.png
|
Фотография
автора
|
84
|
/admin/banned.php,
/admin/unban.php
|
Бан
и разбан
|
1
|
Users.php
|
Управление
пользователями
|
2
|
Access.php
|
Просмотр
логов
|
5
|
Del_user.php
|
Удаление
пользователя
|
1
|
/bm/add.php, /bm/add_from.php
|
Добавление
закладок
|
3
кб и 1 кб
|
/bm/bm_fns.php
|
Функции
для закладок
|
5
|
/bm/index.php
|
Главная
страница
|
3
|
/bm/recs.php
|
Рекомендации
|
2
|
/bm/list.php
|
Список
ссылок
|
2
|
/options/avatar.php
|
Загрузка
аватара
|
6
|
/options/anketa.php
|
Заполнение
анкеты
|
4
|
/options/reset.php
|
Смена
пароля
|
3
|
/pm/inbox.php, /pm/outbox.php
|
Входящие и
исходящие
|
3
|
/pm/send_message.php
|
Отправка
сообщения
|
3
|
/pm/write.php
|
Форма
отправки
|
2
|
/pm/message.php
|
Просмотр
сообщения
|
2
|
Администрирование системы
В число функций управления системой входят:
функции управления и создания предоставляемых
пользователю ресурсов из файлов данных и базы данных;
функции административного управления системой:
управление работой сервера БД, веб-сервера, интерпретатора PHP, установку МСЭ,
IDS;
функции поддержки работы серверов, интерпретатора,
вспомогательных библиотек: обновление версий ПО, достижение оптимальных
настроек конфигурации, защита от атак;
функции авторизации пользователей, управления
пользователями.
Администратор должен выполнять следующие
процедуры:
анализировать журналы работы веб-сервера и
сервера БД;
очищать журналы, контролировать их рост. Это
можно сделать средствами phpMyAdmin для MySQL и программами, выполняющими
архивацию и очистку журнала по расписанию для веб-сервера, например, cron.
находить в журналах подозрительные подключения,
запросы к скриптам и к таблицам.
В своей работе администратор должен использовать
следующие методы:
управления учетными записями пользователей -
блокировка, разблокировка, смена данных;
настраивать и контролировать профили
пользователей, удаляя или изменяя нежелательные элементы;
настраивать и видоизменять вид рабочей среды
пользователя в системе;
производить аудит системы программами,
тестирующими безопасность и мониторинг системы программами-анализаторами логов.
Для основной работы в системе есть меню
Администрирование и его подпункты. Для работы с пользователями необходимо
перейти в соответствующий подпункт, ввести id
пользователя и нажать необходимую ссылку. Для просмотра журнала можно перейти в
пункт «просмотр логов», выбрать число записей и проанализировать их. В случае
долгой загрузки страницы можно сделать вывод о слишком большой величине журнала
и очистить его в директории /user/local/apache/logs,
предварительно сделав архивную копию.
При наличии знаний в HTML
и CSS можно удобно редактировать
шаблоны сайта. Также в шаблоны можно включать код на PHP
и JavaScript.
Для просмотра журналов работы СУБД необходимо
зайти в phpMyAdmin
и выбрать пункт «Показать состояние MySQL».
Для обновления ПО нужно посещать сайты http://apache.org
и http://mysql.org
Заключение
Интернет не стоит на месте, и технологии,
которые основываются на работе в нем, постоянно развиваются. Поэтому
пользователи все более заинтересованы в интерактивных сервисах, позволяющих
легко получать доступ к необходимым данным, создавать эффект живого общения и
иметь интуитивно понятный интерфейс. Была поставлена задача создать минимально
необходимый набор средств для обеспечения обмена ссылками между пользователями.
Следовало добиться интеграции с интерфейсом операционной системы, обеспечить
удобную работу с данными, расширенный поиск, то есть предоставить все условия
пользователю, чтобы найти необходимую информацию для него не составило труда.
В процессе решения задач, поставленных
заказчиком, было произведено большое число исследований, в результате которых
появилось наиболее полное и соответствующее действительности описание
предметной области, построена концептуальная и логическая модели данных,
отражающих связи между компонентами системы, определены характеристики и показатели,
предъявляемые к системе. Затем мной были разработаны алгоритмы решения задач
системы и на их основе разработан программный модуль для выполнения функций
АИС.
После выбора СУБД и среды разработки и
обоснования такого выбора собственно было начато проектирование и
программирование. Программный модуль полностью выполняет те функции, которые
описаны в постановке задачи, и эти функции соответствуют предъявляемым к ним
требованиям. После разработки программного модуля была создана документация для
пользователей и администраторов системы.
В ходе решения задач и интерпретации их в
программную форму было решено множество сложностей, связанных с тонкостями
работы с базами данных, таблицами, их элементами (записями и полями),
взаимодействием таблиц и безопасностью данных, в том числе защитой от атак на
сценарии. В процессе отладки было получено множество практических навыков:
· например, как исправлять ошибки в
программном коде;
· были решены такие проблемы, как
работа с DOM при его
динамической подгрузке;
· «вечная» проблема при работе с
кодировками русского языка в AJAX;
· в составлении достаточно сложных SQL-запросов.
Относительно же степени реализации системы можно
сказать, что все ее функции выполнены в полном объеме, поэтому проблемы поиска
информации и ее синхронизации решать стало намного проще.
Однако в силу ограниченности времени реализации
проекта, не были реализованы некоторые желательные дополнительные функции:
защита от нежелательной корреспонденции;
возможность жалобы на пользователя;
увеличение схожести интерфейса с интерфейсом ОС,
повсеместное использование AJAX.
дополнительные возможности для пользователей:
загрузка своих файлов в хранилище, обмен ими, репутация пользователей;
форум для техподдержки.
Таким образом, систему можно совершенствовать
все время, начав с этого минимального дополнительного набора функций и, имея
обратную связь с пользователями, дополняя его.
Список использованной литературы
.Хольцнер
С. Ajax. Библия программиста. - М.:Диалектика, 2009. - 560 с.
.Крейн
Д., Паскарелло Э., Даррен Д. Ajax в действии. - М.: Вильямс, 2008. - 640 с.
.Мак-Федрис
П. Использование JavaScript. - М.: Вильямс, 2002. - 895 с.
.Веллинг
Л., Томсон Л. Разработка web-приложений с помощью PHP и MySQL. - М.: Вильямс,
2006. - 880 с.
.http://habrahabr.ru
.http://phpclub.ru
.http://php.su
.http://htmlbook.ru
.http://www.javascriptkit.com/
Приложение
Техническое задание
. Требования к системе в целом
1.1. Разрабатываемая система - единое целое,
выполняет решение поставленных перед ней задачи в соответствии с ними
разделяется на следующие функции:
работа с закладками пользователей;
поиск и рекомендация;
работа с личной перепиской;
администрирование и защита информации.
Функция «Работа с закладками» позволяет вводить
и редактировать данные закладок, копировать их к себе от других пользователей.
Функция «Поиск и рекомендация» позволяет находить необходимые закладки либо
непосредственно, либо методом выработки рекомендаций для пользователя. Функция
«Работа с личной перепиской» должна позволять просматривать списки сообщений,
отвечать на них и создавать новые сообщения. Функция «Работа с профилями
пользователей» позволяет ввести пользователю свои данные, а также просмотреть
данных других пользователей. Функция «Администрирование и защита информации»
позволяет защититься от несанкционированного доступа и управлять различными
объектами системы.
.2. Компоненты системы непосредственно
связаны друг с другом и находятся в тесной интеграции с клиентским программным
обеспечением.
1.3. Система функционирует в режиме реального
времени и работает с поддержкой технологии WYSIWYG настолько, насколько
позволяет ее отобразить конечное ПО пользователя.
.4. В случае некорректной работы системы
производится ее проверка и, при необходимости, остановка работы сервера на 1-2
дня, в течение которых восстанавливается ее работоспособность. При
незначительных неполадках работоспособность системы может быть восстановлена
без остановки серверного ПО.
1.5. Число пользователей системы теоретически
неограниченно, практически же - вычислительными ресурсами сервера и
особенностями работы его ПО. В системе обязательно должен присутствовать по
крайней мере один администратор.
1.6. Система приспосабливается к изменению
процессов и методов управления при несущественной доработке. Систему можно
модернизировать до тех пор, пока сложность модернизации не станет равной либо
превысит сложность написания новой АИС. Целевое назначение системы сохраняется
до тех пор, пока не отменен либо изменен стандарт в области образования.
.7. Надежность АИС непосредственно связана
с надежностью технических средств и считается полностью устойчивой при условии
стабильного электропитания и исправного оборудования. Программная часть системы
достаточно выверена, чтобы считаться надежной при любом применении.
.8. Требования по обеспечению безопасности
при монтаже и ремонте, противопожарной безопасности и защите от
электромагнитных полей должны быть описаны в технике безопасности,
распространяемой внутри серверной или датацентра, и требованиям стандартов
индивидуальной защиты при работе с электроприборами.
.9. Требования по эргономике системы - все
элементы должны быть достаточно крупными и хорошо читаемыми, интерфейс должен
быть удобен, комбинация цветов не должна раздражать зрение, не допускается использование
вычурных шрифтов или слишком убористого текста.
.10. Технически эксплуатация АИС должна
осуществляться по правилам использования ПК.
.11. Защита информации ведется с помощью системы
аутентификации на основе ввода имени пользователя и пароля, которая
предупреждает о попытках неверного входа в систему. Нарушить работу системы
может только зарегистрированный в ней пользователь.
.12 Сохранность информации должна осуществляться
при неожиданном отключении электропитания, вирусной атаке либо отказе технических
средств путем резервного копирования и восстановления данных из копии.
.13 Технические средства для обеспечения защиты
от внешних воздействий должны располагаться на достаточном удалении (5-10
метров) от источников электромагнитных полей, нагревательного оборудования,
источников электрического загрязнения (проводка), вдали от воды и пыльных мест
(также необходимо защищать внутренности монитора и системного блока от
попадания воды или инородных тел).
.14. Патентная чистота должна быть обеспечена в
отношении России и стран СНГ.
.15. Вся документация по разработанной системе
должна быть стандартизирована по ЕСПД, в качестве нормативных документов
следует использовать стандартные и унифицированные для данной предметной
области формы.
. Требования к функциям системы
Функция «Работа с закладками» должна решать
следующие задачи:
ввод данных в таблицу БД. Введенная информация
должна там храниться до тех пор, пока не будет удалена пользователем либо
таблица не будет физически удалена с жесткого диска;
редактирование данных. Позволяет редактировать
любую информацию о закладке (если она принадлежит пользователю) вне зависимости
от значений остальных данных о ней, таким образом осуществляется быстрая и
гибкая система исправления ошибок.
рекомендация ссылок. Пользователю предлагается
на выбор 5 доменов, из которых он может сделать выбор ссылок, принадлежащих
прочим пользователям.
поиск данных - может происходить по категории,
по описанию, по наименованию и по url, причем достаточно части слов, также в
полях поиска может присутствовать несколько слов, разделенных запятой.
удаление данных из БД. Позволяет удалить
закладку и все, связанное с ней. Стоит заметить, что при копировании закладок к
себе они не связаны с закладками пользователя, от которого копируются.
Функция «Работа с личной перепиской» должна
решать задачи:
просмотра списка сообщений с разделением на
«входящие» и «исходящие»;
выбор сообщения и его просмотр;
ответ на сообщение;
создание нового сообщения.
Функция «Администрирование и защита информации»
должна решать задачи:
изменения шаблонов оформления сайта;
просмотр данных пользователей и их закладок и в
случае необходимости - изменение и удаление.
аутентификацию и регистрацию новых пользователей
блокирование учетных записей пользователей и их
удаление.
. Требования к видам обеспечения
.1. Математическое обеспечение - в состав
системы входят типовые формулы расчета и преобразования дат, модели работы с
закладками, шифрования данных, выработки рекомендаций и работы с сообщениями,
пользовательским окружением на основе сложных запросов.
.2. Информационное обеспечение - состав,
структура и организация данных (например, личные дела учащихся и сведения об их
успеваемости) - представлены в виде содержимого таблиц БД. Информационный обмен
между компонентами системы происходит путем связи таблиц, форм и SQL-операторов.
Сбор данных в системе производится путем их ввода в таблицы. Обработка и
передача данных происходит на основе алгоритмов решения задач системы. Защита
данных от разрушения решается путем восстановления данных из резервных копий,
то есть восстановление должно идти из ближайшей сделанной копии. Хранение,
обновление и восстановление данных происходит в таблицах БД путем записи,
перезаписи, дозаписи в них данных. Документы, создаваемые в ходе работы АИС, не
имеют юридической силы.
.3 Лингвистическое обеспечение - использование
языка программирования высокого уровня - PHP
- должно обеспечиться тем, что он пригоден для решения всех функций системы.
Обеспечение диалога с пользователем происходит с помощью средств языков HTML и
JavaScript и предусматривает минимальное количество ложных срабатываний и
проверку корректности ввода данных.
.4. Программное обеспечение - используется MySQL
5, PHP 5, Apache 2.6 на стороне сервера и любое ПО на стороне клиента, которое
поддерживается перечисленными ниже минимальными системными требованиями.
.5. Техническое обеспечение - минимальная
конфигурация для клиента 128 Mb
RAM/1 GHz
процессор/10 Gb
HDD/32 Mb
video/принтер,
клавиатура, мышь.
.6. Организационное обеспечение - инструкция по
сопровождению и использованию; реакция системы на ошибки пользователя,
подсказки, справка в бумажном варианте и в виде функции системы.