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

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

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

11

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

В этой главе показано, как управлять записями в базах данных MySQL из PHP+ сценариев. В частности, здесь рассматривается вставка новых записей в таблицу базы данных с помощью PHP, а также удаление и обновление записей, уже имеющихся в таблице базы данных.

Чтобы дать читателю возможность разобраться в этой функциональности, авторы подробно рассматривают разработку двух сценариев: регистрации пользователей (User Manager) и протоколирования посещения страниц (Access Logger). Кроме того, в этой главе показано, как усовершенствовать сценарий для просмотра пользователь+ ских записей, созданного в главе 10, добавив в него возможность управления запися+ ми пользователей. Эта глава завершает серию глав, посвященных MySQL и взаимо+ действию PHP и MySQL.

Вставка записей с помощью PHP

В предыдущей главе было показано, как вставлять данные в таблицу, используя клиентскую программу mysql. Например, следующий запрос вставляет запись для пользователя Pads:

mysql> INSERT INTO user VALUES( -> NULL,

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

-> 'Pads',

-> Password(12345), -> 'Brian Reid', -> 'Winger',

-> 'Stickypads@doggies_rugby.com',

-> 'Высококлассный перехватчик мячей.');

Той же цели можно достичь с помощью PHP:

$result = mysql_query("INSERT INTO user VALUES( ... )");

Обычно для вставки значений в таблицу вместо непосредственного указания зна+ чений в запросе используются PHP+переменные:

$query = "INSERT INTO user VALUES(NULL, '$userid', password('$userpassword'),

'$username', '$userposition', '$useremail', '$userprofile')";

$result = mysql_query($query);

Напомним, что поле usernumber имеет тип AUTO_INCREMENT ++++++ запрос передает в это поле NULL, чтобы его значение в каждой новой добавляемой записи было на единицу больше, чем у предыдущей записи.

Иногда возможность получать результирующее значение бывает очень удобной; например, можно сделать так, чтобы сценарий при регистрации нового пользователя показывал ему его регистрационный номер. Автоматически увеличенное число, сге+ нерированное последним INSERT+запросом, можно получить с помощью функции mysql_insert_id(). Например:

$link_id = db_connect('sample_db');

$result = mysql_query("INSERT INTO user (userid) VALUES('sphinx')");

$usernumber = mysql_insert_id($link_id); echo "Спасибо. Ваш номер - $usernumber.";

Специальные символы

Как уже отмечалось в главе 9, прежде чем вставлять строковое значение в таблицу базы данных, необходимо экранировать каждую одинарную кавычку в этом значении, в противном случае возникает ошибка. В предыдущей главе приводился пример с вставкой строки ‘‘I’m a rugby player’’ в поле userprofile типа TEXT. Ввиду того, что эта строка ограничена двойными кавычками, она хорошо вставляется в базу данных как с помощью клиентской программы mysql, так и с помощью PHP. Чтобы заключить эту строку в одинарные кавычки, понадобилось бы экранировать одинарную кавычку, содержащуюся в строке. Рассмотрим несколько примеров:

"I'm a PHP developer." Работает.

'I\m a PHP developer.' Тоже работает. 'I'm a PHP developer.' Не работает.

Однако почему приходится учитывать эти различия? Несомненно, лучше всего экра+ нировать все вхождения кавычек, как двойных, так и одинарных ++++++ в конце концов, в PHP экранированные кавычки работают как в строковых значениях, ограниченных одинар+ ными кавычками, так и в строковых значениях, ограниченных двойными кавычками. Все зависит от программы. Если поставить обратную косую черту перед одинарной ка+ вычкой в первом примере, то получится следующая строка: "I\'m a PHP developer".

444 Глава 11

Если впоследствии вывести эту строку с помощью PHP, то она отобразится в брау+ зере в таком же виде, т.е. с обратной косой чертой, а это очевидно совсем не то, что нужно. Данная проблема решается в PHP с помощью пары очень удобных функций: addslashes()и stripslashes().

Эти функции тесно связаны друг с другом. Функция addslashes() принимает строковый аргумент, предваряет каждый символ, который должен быть экранирован в запросах к базе данных, символом обратной косой черты, а затем возвращает моди+ фицированную строку. Функция stripslashes() решает обратную задачу, удаляя из строки все символы обратной косой черты.

Следующие строки кода показывают, как можно использовать эти функции для вставки записей в таблицу, экранируя значения так, как это требуется:

$link_id = db_connect('sample_db'); $userprofile = addslashes($userprofile);

