Занятие №5. Работа с базой данных MySQL Возьмем для примера следующую задачу. Нужно сделать базу с книгами, которые появились или скоро появятся в продаже, и которые вызывают интерес. Структура таблиц будет такой. Таблица описания книг BOOKS: id int(5) - уникальный id autoincrement primary key author char(60) - автор namebook text(100) - название книги series int(2) - id серии (если книга принадлежит серии) - для серий отдельная таблица edition int(2) - издание year int(4) - год издания isbn char(20) - ISBN pages int(4) - объем книги when_create int(2) - номер квартала how int(4) - предположительная цена status int(1) - id статуса: обязательно заказать, посмотреть подробнее и т.п. В качестве направлений развития проекта можно добавить серии книг, статусы, таблицу оглавлений и обложек (в blob-ах), комментарии к книгам и список интернет-магазинов, в которых книга была обнаружена. Для создания таблицы нам понадобится создать базу данных в MySQL (назовем ее тоже BOOKS) и в ней уже саму таблицу. Для этого необходимо: 1. Запустить сервис Denwer a. на рабочем столе запустить ярлык “Start Denwer”; b. в адресной строке браузера набрать http://localhost .Откроется страница настроек пакета Denwer; 2. На странице в разделе Утилиты нажать на ссылку Заведение новых БД и пользователей MySQL; 3. Ввести имя базы данных books, логин books. Ввести и подтвердить пароль. 4. Нажать на кнопку Создать БД и пользователя. 5. Вернуться в раздел Утилиты и нажать на ссылку phpMyAdmin. 6. В окне авторизации в поле пользователь ввести books и ниже указать пароль. 7. Выбрать базу данных books. 8. Перейти на вкладку SQL 9. Набрать запрос к базе данных на создание таблицы. create table books ( id int(5) not null primary key auto_increment, author char(60), namebook varchar(100), series int(2), edition int(2), year int(4), isbn char(20), pages int(4), when_create int(2), how int(4), status int(1) ); 10. Заполним таблицу содержимым, для этого необходимо выполнить запрос: insert into books ( id, author, namebook, series, edition, year, isbn, pages, when_create, how, status) values (null, "Р. Яргер и др.", "MySQL и mSQL. Базы данных для небольших предприятий и Интернета", 0, 0, 2000, "5-93286-010-3", 557, 3, 170, 0), (null, "Ларри УОЛЛ", "Программирование на Perl", 0, 3, 2001, null, 1200, 5, null, 0); Теперь напишем скрипт для нашей первой страницы. Комментарии к скрипту Даже в такой упрощенной форме код работы с mysql избыточен. Т.к. мы работает с одной базой, да еще и делаем единственный запрос, то вместо mysql_connect(), mysql_select_db() и mysql_query() достаточно было вызвать mysql_db_query(). Эта функция при необходимости выполнит коннекцию (в прочем, в этом она не одинока), выберет базу данных и выполнит запрос к базе. mysql_close() тоже необязательна, т.к. соединение с сервером будет автоматически закрыто при окончании скрипта. mysql_free_result() - освобождает память после запроса. Функции implode() и explode() относятся к строковым: explode() создает массив из фрагментов строки, разбирая ее как строку с разделителем, указанном в первом параметре. implode() делает обратную операцию. Эта пара применена для удобства - это проще, чем набирать строку в виде "...текст</th><th>текст..." и уж тем более проще, чем делать кучу echo с текстами, обрамленными тегами <th>/</th>. В скрипте постоянно используется функция DIE() с параметром "mysql_errno($link).mysql_error($link)". Функция DIE(текст) выводит текст в выходной поток (в HTML-код) и прерывает дальнейшее выполнение скрипта. В данном случае текст для DIE() формируется двумя функциями из группы mysql-функций: MYSQL_ERRNO() - код ошибки и MYSQL_ERROR() - текст ошибки. Оператор PHP "точка" конкатенирует строки. Необязательный параметр (здесь переменная $link) - идентификатор, возвращаемый функцией MYSQL_CONNECT() после соединения с сервером. Текст же ошибки, возвращаемый функцией MYSQL_ERROR(), выбирается из файлов, расположенных в подкаталоге "share" директории, в которой установлен MySQL. Секция PHP в файле открыта, как всегда, тегом "<?php". Далее объявляются переменные для работы с функциями MySQL (лучше такие переменные выносить в отдельные файлы и включать в скрипты, скажем, функцией REQUIRE() или INCLUDE()). Перед началом работы с MySQL выполняем соединение с сервером: $link=MYSQL_CONNECT($host,$user,$pass); К $host может быть приписан через двоеточие номер tcp-порта, который слушает сервер в надежде, что кто-нибудь его позовет. По умолчанию порт 3306. Изменяется это значение опять же в my.ini. Следующая функция - MYSQL_SELECT_DB(). Она имеет два параметра: первый - имя базы, и второй (необязательный) - id соединения ($link). Под необязательностью идентификатора соединения как параметра понимается следующее. Если параметр не указан, то используется последнее открытое соединение. А если ни одно соединение не открыто, то неявно выполняется connect (т.е. при использовании одного соединения MYSQL_CONNECT() явно вызывать не обязательно). Теперь формируем запрос к базе. Для этой цели используется функция MYSQL_QUERY() или MYSQL_DB_QUERY(). Разница между ними, как Вы, наверное, уже догадываетесь, заключается в том, что первая из них предполагает, что база данных уже выбрана, а вторая наряду с выполнением запроса осуществляет выбор базы. Параметры: MYSQL_QUERY(строка запроса [, $link]), где $link - идентификатор коннекта, возвращаемого функцией MYSQL_CONNECT(); MYSQL_DB_QUERY(база данных, строка запроса [, $link])). Как обычно, если не указан $link, то используется последнее выполненное соединение. Обе функции выполняют соединение с mysql-сервером (MYSQL_CONNECT()), ес- ли ранее не выполнено такое соединение. При этом неявный вызов MYSQL_CONNECT() осуществляется без параметров, используя в качестве имени хоста "localhost", а в качестве имени пользователя и пароля - пустые строки. И обе функции возвращают переменную (идентификатор ресурса), которую потом нужно использовать при обработке запроса (см. ниже). Например, mysql_select_db("books"); $result = mysql_query("select * from books"); или $result = mysql_db_query("books","select * from books"); Теперь самое интересное - обработка запроса. Эта операция осуществляется с помощью fetch-группы функций PHP: MYSQL_FETCH_ARRAY(), MYSQL_FETCH_FIELD(), MYSQL_FETCH_LENGTHS(), MYSQL_FETCH_OBJECT() и MYSQL_FETCH_ROW(), а также некоторыми дополнительными функциями (функций управления fetch-курсором, информационными функциями и пр.). Эти функции возвращают очередную строку выборки в виде массива или объекта, перемещая внутренний указатель на следующую строку. Поэтому их следует использовать в циклах. Сразу небольшое замечание. Среди mysql-функций в PHP есть MYSQL_RESULT(). Она возвращает значение одного столбца в указанной строке. В мануале рекомендуют вместо нее использовать более быстрые функции fetch-группы. Кроме того, по моему мнению, эта функция самая неудобная для работы с выбранными данными. Посему эту функцию я рассматривать не буду. В скрипте мы использовали функцию MYSQL_FETCH_ROW(). Итак, в результате выполнения одной из двух query-функций мы имеем указатель на ресурс выборки. Пусть сей указатель хранится в переменной $result. Тогда в таком цикле: while ($data=mysql_fetch_row($result)) { echo implode(" | ",$data), "<br>"; } можно вывести результаты запроса. Эта функция возвращает массив (здесь $data), в котором каждый элемент - поле строки выборки, возвращаемое select-ом в query-функции. Функция из string-группы IMPLODE() вернет строку, состоящую из элементов массива, указанного во втором параметре, разделенных разделителем - первым параметром. Теперь попробуем повторить вывод результатов запроса дважды (пример, конечно, надуманный, но на практике иногда требуется пройтись по результатам запроса более одного раза): echo "Первый раз"; while ($data=mysql_fetch_row($result)) { echo implode(" | ",$data), "<br>"; } echo "Второй раз"; while ($data=mysql_fetch_row($result)) { echo implode(" | ",$data), "<br>"; } После строки "Второй раз" мы ничего не увидим. Причина в том, что при каждом вызове fetch-функции внутренний указатель (курсор) автоматически переходит к следующей записи. Как только этот указатель доберется до конца выборки, fetch-функция вернет FALSE, и произойдет выход из цикла. Управлять указателем можно с помощью функции MYSQL_DATA_SEEK(). Параметры: id результата и номер строки, на которую надо установить указатель. Отсчет строк начинается с нуля. В последнем примере перед вторым циклом нужно было бы сказать mysql_data_seek($result, 0);