Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

web - tec / PHP 5 для начинающи

.pdf
Скачиваний:
78
Добавлен:
12.06.2015
Размер:
26.79 Mб
Скачать

472 Глава 11

Теперь по мере того как пользователи будут перемещаться по сайту, все посеще+ ния страниц будут протоколироваться.

Рассмотрим объявление функции, которая проверяет отправку пользователем своего идентификатора. Если пользователь не передал идентификатор, то необходи+ мо вызывать функцию login_form(), ту же самую, которая использовалась в auth_user.php (нужно просто перенести код этой функции в данный файл; здесь ее код не показывается):

function do_authentication() {

global $default_dbname, $user_tablename, $access_log_tablename; global $MYSQL_ERROR, $MYSQL_ERRNO;

global $filename; global $PHP_SELF;

if(!isset($_POST['userid'])) { login_form();

exit;

Если сценарий получил переданные пользователем идентификатор и пароль, то эти значения используются в запросе к базе данных. Здесь также определяются пере+ менные сеанса. Переменные сеанса сохраняются между запросами страниц.

}else {

$_SESSION['userpassword'] = $_POST['userpassword']; $_SESSION['userid'] = $_POST['userid']; }

$userid = $_POST['userid']; $userpassword = $_POST['userpassword']; $link_id = db_connect($default_dbname);

$query = "SELECT username FROM $user_tablename

WHERE userid = '$userid' AND userpassword = password('$userpassword')"; $result = mysql_query($query);

}

Если запрос был выполнен неудачно (например, если пользователь вводит только свое имя), то сеанс аннулируется и пользователю выводится сообщение о том, что он не прошел авторизацию:

if(!mysql_num_rows($result)) {

session_unregister("userid");

echo "Попытка авторизации неудачна. " .

"Вы должны ввести допустимый идентификатор пользователя и пароль. " . "Чтобы попытаться снова, щелкните следующую ссылку.<BR>\n";

echo "<A HREF=\"$PHP_SELF\"> Вход в систему</A><BR>";

echo "Если Вы еще не зарегистрированы, для регистрации щелкните следующую ссылку." .

"<BR>\n";

echo "<A HREF= \"register.php\">Зарегистрироваться</A>"; exit;

В случае успешного выполнения запроса необходимо проверить, посещал ли поль+ зователь данную страницу раньше, и либо вставить, либо обновить соответствующие значения в таблице:

}else{

$query = "SELECT userid FROM $access_log_tablename WHERE page = '$filename' AND userid = '$userid'"; $result = mysql_query($query); if(!mysql_num_rows($result)) {

$query = "INSERT INTO $access_log_tablename VALUES ('$filename', '$userid', 1, NULL)";

Использование PHP для управления информацией в базах данных MySQL 473

}else{

$query = "UPDATE $access_log_tablename

SET visitcount = visitcount + 1, accessdate = NULL WHERE page = '$filename' AND userid = '$userid'";

}

mysql_query($query);

$num_rows = mysql_affected_rows($link_id); if($num_rows != 1) die(sql_error());

}

}

Если вызвать этот сценарий в браузере, то будет выведена пустая страница (предполагается, что пользователь вводит корректный идентификатор и пароль). Од+ нако если изучить информацию в таблице access_log, то станет ясно, что это посе+ щение было запротоколировано. В приведенном ниже примере администратор сайта открыл страницу access_logger.php, чтобы убедиться в ее работоспособности:

mysql> select * from access_log; +———------------———-+----——--+—--------———+——----------———-+ | page | userid | visitcount | accessdate | +------------——————-+----——--+——----------------------————-+

| stats.html

| Brian

|

1

| 20040304143102 |

| score.html

| Pads

|

2

| 20040312160114 |

| refs.html

| Nicrot |

5

| 20040124122744

|

| log.html

| Nicrot |

3

| 20040124122642

|

| log.html

| Greeny |

4

| 20040124112654

|

| access_logger.php

| Dodge

|

1

| 20040314192430

|

+------------——————-+----——--+——--------——+——--------------+ 6 rows in set (0.00 sec)