$query = "INSERT INTO user (userprofile) VALUES('$userprofile')"; mysql_query($query, $link_id);

$userprofile = stripslashes($userprofile);

Если предположить, что в переменной $userprofile хранится строка:

I'm a PHP developer.

то после обработки функцией addslashes() эта переменная получит значение:

I\'m a PHP developer.

Теперь эту переменную можно безопасно передавать в SQL+оператор. Когда понадо+ бится прочитать это значение из базы данных, сервер вернет строку с кавычкой, но без escape+последовательностей. Однако если использовать переменную $userprofile в последующем коде, то посторонние символы обратной косой черты будут искажать правильно отформатированный текст. Чтобы привести эту строку в порядок, следует использовать функцию stripslashes().

Функция htmlspecialchars()

Вопросы, связанные со специальными символами, не заканчиваются экраниро+ ванием кавычек. Как известно, определенные символы имеют в HTML специальное значение, например, символ < обозначает начало HTML+тега. Если этот символ со+ держится во введенной пользователем строке, которая затем выводится на HTML+ странице, то это неизбежно приведет к неверному отображению Web+страницы в браузере. Синтаксический анализатор HTML+кода будет связывать все, что следу+ ет после этого символа (вплоть до символа >), с каким+либо тегом, хотя вряд ли это будет действительно так.

Чтобы избежать этого, можно представить указанный символ в форме HTML+ последовательности, которая выглядит так:

<

PHP+функция htmlspecialchars(), которая уже рассматривалась вкратце в главе 5, решает задачу преобразования специальных HTML+символов в их текстовую форму, что значительно упрощает работу программиста. Так же как функции, добавляю+ щие/удаляющие обратную косую черту, которые рассматривались выше, htmlspecialchars() принимает строковый аргумент, заменяет все специальные символы соответствующими безопасными формами и возвращает модифицированную строку:

$userprofile = htmlspecialchars($userprofile);

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

Преобразовываются следующие символы:

Специальный символ

HTML-последовательность

 

 

& (амперсанд)

&

" (двойная кавычка)

"

< (знак меньше)

<

> (знак больше)

>

 

 

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

Обновление и удаление записей в таблицах

Предположим, что один из зарегистрированных пользователей сайта намерен из+ менить его регистрационное имя, так как в нем обнаружилась опечатка. Вместо того чтобы заменять всю запись для данного пользователя, можно изменить только значе+ ние в поле username имеющейся записи. Очевидно, что для этого используется ко+ манда UPDATE. Рассмотрим пример соответствующего оператора:

UPDATE user SET username = 'Darren Ebbs'

WHERE username = 'Daren Ebbs'

Указанная команда изменяет в поле username все вхождения строки Daren Ebs

на Darren Ebbs.

Чтобы удалить из таблицы существующую запись, необходимо использовать ко+ манду DELETE:

DELETE FROM access_log WHERE page = 'who.html'

Она удаляет все записи, в которых значение поля page равно 'who.html'.

Ниже приводится пример такого UPDATE+запроса, который использовать не следу* ет. Он обновляет все записи в таблице user так, что любой пользователь впоследст+ вии сможет входить на сайт, используя пароль comeonin:

UPDATE user SET userpassword = password('comeonin')

Еще хуже последствия запроса, который очищает таблицу user:

DELETE FROM user

Такого рода грубые ошибки могут допускать даже очень опытные администраторы баз данных ++++++ это последствия невнимательности во время ввода запроса. Используя данные команды, следует быть очень внимательным.

Предположим, что из таблицы access_log требуется удалить все записи, начиная с 1999 года, так как они больше не нужны. Для этого можно использовать такой запрос:

mysql> DELETE FROM access_log WHERE accessdate LIKE '1999%';

Пользователь может захотеть время от времени изменять свой пароль. Следующий запрос изменяет пароль пользователя на guessit:

mysql> UPDATE user SET userpassword = password('guessit') -> WHERE userid = 'Greeny';

Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0

446 Глава 11

Сервер сообщает, что с заданным условием совпала одна строка, которая, следова+ тельно, и была изменена. Если сервер не находит совпадающих записей, то обновле+ ние не выполняется:

mysql> UPDATE user SET userpassword = password('guessit') -> WHERE userid = 'Ginger';

Query OK, 0 rows affected (0.00 sec) Rows matched: 0 Changed: 0 Warnings: 0

Можно использовать существующие значения для обновления записи. Например,

вполе visitcount содержится количество посещений определенным пользователем какой+либо Web+страницы. Если пользователь посещает данную страницу снова, то значение в поле visitcount необходимо увеличить на 1. Для этого можно получить текущее значение из таблицы access_log, прибавить к нему 1, а затем записать

втаблицу новое значение. Однако той же цели можно достичь намного проще ++++++ ис+ пользуя существующее значение в UPDATE+запросе. Следующий запрос делает как раз то, что нужно ++++++ он увеличивает значение поля visitcount для пользователя Dodge, посещающего страницу /score.html:

mysql> UPDATE access_log SET visitcount = visitcount + 1 -> WHERE user_id = 'Dodge' AND page = '/score.html';

Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0

Поле lastaccesstime необходимо обновлять отдельно (этот вопрос обсужда+ ется далее).

Строковые значения обновляются аналогично:

mysql> UPDATE user SET userid = concat(userid, '_1'); Query OK, 6 row affected (0.00 sec)

Rows matched: 6 Changed: 6 Warnings: 0

В запросе используется функция MySQL+сервера для слияния строк, которая добав+ ляет строку _1 к каждому значению поля userid. Например, в данном случае иденти+ фикатор пользователя Dodge станет равным Dodge_1. Этот метод оказывается очень удобным, когда новый пользователь запрашивает идентификатор, который уже исполь+ зуется другим пользователем, и нужно предложить альтернативный идентификатор.

Если бы использовался запрос SET userid = userid + ‘_1’, то значение поля userid было бы равным 0, а не Dodge_1.

Допускаются также множественные обновления одного поля:

mysql> UPDATE access_log

-> SET visitcount = visitcount + 1, visitcount = visitcount * 2; Query OK, 6 rows affected (0.00 sec)

Rows matched: 6 Changed: 6 Warnings: 0

Присвоения значений выполняются слева направо, поэтому во втором присвое+ нии используется уже увеличенное на 1 значение поля visitcount. Другими слова+ ми, сначала ко всем текущим значениям поля visitcount прибавляется 1, а затем по+ лученные числа удваиваются.

К настоящему моменту читатели уже, вероятно, привыкли видеть отчеты MySQL+ сервера в командной строке. Когда используется запрос DELETE или UPDATE, сервер автоматически сообщает количество задействованных строк, время, потраченное на выполнение данного запроса, количество совпадающих и измененных строк, а также выводит любые сгенерированные предупреждения.

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

Первый из этих параметров можно получить в PHP+сценарии, используя функцию mysql_affected_rows(). Она в качестве аргумента принимает идентификатор со+ единения с базой данных и возвращает количество записей, затронутых предыдущим SQL+запросом ++++++ DELETE+запросом в следующем примере:

$link_id = db_connect("sample_db"); mysql_query("DELETE FROM access_log

WHERE page = '/penalties.html'");

$num_rows = mysql_affected_rows($link_id); echo "Было удалено $num_rows пользователей.";

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

Было удалено 1 пользователей.

Если сценарий удаляет все записи в таблице, то функция mysql_affected_rows() возвращает 0.

Работа с полями даты и времени

Пожалуй, из всех типов данных в MySQL самыми сложными для обработки явля+ ются дата и время. Для правильной работы с ними необходима длительная практика. В полях этих типов значения даты и времени хранятся в следующих форматах:

Тип данных

Формат

 

 

DATE

2004-01-01

TIME

12:00:00

DATETIME

2004-01-01 12:00:00

TIMESTAMP

20000101120000

YEAR

2004

 

 

Если попытаться вставить в такое поле неверно отформатированное значение да+ ты и/или времени, то это поле в соответствующей записи будет заполнено нулями. Например, вставка строки Pads в поле TIME+типа приведет к тому, что в данном поле сохранится значение 00000000000000:

mysql> select accessdate from access_log where userid = 'Pads' AND page ='';

+----------------

 

+

| accessdate

|

+----------------

 

+

+ 00000000000000 |

+----------------

 

+

1

row in set (0.00 sec)

MySQL+сервер предоставляет несколько встроенных функций, связанных с да+ той и временем, которые позволяют гарантировать вставку корректных значений. Выше уже упоминалась функция now(), которая возвращает текущую дату и время в формате DATETIME:

mysql> select now();

 

+--------------------------

 

+

| now()

|

+--------------------------

 

+

| 2004-03-04 19:30:15

|

+--------------------------

 

+

1

row in set (0.00 sec)

 

448 Глава 11

а также функции curdate()и curtime(), которые возвращают по отдельности зна+ чения DATE и TIME:

mysql> select curdate(), curtime();

+------------

 

+-----------

+

| curdate()

| curtime() |

+------------

 

+-----------

+

| 2004-03-04

| 19:31:33

|

+------------

 

+-----------

+

1

row in set

(0.00 sec)

 

Для вставки значения в поле типа TIMESTAMP можно указать либо дату и время

ввиде строки из 14 цифр, либо NULL, в результате чего в поле сохраняется текущая системная дата и время в таком же формате. Чтобы правильно обновлять записи

втаблице access_log, следует использовать команду:

mysql> UPDATE access_log

-> SET visitcount = visitcount + 1, accessdate = NULL -> WHERE userid = 'Dodge' AND page = '/score.html';

Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0

Серверная функция date_format() возвращает отформатированное значение даты и времени. Она принимает аргумент DATE+ или DATETIME+типа, а также строку формата. Если поле lastaccesstime имеет тип DATE или DATETIME, то можно ис+ пользовать следующую команду:

mysql> SELECT date_format('2004-03-04 22:23:00', '%M %e, %Y'); +-------------------------------------------------+

| date_format('2004-03-04 22:23:00', '%M %e, %Y') |

+-------------------------------------------------

 

+

| March 4, 2004

|

+-------------------------------------------------

 

+

1

row in set (0.03 sec)

 

Существует более 30 спецификаторов, которые можно использовать в строке формата. Ниже перечислены наиболее распространенные из них.

Спецификатор

Описание

 

 

%s

Секунда в двузначной числовой форме (00,01...)

%i

Минута в двузначной числовой форме (00,01...)

%H

Час в двузначной 24-часовой числовой форме (00,01...)

%h

Час в двузначной 12-часовой числовой форме (00,01...)

%T

Время в 24-часовой форме (hh:mm:ss)

%r

Время в 12-часовой форме (hh:mm:ss AM|PM)

%W

День недели (Monday, Tuesday, Wednesday...)

%a

Сокращенное называние дня недели (Mon, Tue, Wed...)

%d

День месяца в двузначной числовой форме (01,02,03...)

%e

День месяца в числовой форме (1,2,3...)

%D

День месяца с порядковым суффиксом (1st, 2nd, 3rd...)

%M

Месяц (January, February...)

%b

Сокращенное название месяца (Jan, Feb...)

%Y

Год в четырехзначной числовой форме

%y

Год в двухзначной числовой форме

 

 

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

Полный перечень спецификаторов приведен в документации по MySQL www.mysql.com/doc/en/Date_and_time_functions.html#IDX1335.

В коде функции view_record() сценария для просмотра пользовательских запи+ сей (см. предыдущую главу) значение поля accessdate форматировалось с помощью следующих строк кода:

$accessdate = substr($query_data["accessdate"], 0, 4) . '-' . substr($query_data["accessdate"], 4, 2) . '-' . substr($query_data["accessdate"], 6, 2) . ' ' . substr($query_data["accessdate"], 8, 2) . ':' . substr($query_data["accessdate"], 10, 2) . ':' . substr($query_data["accessdate"], 12, 2);

которые генерировали значение даты и времени в следующем формате:

2004-01-22 10:31:35

Той же цели можно достичь с помощью одного запроса:

mysql> SELECT date_format(accessdate, '%Y-%m-%d %H:%i:%s')

 

-> FROM access_log WHERE userid='Dodge';

+----------------------------------------------

+

| date_format(accessdate, '%Y-%m-%d %H:%i:%s') |

+----------------------------------------------

 

 

+

| 2004-03-11

12:22:49

|

| 2004-01-25

16:41:33

|

+----------------------------------------------

 

 

+

2

rows in set

(0.00 sec)

 

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

mysql> SELECT accessdate, dayname(accessdate) FROM access_log -> WHERE userid='Dodge';

+----------------

 

+---------------------

+

| accessdate

| dayname(accessdate) |

+--------------------------------------

 

 

+

| 20040311122249

|Thursday

|

| 20040125164133

|Sunday

|

+----------------

 

+---------------------

+

2

rows in set (0.01 sec)

 

Серверная функция to_days() вычисляет общее количество дней с нулевого года нашей эры:

mysql> SELECT to_days(accessdate) FROM access_log

 

-> WHERE userid='Dodge';

+---------------------

 

+

| to_days(accessdate) |

+---------------------

 

+

|

732016

|

|

731970

|

+---------------------

 

+

2

rows in set (0.00 sec)

Предположим, что требуется узнать количество дней, прошедших после последне+ го посещения пользователем сайта:

mysql> SELECT userid, to_days(now()) -

to_days(accessdate)

 

-> FROM access_log GROUP BY userid

LIMIT 5;

+--------

+--------------------------------------

+

| userid | to_days(now()) - to_days(accessdate) |

+--------

+--------------------------------------

+

450 Глава 11

| Brian

|

7

|

| Dodge

|

0

|

| Greeny |

47

|

| Mac

|

49

|

| Nicrot |

47

|

+--------

+--------------------------------------

 

+

5 rows in set (0.01 sec)

 

 

Данный запрос в частности показывает, что пользователь Mac не посещал сайт 49 дней. Если это обстоятельство огорчает владельца сайта, то можно просто удалять пользо+ вателей, которые не посещали сайт более чем 48 дней. Это можно сделать с помощью следующего запроса:

mysql> DELETE FROM access_log WHERE to_days(now()) - to_days(accessdate) > 48; Query OK, 1 row affected (0.01 sec)

Выше приведены лишь простые примеры некоторых серверных MySQL+функций для обработки даты и времени. За более подробной информацией рекомендуется об+ ратиться к справочному руководству по MySQL на Web+сайте www.mysql.com.

Получение информации о таблицах в базе данных

Выяснение информации об используемой базе данных часто бывает настолько же важным, насколько важны сами данные, содержащиеся в базе. Например, нередко для принятия решения о следующей операции над таблицей необходимо узнать некото+ рые сведения об этой таблице. Сделать это несложно ++++++ получить информацию о таб+ лицах баз данных с помощью PHP так же просто, как получить сами данные из таблиц.

Для просмотра структуры таблиц базы данных предназначены следующие функции.

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

$result = mysql_list_fields("sample_db", "user");

Переменная $result теперь содержит указатель на список полей в таблице user. Пример использования данной функции будет представлен позднее.

mysql_num_fields(): принимает в качестве аргумента указатель на результат (возвращаемый предыдущей функцией) и возвращает общее количество полей результирующего множества, на которое ссылается данный указатель. Чтобы получить количество полей в таблице user, достаточно передать в функцию mysql_num_fields() указатель $result, полученный от функции mysql_list_fields():

$number_of_fields = mysql_num_fields($result);

Переменная $number_of_fields содержит (как и ожидалось) количество полей таблицы user.

msyql_field_name(), mysql_field_len() и mysql_field_type(): эти функции возвращают имя поля, длину поля и тип поля соответственно. Каждая

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

из функций принимает в качестве аргументов указатель на результирующее множество и индекс поля, определяющие таблицу и поле (отсчет полей начи+ нается с нуля) соответственно. Например, чтобы получить длину поля username в таблице user, сначала необходимо знать, что поле username ++++++ четвер+ тое поле таблицы и, следовательно, имеет индекс 3 (индексы начинаются с нуля), а затем можно использовать следующий код:

$username_length = mysql_field_len($result, 3);

Так как при определении поля username его длина была задана равной 30 симво+ лам, в результате выполнения данной функции переменная $username_length должна содержать число 30. Две другие функции работают почти так же.

mysql_field_flags(): принимает указатель на результирующее множество и индекс поля, а возвращает строку, содержащую атрибуты для заданного поля. Атрибутами поля могут быть NULL или NOT NULL, PRIMARY KEY, UNIQUE. Чтобы записать атрибуты поля username (таблицы user) в переменную $attributes, можно использовать следующий код:

$attributes = mysql_field_flags($result, 3);

Поле username имеет единственный атрибут ++++++ NOT NULL, поэтому переменная $attributes получит это значение.

Практика Получение информации о полях

Рассмотрим упомянутые выше функции в действии. Следующий сценарий, metadata.php, возвращает имя, длину и тип каждого поля, определенного в таб+ лице user:

<?php

include "./common_db.inc"; $link_id = db_connect();

$result = mysql_list_fields("sample_db", "user", $link_id);

for($i=0; $i < mysql_num_fields($result); $i++ ) { echo mysql_field_name($result,$i );

echo "(" . mysql_field_len($result, $i) . ")"; echo " - " . mysql_field_type($result, $i) . "<BR>";

}

?>

Результат работы данного сценария представлен на рис. 11.1.

Как это работает

Как обычно, сначала сценарий подключает файл с функциями для работы с базами данных (common_db.inc), а затем подключается к серверу, используя функцию db_connect():

include_once "./common_db.inc"; $link_id = db_connect();

После этого вызывается функция mysql_list_fields() с указанием базы дан+ ных, таблицы и идентификатора соединения с используемой базой данных (в рас+ сматриваемом случае sample_db, user и $link_id соответственно):

$result = mysql_list_fields("sample_db", "user", $link_id);

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