Создание сценария для управления пользователями

Наконец, можно собрать все примеры сценариев вместе и усовершенствовать сцена+ рий просмотра записей (созданный в предыдущей главе) так, чтобы он позволял управ+ лять данными в связанных таблицах. Используя следующий сценарий userman.php, можно редактировать и удалять регистрационные записи пользователей и/или соот+ ветствующие записи о посещении страниц.

Файл userman.php

Данный сценарий начинается, как и register.php, с выборки вариантов для

ENUM+поля userposition:

<?php

//userman.php

include_once "./common_db.inc";

$link_id = db_connect(); mysql_select_db("sample_db");

$position_array = enum_options('userposition', $link_id); mysql_close($link_id);

474 Глава 11

Функция user_message()

Функция user_message() сообщает о результатах заданной операции. Если ей был передан необязательный аргумент URL, то она загружает определенную страницу:

function user_message($msg, $url =")

{

html_header();

if(empty($url)){

echo "<SCRIPT>alert(\"$msg\");history.go(-1)</SCRIPT>"; }else{

echo "<SCRIPT>alert(\"$msg\");self.location.href='$url'</SCRIPT>";

}

html_footer(); exit;

}

Функция list_records()

В переработанной функции list_records() появляется возможность удалять определенную запись. Остальная часть функции такая же, как и в предыдущей ее вер+ сии (в главе 10):

function list_records() {

...

echo "<td WIDTH=\"25%\" ALIGN=\"CENTER\">

<a href=\"javascript:open_window('$PHP_SELF?action=view_record&

userid=$userid');\">

Просмотреть запись</a>

<a href=\"$PHP_SELF?action=delete_record&userid=$userid\"

onClick=\"return confirm('Вы уверены?');\">

Удалить запись</a>

</td>\n"; echo "</tr>\n";

...

}

Функция delete_record()

Функция delete_record() удаляет запись определенного пользователя из таб+ лицы user, а также соответствующие ей записи из таблицы access_log:

function delete_record()

{

global $default_dbname, $user_tablename, $access_log_tablename; $userid = $_GET['userid'];

if(empty($userid)){

error_message('Введите идентификатор пользователя!');

}

$link_id = db_connect($default_dbname); if(!$link_id){

error_message(sql_error());

}

$query = "DELETE FROM $user_tablename WHERE userid = '$userid'"; $result = mysql_query($query);

if(!$result){ error_message(sql_error());

Использование PHP для управления информацией в базах данных MySQL 475

}

$num_rows = mysql_affected_rows($link_id);

if($num_rows != 1){

error_message("Пользователя $userid не существует");

}

$query = "DELETE FROM $access_log_tablename WHERE userid = '$userid'"; $result = mysql_query($query);

user_message("Все записи, относящиеся к пользователю $userid удалены!");

}

Функция edit_record()

Функция edit_record() обновляет запись определенного пользователя в табли+ це user. Если изменяется идентификатор пользователя, то она также обновляет свя+ занные записи в таблице access_log, отражая это изменение:

function edit_record()

{

global $default_dbname, $user_tablename, $access_log_tablename; $PHP_SELF = $_SERVER['PHP_SELF'];

$userid = $_GET['userid']; $newuserid = $_GET['new_userid']; $username = $_GET['username'];

$userpassword = $_GET['userpassword']; $userposition = $_GET['userposition']; $useremail = $_GET['useremail']; $userprofile = $_GET['userprofile'];

if(empty($userid)){

$userid = $_GET['new_userid'];

}

$link_id = db_connect($default_dbname); if(!$link_id){

error_message(sql_error());

}

$field_str = ";

Действительно, значение поля userid тоже можно изменить. С точки зрения ад+ министраторов баз данных, как правило, недопустимо давать пользователю возмож+ ность изменять свой идентификатор, так как он (идентификатор) выполняет функ+ ции номера социального страхования (Social Security number) ++++++ он уникален и одновременно неизменен. Тем не менее, если бы пользователь настаивал на изме+ нении своего идентификатора, то пришлось бы изменить каждую запись в каждой связанной таблице независимо от количества этих записей, или, в конце концов, в ба+ зе данных накопилось бы множество бесполезных записей, не имеющих владельца.

Новый идентификатор пользователя следует сравнить с существующим и в случае необходимости обновить переменную $field_str:

if($userid != $new_userid) $field_str = " userid = '$newuserid', ";

Если переменная $userpassword содержит какое+либо значение, то необходимо обновить поле userpassword:

if(!empty($userpassword)) {

$field_str .= " userpassword = password('$userpassword'), ";

}

476 Глава 11

Подобная проверка не позволит администратору случайно оставить в поле userpassword пустое значение. Затем необходимо обновить остальные поля и про+ верить, все ли идет по плану:

$field_str .= " username = '$username', "; $field_str .= " userposition = '$userposition', "; $field_str .= " useremail = '$useremail', "; $field_str .= " userprofile = '$userprofile'";

$query = "UPDATE IGNORE $user_tablename SET $field_str WHERE userid = '$userid'"; $result = mysql_query($query);

if(!$result){ error_message(sql_error());

}

$num_rows = mysql_affected_rows($link_id);

if(!$num_rows){

error_message("Ни одна запись не изменена!");

}

Следует отметить использование в данном запросе оператора IGNORE. Поле userid является частью первичного ключа и MySQL препятствует его изменению, а оператор IGNORE позволяет продолжить выполнение запроса и внести изменения. Кроме того, чтобы база данных была согласованной, для отражения изменений необходимо обно+ вить все остальные таблицы.

Если значение поля userid изменяется, то функция edit_record соответствую+ щим образом обновляет все связанные записи в таблице access_log:

if($userid != $new_userid){

$query = "UPDATE $access_log_tablename SET userid = '$newuserid' WHERE userid = '$userid'";

$result = mysql_query($query); if(!$result){

error_message(sql_error());

}

user_message("Все записи, связанные с $userid, были изменены!", "$PHP_SELF?action=view_record&userid=$newuserid");

}else{

user_message("Все записи, связанные с $userid, были изменены!", "$PHP_SELF?action=view_record&userid=$userid");

}

}

Если поле userid было изменено, то вызывается функция user_message(), вто+ рой аргумент которой определяет часть URL userid=$new_userid, так как возвра+ щение в сценарий со старым значением userid привело бы к неожиданному резуль+ тату ++++++ выводу формы для редактирования данных несуществующего пользователя.

Функция edit_log_record()

Функция edit_log_record() обновляет в таблице access_log записи о посе+ щениях страниц для заданного пользователя:

function edit_log_record() {

global $default_dbname, $access_log_tablename; $userid = $_GET['userid'];

$newpage = $_GET['new_page']; $visitcount = $_GET['visitcount'];

Использование PHP для управления информацией в базах данных MySQL 477

$accessdate = $_GET['accessdate']; $orgpage = $_GET['org_page']; $PHP_SELF = $_SERVER['PHP_SELF'];

if(empty($userid)){

error_message('Введите идентификатор пользователя!');

}

$link_id = db_connect($default_dbname); if(!$link_id){

error_message(sql_error());

}

$field_str = ";

$field_str .= " page = '$newpage', "; $field_str .= " visitcount = '$visitcount', "; $field_str .= " accessdate = '$accessdate' ";

Данная функция работает почти так же, как функция edit_record(). Основное отличие заключается в том, что функция edit_log_record() использует для выбора соответствующих записей таблицы access_log два поля: userid и page.

Существующее значение поля page сохраняется в переменной $org_page на слу+ чай, если администратор изменит значение этого поля в форме для редактирования:

$query = "UPDATE $access_log_tablename SET $field_str WHERE userid = '$userid' AND page = '$orgpage'";

$result = mysql_query($query); if(!$result){

error_message(sql_error());

}

Если ни одна запись не обновилась, то это значит, что администратор нажал кноп+ ку Отправить, ничего не изменив в соответствующей форме для редактирования.

Функция mysql_affected_rows() возвращает 0, так как в результате предыду+ щей UPDATE+операции ни одна запись не изменилась. Команда UPDATE не выполняет никаких изменений, если новая запись содержит те же значения, что и существующая:

$num_rows = mysql_affected_rows($link_id);

if(!$num_rows){

error_message("Данные не изменены!");

}

user_message("Все записи, относящиеся к пользователю $userid, были изменены!", "$PHP_SELF?action=view_record&userid=$userid");

}

Функция view_record()

Усовершенствованная версия функции view_record() позволяет администрато+ ру редактировать пользовательские записи:

function view_record() {

global $default_dbname, $user_tablename, $access_log_tablename; global $position_array; $userid = $_GET['userid']; $PHP_SELF = $_SERVER['PHP_SELF'];

if(empty($userid)){

error_message('Введите идентификатор пользователя!');

478 Глава 11

}

$link_id = db_connect($default_dbname);

if(!$link_id){ error_message(sql_error());

}

$query = "SELECT usernumber, userid, username, userposition, useremail, userprofile FROM $user_tablename WHERE userid = '$userid'";

$result = mysql_query($query); if(!$result){

error_message(sql_error());

}

$query_data = mysql_fetch_array($result); $usernumber = $query_data["usernumber"]; $userid = $query_data["userid"]; $username = $query_data["username"];

$userposition = $query_data["userposition"]; $useremail = $query_data["useremail"]; $userprofile = $query_data["userprofile"];

Наконец, отображается несколько форм, с помощью которых администратор мо+ жет редактировать пользовательские записи и данные о посещении страниц:

html_header();

echo "<center><H3>

Запись для пользователя №. $usernumber - $userid($username) </h3></center>";

?>

<form method="get" action="<?php echo $PHP_SELF ?>"> <input type="hidden" name="action" value="edit_record">

<input type="hidden" name="userid" value="<? echo $userid ?>"> <div align="center"><center>

<table border="1" width="90%" cellpadding="2">

<tr>

<th width="30%" nowrap>Идентификатор</th>

Скрытое поле new_userid используется в случае, если администратор изменяет значение поля userid:

<td width="70%">

<input type="text" name="new_userid" value="<?php echo $userid ?>" size="8" maxlength="8"></td>

</tr>

<tr>

<th width="30%" nowrap>Пароль</th>

Зашифрованный пароль не выводится, так как он не используется:

<td width="70%"><input type="text" name="userpassword" size="15"></td> </tr>

<tr>

<th width="30%" nowrap>Полное имя</th>

<th width="70%"><input type="text" name="username"

value="<?php echo $username ?>" SIZE="20"></td>

</tr>

<tr>

<th width="30%" nowrap>Позиция</th>

<td width="70%"><select name="userposition" size="1">

<?php

Использование PHP для управления информацией в базах данных MySQL 479

Для создания выпадающего списка возможных позиций используется переменная $position_array:

for($i=0; $i < count($position_array); $i++) { if(!isset($userposition) && $i == 0) {

echo "<OPTION SELECTED VALUE=\"". $position_array[$i] . "\">" . $position_array[$i] . "</OPTION>\n";

}else if($userposition == $position_array[$i]) {

echo "<OPTION SELECTED VALUE=\"". $position_array[$i] . "\">" . $position_array[$i] . "</OPTION>\n";

}else{

echo "<OPTION VALUE=\"". $position_array[$i] . "\">" . $position_array[$i] . "</OPTION>\n";

}

}

?>

</select></td>

</tr>

<tr>

<th width="30%" nowrap>E-mail-адрес</th>

<td width="70%"><input type="text" name="useremail" size="20" value="<?php echo $useremail ?>"></td>

</tr>

<tr>

<th width="30%" nowrap>Профиль</th>

Функция htmlspecialchars() гарантирует, что любые специальные HTML+ символы в переменной $userprofile выводятся в виде HTML+последовательностей и не способны нарушить окружающую разметку:

<td width="70%">

<textarea rows="5" cols="40" name="userprofile"> <?php echo htmlspecialchars($userprofile) ?>

</textarea>

</td>

</tr>

<tr>

<th width="100%" colspan="2" nowrap> <input type="submit" value="Записать"> <input type="reset" value="Очистить">

</th>

</tr>

</table>

</center></div>

</form>

<?php

echo "<HR SIZE=\"2\" WIDTH=\"90%\">\n";

Каждая запись из таблицы access_log представляется в отдельной форме:

$query = "SELECT page, visitcount, accessdate, date_format(accessdate, '%M, %e, %Y') as formatted_accessdate FROM $access_log_tablename WHERE userid = '$userid'";

$result = mysql_query($query);

if(!$result){ error_message(sql_error());

}

if(!mysql_num_rows($result)){

echo "<center>У пользователя $userid ($username) нет записей о посещении страниц.</center>";

}else{

echo "<center>Записи о посещении страниц пользователем $userid ($username).</center>";

480 Глава 11

}

?>

<div align="center"><center>

<table border="1" width="90%" cellpadding="2">

<tr>

<th width="20%" nowrap>Страница</th> <th width="20%" nowrap>Посещения</th>

<th width="30%" nowraP>Последнее посещение</th> <th width="30%" nowrap>Действие</th>

</tr>

<?php

Результаты данного запроса выводятся в хорошо отформатированной таблице, которую администратор может использовать для изменения access_log+значений:

while($query_data = mysql_fetch_array($result)){ $page = $query_data["page"];

$visitcount = $query_data["visitcount"]; $accessdate = $query_data["accessdate"];

$formatted_accessdate = $query_data["formatted_accessdate"];

echo "<FORM METHOD=\"GET\" ACTION=\"$PHP_SELF\">";

echo "<INPUT TYPE=\"HIDDEN\" NAME=\"action\"VALUE=\"edit_log_record\">"; echo "<INPUT TYPE=\"HIDDEN\" NAME=\"userid\" VALUE=\"$userid\">";

echo "<INPUT TYPE=\"HIDDEN\" NAME=\"org_page\" VALUE=\"$page\">"; echo "<TR>\n";

echo "<TD WIDTH=\"20%\"><INPUT TYPE=\"TEXT\"NAME=\"new_page\" SIZE=\"30\" VALUE=\"$page\"></TD>\n";

echo "<TD WIDTH=\"20%\" ALIGN=\"CENTER\">

<INPUT TYPE=\"TEXT\" NAME=\"visitcount\" SIZE=\"3\" VALUE=\"$visitcount\"></TD>\n";

echo "<TD WIDTH=\"30%\" ALIGN=\"CENTER\">

<INPUT TYPE=\"TEXT\" NAME=\"accessdate\" SIZE=\"14\" MAXLENGTH=\"14\" VALUE=\"$accessdate\"> <BR>$formatted_accessdate</TD>\n";

echo "<TD WIDTH=\"30%\" ALIGN=\"CENTER\"> <INPUT TYPE=\"SUBMIT\" VALUE=\"Записать\">

<INPUT TYPE=\"RESET\" VALUE=\"Очистить\"></TD>\n"; echo "</TR>\n";

echo "</FORM>\n";

}

?>

</tr>

</table>

</center></div>

<?php html_footer();

}

Выбор действия

Наконец, чтобы определить, какая функция должна быть вызвана далее, использу+ ется переменная $action:

if (empty($_GET['action'])){ $_GET['action'] = "";

}

switch($_GET['action']) { case "edit_record": edit_record();

break;

case "edit_log_record": edit_log_record(); break;

Использование PHP для управления информацией в базах данных MySQL 481

case "delete_record": delete_record(); break;

case "view_record": view_record(); break;

default: list_records();

break;

}

?>

Предположим, что администратору нужно вывести список записей, отсортиро+ ванных по номеру пользователя. На рис. 11.11 показана страница после нажатия на заголовок соответствующего поля:

Рис. 11.11.

Если щелкнуть на ссылке Просмотреть запись, то откроется новое окно, в кото+ ром будут показаны записи, относящиеся к пользователю, связанному с данной ссыл+ кой (рис. 11.12).

Соседние файлы в папке web - tec