- •1. Цель работы
- •2. Основные технические возможности
- •3. Описание установки
- •4. Порядок выполнения работы
- •5. Содержание отчета
- •1. Цель работы
- •2. Основные теоретические положения
- •3. Описание лабораторного макета
- •4. Порядок выполнения работы
- •5. Указания к выполнению работы
- •1. Цель работы
- •2. Основные сведения
- •Incorrect table definition; There can only be one auto column and it mast be defined as a key
- •3. Программа работы
- •4. Указания к выполнению работы
- •1. Цель работы
- •2. Основные сведения
- •3. Программа работы
- •00 Проверка моего домена с именем Moy.Loc
- •4. Указания к выполнению работы
- •5. Содержание отчета
- •1. Цель работы
- •2. Основные сведения
- •3. Указания к выполнению работы
- •5. Примеры реализации тем
- •Insert into customers values
- •Insert into orders values
- •Insert into books values
- •Insert into order_items values (1, "0-672", 2), (2, "0-675", 1), (3, "0-675", 1), (3, "0-674", 1), (4, "0-673", 3);
Insert into customers values
214
(1, "Петр Петров", "пр. Мира д.7", "Москва"), (2, "Юлия Вонг", "ул. Шевченко д.1, кв 5", "Киев"),
(3, "Ян Дрибас", "пр. Зорь д.5, кв. 12 ", "Минск");
Insert into orders values
(NULL, 3, 69.98, "2009-12-02"), (NULL, 1, 49.00, "2009-12-15"), (NULL, 2, 74.98, "2009-12-19"), (NULL, 3, 24.99, "2010-02-01");
Insert into books values
("0-672", "Люк Морган", "Java 2 для профессионалов", 34.99),
("0-673", "Дж. Даун", "Инсталляция GNU/Linux", 24.99), ("0-674", "В. Дрибас", "Основы баз данных", 24.99), ("0-675", "М. Цаленко", "Алгебра баз данных", 49.99);
Insert into order_items values (1, "0-672", 2), (2, "0-675", 1), (3, "0-675", 1), (3, "0-674", 1), (4, "0-673", 3);
SET NAMES cp866; select * from customers; select * from orders; select * from books; select * from order_items;
Рис. 3.215. Исходные данные для вставки в базу данных books.
Для
ввода данных, представленных на рис.
3.215, создадим пакетный файл с именем
.
Местоположение файла показано на рис.
3.216.

Рис. 3.216. Местоположение командного файла INSxSQL.bat.
215
Состав
файла
приведен ниже (рис. 3.217 или рис. 3.218)

Рис. 3.217. Отображение файла INSxSQL.bat в редакторе Scite.

Рис. 3.218. Состав файла INSxSQL.bat.
Обратите внимание, что состав файла INSxSQL.bat и файла
соответствует
файлу Insmysql.bat, за исключением элемента
,
который подменяет имя вызываемого
SQL-сценария.
Использование подобного механизма подмены, позволяет вызывать сценарий Lab13_03.sql в работу с командной строки менеджера файлов следующим образом (рис. 3.219).

Рис. 3.219. Вызов INSxSQL.bat с параметром исполняемого файла.
Исполнение
занесет информацию в таблицы базы данных
Books, но на экране промелькнет только Dos
окно.
216
Посмотреть результат проделанной работы пакетного файла можно либо средствами PhpMyAdmin, либо через монитор MySql.
Например,
щелкнув мышкой на имени пакетного файла
в окне менеджера файлов (см. рис. 3.219) мы
получим приглашение в Mysql, после которого
укажем команду открытия базы данных
(use books;), установки кодировки CP866 (set names
cp866) и команду показа содержимого таблицы
(например, SELECT * FROMcustomers;)
(рис. 3.220).

Рис. 3.220. Вызов монитора MySQL и открытие базы.
Естественно, что в команде SELECT может быть указана любая необходимая нам таблица базы данных.
Для выполнения следующих тестов выйдите из Mysql, используя команду Exit.
Следующий пример показывает реакцию MySQL, если оператор ошибочно повторит ввод в командной строке информации
,
показанной на рис. 3.219.
По определению схемы (рис. 3.214) атрибут CustomerId в таблице Customers является ключевым (т.е. не допускает дубликатов хранимых значений атрибута), поэтому СУБД MySQL выдаст следующее сообщение:

Приведенное сообщение промелькнет в окне и прочитать его очень трудно. Чтобы увидеть и проанализировать данное сообщение необходимо вызвать командный процессор Cmd.exe (рис. 3.221).
217

Рис. 3.221. Вызов командного процессора.
Окно командного процессора представлено на рис. 3.222.

Рис. 3.222. Окно командного процессора с приглашением для ввода информации.
Если
в приглашении
ввести имя командного файла с параметром
имени исполняемого SQL сценария:
,
то ошибка, обнаруженная Mysql, останется на экране (рис. 3.223).

Рис. 3.223. Окно командного процессора с ошибкой ввода информации.
Следующий прием показывает применение текстового файла для контроля вводимой информации. Для удобства вычистим все таблицы базы данных, воспользовавшись средствами PhpMyadmin.(рис. 3.224).
218

Рис. 3.224. Окно PhpMyadmin с таблицей books базы данных books.
Используя
кнопку
(рис. 3.224) последовательно удалим все
записи из четырех таблиц базы данных.
Далее воспользовавшись командным процессором (см. рис. 3.221), введем в полученное приглашение следующую информацию:
insxsql.bat lab13_03ins.sql >1.txt

Рис. 3.225. Использование перенаправления в командной строке.
Содержимое файла 1.txt (имя может быть любое) (рис. 3.226) можно посмотреть через любой текстовый редактор.
219

Рис. 3.226. Результат работы командного файла в текстовом файле.
Как видно из рис. 3.226 содержимое файла 1.txt соответствует информации приведенной на рис. 3.215.
220
Тема № 13. Извлечение данных из базы данных Цель. Практическое использование конструкций SQL.
Задание 1. Оператор выборки данных SELECT
Оператор SELECT языка SQL извлекает данные из базы данных, выбирая из таблицы строки, которые отвечают заданному критерию поиска.
Основная форма оператора SELECT следующая (полное описание и использование языка SQL приведено в [7], в этой теме будут рассматриваться наиболее употребимые):
SELECT items FROM tables
[ WHERE condition ]
[ GROUP BY group_type ]
[ HAVING wnere_definition ] [ ORDER BY order_type ]
[ LIMIT Iimit_criteria ] ;
Рассмотрим каждую конструкцию, используя схему базы данных представленную на рис. 3.214. Выполнение данной темы предполагает, что
MySQL
запущен

.
Простейшим вариантом выборки данных Вы уже неоднократно пользовались, используя конструкцию SELECT * FROM tables (см. например рис. 3.220). Символ ―*‖ использовался для вывода всех столбцов искомой таблицы tables.
Если взамен символа ―*‖ использовать (через запятую) имена столбцов, то в результате подобного запроса Вы получите информацию только по тем столбцам, которые указаны в качестве элементов items.
Например, запрос (поиск):
SELECT name, city FROM customers ;
запрашивает данные столбцов name (имя) и city (город) таблицы Customers: Если воспользоваться монитором MySQL (вызов через пакетный файл
CmySql.bat - рис. 3.188), то ввод необходимых команд даст следующий результат, показанный на рис. 3.227.
Если воспользоваться средствами PhpMyAdmin для реализации этого запроса, то результат будет такой же, но изображение естественно будет другим (рис. 3.229).
Можно указывать столько столбцов таблицы, сколько необходимо, главное — вписать их по порядку после ключевого слова select. Кроме того, можно указывать и другие элементы, уточняющие выборку данных.
221

Рис. 3.227. Результат поиска (выборки) через монитор MySQL.

Рис. 3.228. Подготовка запроса в PhpMyAdmin через кнопку SQL.
Нажатие
кнопки
даст следующий результат:

Рис. 3.229. Результат поиска через PhpMyAdmin.
В следующих заданиях по данной теме результаты использования средств PhpMyAdmin в целях экономии места приводиться не будут. Также не будут указываться команды set names cp866 и use books при использовании монитора.
222
Задание 2. Извлечение данных по определенному критерию
Чтобы получить доступ к подмножеству строк в таблице, следует указать критерий выбора с помощью конструкции WHERE. Например,
SELECT * FROM orders WHERE customerid = 3;
выбирает все столбцы из таблицы заказов, но только из строк с customerid, равным 3.

Рис. 3.230. Результат поиска через монитор MySQL.
Конструкция WHERE устанавливает критерий выбора определенных строк. В нашем случае выбраны строки с customerid, равным 3. Одиночный знак равенства используется для проверки на равенство — обратите внимание, что это немного отличается от РНР, и если работать и с тем, и с другим, вполне можно запутаться.
Вдобавок к равенству, MySQL поддерживает целое семейство операторов и регулярных выражений. Наиболее употребимые в конструкции WHERE перечислены в таблице приведенной на рис. 3.231.
Примечание. Обратите внимание, что список далеко не полон, и если понадобится что-нибудь, отсутствующее в нем, обратитесь к руководству по MySQL.
Знаки операции сравнения для конструкции WHERE (рис. 3.231):
Операция
Название
Пример
Описание
(терм
(если
сравнения)
применимо)
=
равенство
custumerid = 3
Проверяет, являются ли два
значения равными
>
больше
amount>60.00
Проверяет, больше ли одно
значение другого
<
меньше
amount<60.00
Проверяет, меньше ли одно
значение другого
>=
больше или
amount>=60.00
Проверяет, больше или равно
равно
одно значение по отношению к
223
другому
<=
меньше
или
amount<=60.00
Проверяет, меньше или равно
равно
одно значение по отношению к
другому
!= или <>
не равно
quantity !=0
Проверяет, не равны ли два
значения. Пробел между ! и = не
допустим
IS NOT
адрес
не
Проверяет, имеет ли поле
NULL
равен нулю
значение
IS NULL
адрес равен
Проверяет, не имеет ли поле
нулю
значения
BETWEEN
величина
Проверяет, значение больше или
между
0
и
равно минимальному и меньше
60.00
или равно максимальному
IN
город
Проверяет,
содержится
ли
содержится
значение
в
определенном
множестве
NOT IN
город
не
Проверяет, не содержится ли
содержится
значение
в
определенном
множестве
LIKE
соответствие
name
like
Проверяет, отвечает ли зачение
("%Fred %")
образцу,
используя простые
механизмы соответствия SQL
NOT LIKE
соответствие
name
not
like
Проверяет, не соответствует ли
("%Fred %")
значение образцу
REGEXP
регулярное
name regexp
Проверяет, соответствует ли
выражение значение
регулярному выражению
Рис. 3.231. Операции сравнения для конструкции WHERE.
Три последних строки таблицы относятся к LIKE и REGEXP. Это формы соответствия образцу.
Операция LIKE использует простой механизм соответствия SQL. Образец может состоять из обычного текста плюс % (знак процента) для указания совпадения с любым количеством символов и _ (символ подчеркивания) для указания совпадения с одним символом. В MySQL соответствия не чувствительны к регистру. Например, 'Fred %' найдет любое значение, которое начинается с 'fred '.
Ключевое слово REGEXP используется для соответствия регулярных выражений. MySQL использует регулярные выражения в стиле POSIX. Вместо REGEXP можно применять и RLIKE, что является синонимом. Регулярные выражения POSIX также применяются и в РНР.
224
Можно проверять несколько критериев сразу, объединяя их операциями AND или OR. Например,

Рис. 3.232. Операции сравнения для конструкции WHERE.
Следующий запрос показывает выборку с использованием операции
BETWEEN.

Рис. 3.233. Операции сравнения для конструкции WHERE.
Запрос на совпадение с операцией LIKE

Рис. 3.234. Операции сравнения для конструкции WHERE.
Обратите внимание на следующий запрос:

Рис. 3.235. Результат с пустым ответом.
225
Задание 3. Извлечение данных из нескольких таблиц
Часто для получения ответа от базы данных на заданный вопрос могут потребоваться данные нескольких таблиц. Например, если необходимо узнать, кто из клиентов осуществлял в этом месяце заказы, придется просмотреть таблицы Customers (Клиент) и Orders (Заказ). Если нужно узнать, что конкретно они заказали, нельзя обойти вниманием и таблицу
Order_Items (Покупка).
Примечание. Эти данные находятся в разных таблицах, поскольку относятся к разным реальным объектам. Это один из принципов хорошей разработки базы данных.
Для объединения этой информации в SQL потребуется выполнить операцию, называемую соединением (join). Подразумевается соединение двух и больше таблиц с тем, чтобы сохранялись отношения между данными. Если, например, необходимо посмотреть, какие заказы сделал клиент Ян Дрибас, то сначала потребуется просмотреть таблицу Customers и найти в ней CustomerlD для клиента, после чего — таблицу Orders на предмет заказов, сделанных этим CustomerlD.
Хотя на первый взгляд операция соединения достаточно проста, на самом деле это один из наиболее сложных и тонких разделов SQL. В MySQL существует несколько разных типов соединения, каждый из которых предназначен для определенной цели.
Простое соединение двух таблиц
Начнем с поиска Ян Дрибас, которого мы уже упоминали:

Рис. 3.236. Результат запроса с использованием соединения таблиц.
Здесь стоит отметить несколько моментов.
Во-первых, для ответа на этот запрос необходима информация из двух таблиц, поэтому в списке перечислены обе.
226
Также мы определили тип соединения, возможно даже не зная его. Запятая между названиями таблиц эквивалентна словам INNER JOIN (внутреннее соединение) или CROSS JOIN (перекрестное соединение). Такой тип соединения еще называют полным объединением или Декартовым произведением таблиц. Это означает: "Возьми указанные таблицы и сделай из них одну большую. В большой таблице должна быть строка для любой возможной комбинации строк из каждой таблицы, указанной в списке, имеют они смысл или нет". Другими словами, получаем таблицу, в которой каждая строка таблицы Customers сопоставляется каждой строке таблицы Orders независимо от того, какой клиент сделал какой заказ.
В большинстве случаев смысла в этом немного. Как правило, нам нужны строки, которые в самом деле совпадают, т.е. когда конкретные заказы совпадают с теми клиентами, которые их производили.
Это достигается путем помещения в конструкцию WHERE условия соединения. Это особый тип условного оператора, который объясняет, какие атрибуты показывают отношения между двумя таблицами. В данном случае наше условие соединения было таким:
customers.customerid = orders.customerid
что предписывает MySQL выводить в таблицу с результатами только соответствия Customerid из таблицы Customers с CustomerlD из таблицы Orders.
Внеся это условие в запрос, мы получили объединение другого типа — соединение по равенству (equi-join - эквисоединение).
Обратите внимание на точечную нотацию, которой мы воспользовались для уточнения конкретного столбца конкретной таблицы.
Так, customers.customerid относится к столбцу customerid из таблицы Customers, a orders.customerid — к столбцу customerid
из таблицы Orders.
Точечная нотация необходима, когда имена столбцов неоднозначны, что случается, если одни и те же имена встречается в нескольких таблицах.
Как расширение его можно использовать для различения имен столбцов из разных баз данных. В нашем примере обозначение выглядит как table.column (таблица.столбец). Можно указать и иначе — database.table.column (база_данных.таблица.столбец), например, для проверки условия наподобие
books.orders.customerid = other_db.orders.customerid
227
С другой стороны, точечную нотацию можно применять и для всех ссылок на столбцы в запросе. Это частенько избавляет от лишней головной боли, особенно когда запросы становятся все более сложными. MySQL этого не требует, но удобочитабельные запросы — это не так уж и плохо. Если вы заметили, мы придерживаемся этого принципа во всех наших примерах, взять хотя бы вот такое условие customers.name = 'Ян Дрибас'.
Столбец name присутствует только в таблице customers, поэтому его необязательно указывать, но так, в общем-то, понятнее.
Соединение трех и более таблиц
Объединение более двух таблиц не сложнее объединения двух. Главное правило таково — таблицы нужно объединять попарно, учитывая условия объединения. Это можно представить в виде отношений данных между первой таблицей, второй и третьей.
Например, если требуется узнать, кто из клиентов заказал книги по Java, необходимо отследить эти отношения в рамках небольшого количества таблиц.
Необходимо будет найти клиентов, разместивших, по крайней мере, один заказ, который выражен в orderjtems книгой по Java. Из таблицы Customers перебираемся в таблицу Orders, используя customerid, как и в предыдущих случаях. Из таблицы Orders в таблицу Order_Items, используя orderid. Из Order_Items — в таблицу Books за нужной книгой, руководствуясь номером ISBN. После того как все связи установлены, можем запросить книги со словом Java в названии и получить в результате имена клиентов, которые купили какую-либо из этих книг.
Посмотрим на запрос, который приведет все это в исполнение: select customers . name
from customers, orders, order_items, books where customers.customerid = orders.customerid and orders.orderid = order_items.orderid
and order_items.isbn = books.isbn and books.title like '%Java%';
Этот запрос выдаст следующий результат:

Рис. 3.237. Результат запроса с использованием соединения таблиц.
В то же время запрос вида (рис. 3.238) даст пустой результат (Empty set):
228

Рис. 3.238. Результат запроса с неточным указанием аргумента поиска
.
Обратите внимание, что были отслежены данные из четырех разных таблиц, а чтобы сделать это с помощью соединения по равенству, понадобились три разных условия объединения. Обычно каждой паре таблиц требуется одно условие соединения, таким образом, количество условий соединения на единицу меньше количества объединяемых таблиц. Это правило большого пальца может пригодиться при отладке запросов, которые работают неустойчиво. Проверьте свои условия объединения и убедитесь в том, что вы все время следовали намеченному пути, от того, что вы уже знаете — к тому, что нужно узнать.
Задание 4. Поиск несоответствующих строк
Другой распространенный тип соединения в MySQL — объединение по остатку (левостороннее соединение – left join). В предыдущих примерах отбирались только те строки, в которых наблюдалось соответствие между таблицами. Однако могут потребоваться и строки, в которых нет соответствия — например, нужно найти клиентов, которые не сделали ни одного заказа, или книги, которые никто не заказывал.
Самый простой вариант ответа на такой вопрос в MySQL — использование левостороннего соединения, которое будет искать строки по указанному условию соединения двух таблиц. Если в указанной таблице нет подходящей строки, эта строка добавляется к результату, но с нулевым значением.
Пример:
select customers.customerid, customers.name, orders.orderid from customers left join orders
on customers.customerid = orders.customerid;
Рис. 3.239. Запрос с левосторонним соединением.
Данный запрос SQL использует объединение по остатку для таблиц Customers и Orders. Его синтаксис в отношении условий объединения несколько иной; условие соединения указывается в специальной конструкции ON оператора SQL.
229
Результат запроса приведен на рис. 3.240.

Рис. 3.240. Результат запроса с левосторонним соединением.
Чтобы раскрыть суть левостороннего соединения добавим в таблицу Customers (Клиенты) еще одну строчку.

Рис. 3.241. Состав таблицы Customers (Клиенты) после добавления.
Если повторить запрос показанный на рис. 3.239, то получим результат приведенный на рис. 3.242.
Результат показывает, что для клиента Иван Иванов нет соответствующего orderid, поскольку его orderid имеют значения
NULL.
Если необходимо найти исключительно тех клиентов, которые ничего не заказывали, этого можно достичь, проверив их на значение NULL в поле первичного ключа правой таблицы (в данном случае, orderid), поскольку строки с реальными значениями не могут иметь значение NULL (рис. 3.243)

230
Рис. 3.242. Результат левостороннего соединения таблиц Customers и Orders.
select customers.customerid, customers.name from customers left join orders
using (customerid)
where orders.orderid is null;
Рис. 3.243. Запрос левостороннего соединения таблиц Customers и Orders с использованием using.
И вот результат:

Рис. 3.244. Результат левостороннего соединения таблиц Customers и Orders с использованием using.
Вероятно, вы обратили внимание на то, что в этом примере условие соединения обладает несколько другим синтаксисом. Соединение по остатку воспринимает как синтаксис ON, как было в первом примере, так и USING, как было во втором. Синтаксис USING не предполагает указания таблицы атрибута соединения, и по этой причине, если вы хотите пользоваться таким синтаксисом, столбцы в обеих таблицах должны называться одинаково.
231
Задание 5. Использование псевдонимов имен таблиц (AS)
Часто бывает очень удобно, а порой и необходимо обращаться к таблицам под другими именами. Такие имена называются псевдонимами (aliase). Их можно создать в самом начале запроса, а потом пользоваться по мере необходимости. Псевдонимы очень удобны, все равно, что ярлык на рабочем столе. Если запрос, показанный на рис. 3.245 переписать с использованием псевдонимов (рис. 3.2460), то его объем становится меньше.
select customers . name
from customers, orders, order_items, books where customers.customerid = orders.customerid and orders.orderid = order_items.orderid
and order_items.isbn = books.isbn and books.title like '%Java%';
Рис. 3.245. Запрос без использования псевдонимов.
Указывая таблицы, в фразе FROM, мы за именем таблицы вставляем конструкцию as, присваивая таблице псевдоним (короткое имя).
select с.name
from customers as с, orders as о, order_iterns as oi, books as b where с.customerid = о.customerid
and о.orderid = oi.orderid and oi.isbn = b.isbn
and b.title like '%Java%' ;
Рис. 3.246. Запрос с использованием псевдонимов.
Кроме того, псевдонимы можно давать столбцам, однако к этому мы вернемся после того, как рассмотрим обобщенные функции.
Табличные псевдонимы необходимы в случае соединения таблицы с самой собой. А такой подход очень удобен для поиска строк в той же таблице, в которой есть одинаковые значения. Если требуется найти клиентов, живущих в одном городе, скажем, с целью создания читательского клуба, можно присвоить одной и той же таблице Customers два разных псевдонима:
select sl.name, s2.name, sl.city
from customers as sl, customers as s2 where sl.city = s2.city
and sl.name != s2.name;
Рис. 3.247. Запрос с использованием 2-х псевдонимов на одной таблице.
Чтобы раскрыть суть соединения таблицы самой с собой, добавим в таблицу Customers (Клиенты) еще одну запись (рис. 3.248).
232

Рис. 3.248. Запрос на добавление нового клиента.
Далее исполним запрос на самосоединение таблиц:

Рис. 3.249. Список клиентов из одного города.
Мы делаем вид, что таблица Customers — это на самом деле две разные таблицы, sl и s2, и выполняем соединение по столбцу City. Второе условие, sl.name != s2.name, необходимо для того, чтобы в результате запроса не выдавалось соответствие клиента самому себе.
Резюме по типам соединениий
Мы рассмотрели только самые основные, хотя существуют еще несколько соединений, представленных в таблице на рис. 3.250.
Название
Описание
Декартово
Все комбинации всех строк во всех таблицах. В случае
произведение
применения между именами таблиц ставят запятые и не
употребляют конструкцию WHERE.
Полное
Аналогично предыдущему.
соединение
Перекрестное
Аналогично предыдущему. Также может использоваться с
соединение
указанием ключевых слов CROSS JOIN между названиями
объединяемых таблиц.
Внутреннее
Семантически эквивалентно запятой. Может использоваться
соединение
с указанием ключевых слов INNER JOIN. Без условия
233
WHERE эквивалентно полному объединению. Обычно при
истинно внутреннемобъединении задается условие WHERE.
Соединение
Использует условное выражение со знаком = для
по равенству
Соответствия в объединении строк из разных таблиц. В SQL
в этом объединении применяется конструкция WHERE.
Соединение
Старается уравнивать строки в таблицах и выискивает
по
несовпадающие строки со значениями NULL. В SQL
остатку
используется с ключевыми словами LEFT JOIN.
Предназначено для поиска отсутствующих значений.
Аналогично можно употреблять RIGHT JOIN.
Рис. 3.250. Типы соединеий в MySQL.
Задание 6. Извлечение данных в определенном порядке
Если строки, извлеченные по запросу, должны перечисляться в определенном порядке, для этого используется конструкция ORDER BY оператора SELECT. Эта особенность удобна для представления результатов запроса в удобочитабельном формате.
Конструкция ORDER BY применяется для сортировки строк в столбцах, указанных в конструкции SELECT. Например,
select name, address from customers order by name ;
Рис. 3.251. Сортировка результата с помощью ORDER BY в MySQL.

Рис. 3.252. Результат сортировки результата с помощью ORDER BY.
Такой запрос представит имена клиентов в алфавитном порядке по именам name.
Примечание. Обратите внимание, что в таком случае, поскольку имена состоят из имени и фамилии, отсортированы они будут по имени. Если вы хотите сортировки по фамилии (которая стоит второй), нужно, чтобы имя и фамилия хранились в двух разных полях.
234
По умолчанию порядок сортировки идет по возрастанию (от а до z или по возрастанию числовых значений). Это можно указать ключевым словом
ASC (от англ, ascending):
select customerid,address, name from customers
order by address asc;

Рис. 3.253. Результат сортировки результата с помощью ORDER BY ASC.
Изменить порядок сортировки на обратный можно с помощью другого ключевого слова — DESC (от англ, descending):
select address, name from customers
order by address desc;

Рис. 3.254 13.27. Результат сортировки результата с помощью ORDER BY DESC.
Сортировать можно и по нескольким столбцам. Вместо названий можно использовать псевдонимы столбцов, и даже их порядковые номера (например, 3 — для третьего столбца в таблице) см. [7].
235
Задание 7. Группировка и агрегирование данных
Нередко необходимо подсчитать, сколько строк присутствует в определенном наборе, или каково среднее значение какого-нибудь столбца
— скажем, средняя цена каждого заказа. В MySQL имеется набор функций агрегирования, которые неплохо подходят для выполнения задач подобного рода.
Эти функции агрегирования можно применять как для таблицы в целом, так и для групп данных внутри таблицы.
Наиболее часто используемые функции перечислены в таблице показанной на рис. 3.255.
Название
Описание
AVG (столбец)
Средняя величина значений в определенном столбце.
COUNT
При указании столбца выдается количество числовых
(элементы)
ненулевых) значений в этом столбце. Если перед
названием столбца вставить слово DISTINCT, выдается
только количество конкретных значений в столбце.
Если указать COUNT (*) — подсчет строк будет
производиться независимо от нулевых значений.
MIN (столбец)
Минимальное значение в столбце.
МАХ (столбец)
Максимальное значение в столбце.
STD (столбец)
Стандартное отклонение значений в столбце.
SUM (столбец)
Сумма значений в столбце.
Рис. 3.255. Функции агрегирования в MySQL.
Взглянем на несколько примеров, начиная с AVG. Среднюю величину всех заказов можно высчитать так:
select avg (amount) from orders;

Рис. 3.256. Результат AVG по столбцу amount таблицы orders.
Чтобы получить более детальную информацию, можно воспользоваться конструкцией GROUP BY. Это позволит посмотреть среднюю величину заказа по группам, например, по номеру клиента, что даст информацию о том, кто из клиентов делает самые крупные заказы:
236
select customerid, avg (amount) from orders
group by customerid;
При использовании конструкции GROUP BY с функцией агрегирования это фактически меняет поведение функции. Вместо того чтобы выдавать среднюю величину заказов в таблице, такой запрос даст информацию по средней величине заказа каждого клиента (а если точнее,
каждого customerid)

Рис. 3.257. Результат AVG с группировкой по Клиентам.
Единственное, что стоит отметить при использовании функций группировки и агрегирования: если используется функция агрегирования или конструкция GROUP BY в ANSI SQL, в конструкции SELECT будут присутствовать только функции агрегирования и столбцы, указанные в конструкции GROUP BY. Если требуется использовать столбец в конструкции GROUP BY, он должен быть указан в конструкции SELECT.
На самом деле MySQL обеспечивает гораздо большую свободу действий, поддерживая расширенный синтаксис, который дает возможность убирать ненужные элементы из конструкции SELECT.
Вдобавок к группировке и агрегированию данных есть все шансы проверить результат агрегирования с использованием конструкции HAVING. Она следует сразу после конструкции GROUP BY и похожа на WHERE, но только применяется к группам и множествам.
Чтобы расширить предыдущий пример, скажем, получением информации, кто из клиентов произвел заказ в среднем больше чем на $50, можем воспользоваться следующим запросом:
select customerid, avg (amount) from orders
group by customerid having avg (amount) > 50;
237
Заметьте, конструкция HAVING обращается к группам. Такой запрос выдаст следующий результат:

Рис. 3.258. Результат AVG с группировкой по HAVING.
Выбор количества отображаемый строк
Одна конструкция оператора SELECT, которая может оказаться особенно полезной в Web-приложениях — это конструкция LIMIT. Ее используют для указания, сколько строк результата следует отображать. Необходимы два параметра: номер строки, с которой следует начать, и количество строк.
Следующий запрос иллюстрирует применение LIMIT: select name, address, city
from customers limit 2, 3;
Запрос можно интерпретировать так: "Выбрать имена среди клиентов, в результате отобразить три строки, начиная со строки 2". Не забывайте, что нумерация строк начинается с нуля.

Рис. 3.259. Результат применения LIMIT.
Это очень удобная конструкция для Web-приложений. Ее принцип точно такой же, как и в случае, когда покупатель листает каталог и хочет видеть на одной странице только 10 пунктов.
Примечание. Обратите внимание, что LIMIT в стандарте ANSI SQL отсутствует, потому его использование приводит к несовместимости кода со многими реляционными СУБД.
238
Задание 8. Обновление записей в базе данных (UPDATE)
Помимо того, что данные необходимо извлекать из базы данных, их еще необходимо периодически обновлять. Например, иногда требуется повысить цены на книги в базе данных. Это можно сделать, используя оператор UPDATE.
Типовая форма этого оператора выглядит так:
UPDATE tablename
SET columnl=expressionl, column2=expression2, [WHERE condition]
[LIMIT number]
Основная идея заключается в обновлении таблицы с именем tablename, изменяя каждый указанный столбец column соответствующим выражением expression. Конструкцией WHERE UPDATE можно ограничить до работы с определенными строками, а конструкцией LIMIT обозначить количество строк, которые нужно обновить.
Давайте рассмотрим несколько примеров.
Если мы хотим повысить цену всех книг на 10%, можно воспользоваться оператором UPDATE без конструкции WHERE:
Исходное состояние таблицы BOOKS приведено ниже.

Рис. 3.260. Состояние таблицы BOOKS до модификации данных.
update books
set price=price * 1.1;

Рис. 3.261. Состояние таблицы BOOKS после модификации данных.
239
Если же требуется изменить одну строку, скажем, адрес некоторого клиента, можно поступить таким образом:
update customers
set address = 'ул. Победы д.7, кв.7' where customerid = 4;
Так, например, состояние таблицы показанное на рис. 3.248 будет приведено к виду представленному на рис 3.262.

Рис. 3.262. Результат модификации данных в таблице Customers.
240
Задание 9. Изменение таблиц после создания (ALTER TABLE)
Кроме обновления данных в строках, может потребоваться изменить структуру самой таблицы в базе данных. Для этого применяется очень гибкий оператор ALTER TABLE. Базовая его форма такова:
ALTER TABLE tablename alteration [, alteration ...]
В ANSI SQL один оператор ALTER TABLE может осуществить только одно преобразование, а вот в MySQL подобных ограничений нет. Разные конструкции преобразования могут изменять разные аспекты таблицы.
Типы преобразования, осуществляемые оператором ALTER TABLE, перечислены в таблице на рис. 3.263.
Синтаксис
Описание
ADD [COLUMN] column_description
Добавить столбец в указанное место
[FIRST | AFTER column ]
(если место не указано, столбец
добавляется в конец). Обратите
внимание,
column_description
требует имени и типа, точно так же,
как при работе с оператором
CREATE.
ADD [COLUMN]
Добавить
один
или
несколько
(column_description,column_description,
столбцов в конец таблицы.
...)
ADD INDEX [index] (column,
Добавить
индекс
в
указанный
...)(столбцы) таблицы.
столбец
ADD PRIMARY KEY (column, ...)
Сделать указанный столбец (ы)
первичным ключом таблицы.
ADD UNIQUE [index] (column, ...)
Добавить
уникальный
индекс в
(столбцы) таблицы.
указанный столбец
ALTER [COLUMN] column {SET
Добавить или удалить значение по
DEFAULT value \ DROP DEFAULT}
умолчанию определенного столбца.
CHANGE [COLUMN] column
Изменить столбец с именем column
new_column_description
так, чтобы он получил указанное
описание. Это можно использовать
для изменения имени столбца,
поскольку
column_description
включает в себя имя.
MODIFY [COLUMN]
Похоже на CHANGE. Используется
column_description
для изменения типов столбцов, но
не имен.
DROP [COLUMN] column
Удалить указанный столбец.
DROP PRIMARY KEY
Удалить первичный индекс (не
столбец!).
241
DROP INDEX index
Удалить указанный индекс.
RENAME[AS] new_table_name
Переименовать таблицу. в операторе
ALTER TABLE
Рис. 3.263. Возможные преобразования оператором ALTER TABLE.
Рассмотрим наиболее типичные случаи употребления ALTER TABLE. Частенько случается так, что Вы вдруг осознаете: какой-то столбец "недостаточно велик", чтобы вместить в себе необходимые данные. Например,в нашей таблице Customers имена и фамилии могут иметь длину до 30 символов. И вскоре может оказаться, что некоторые имена и фамилии слишком длинны и сохраняются в таблице в искаженном виде. Однако это можно исправить, изменив тип данных столбца, после чего он сможет принимать имена и фамилии длиной до 35 символов.
alter table customers
modify name char(35) not null;
Другая часто встречающаяся необходимость связана с добавлением столбца. Представьте, что в каждом регионе существует свой налог с продаж, поэтому магазину приходится учитывать этот налог, но делать это раздельно, поскольку он везде разный. В таблицу Orders потребуется добавить столбец налога:
alter table orders
add tax float(6,2) after amount;
В мониторе результат добавления столбца и состав столбцов таблицы
Orders:

Рис. 3.264. Модифицированный состав структуры таблицы Orders.
Иногда какой-нибудь столбец может оказаться лишним. Удалим столбец, который мы только что добавили:
alter table orders
242
drop tax;
Задание 10. Удаление записей, таблиц и базы данных (DELETE)
Удалять строки из базы данных производится оператором DELETE, который выглядит следующим образом:
DELETE FROM table
[WHERE condition] [LIMIT number]
Если просто записать
DELETE FROM table;
то удаляются все строки в таблице, так что будьте осторожны! Обычно ненужными оказываются какие-то определенные строки и они указываются при помощи конструкции WHERE. Это может случиться, если какая-то книга больше не продается или кто либо из клиентов длительное время ничего не заказывает:
delete from customers where customerid=5;
Ниже (на рис. 3.265) приводится окно монитора с использованием оператора DELETE и результат его работы.

Рис. 3.265. Состав таблицы Customers после удаления пятой строки.
Конструкция LIMIT ограничивает количество удаляемых строк.
Удаление таблиц
Для этого используют оператор DROP TABLE.
DROP TABLE table;
Он удаляет все строки из таблицы и вместе с ними саму таблицу, так что будьте с ним поосторожней.
243
Удаление целой базы данных
Удаление базы данных осуществляется оператором - DROP DATABASE:
DROP DATABASE database;
В результате удаляются все строки, таблицы, индексы и сама база данных.
Дополнительная информация
В этой теме был рассмотрен обычный SQL, с которым приходится иметь дело при работе с базами данных MySQL.
Если хотите получить дополнительную информацию по SQL, обратитесь к истокам, почитайте о стандартах ANSI SQL, обратившись по адресу: http://www.ansi.org/
Дополнительные возможности MySQL по сравнению с ANSI SQL описаны на Web-сайте MySQL: http://www.mysql.com/.
244
Тема № 14. PHP и MySQL. Доступ к базе данных MySQL из Web с помощью РНР
Цель работы: Получение практических навыков по связке MySQL и
PHP.
В заданиях данной темы используется база данных BOOKS, схема которой представлена на рис. 3.171, создание таблиц осуществлено с помощью SQL-сценария показанного на рис. 3.174. Вы узнаете, как используя PHP читать базу и вносить в нее данные, и как фильтровать потенциально опасные входные данные.
теме рассматриваются следующие вопросы:
Как работает архитектура Web-баз данных
Основные шаги выполнения запросов к базе данных через Web
Установка соединения
Получение информации о доступных базах данных
Выбор базы данных
Выполнение запроса к базе данных
Получение результатов запроса
Отсоединение от базы данных
Внесение новой информации в базу данных
Обеспечение безопасности базы данных
Прочие полезные функции PHP-MySQL
Задание 1. Изучение работы архитектуры Web-баз данных
Ранее мы в общих чертах выяснили, как работает архитектура Web-баз данных. Алгоритм работы содержит следующие шаги:
Web-браузер пользователя выдает HTTP-запрос определенной Web-страницы. Например, пользователь ищет в таблице BOOKS, все книги, используя HTML-форму (рис. 3.266), исходный код HTML файла Lab15_00.php (рис. 3.267). Страница с результатами поиска будет называться Lab15_01.php (обработчик формы).
Web-сервер принимает запрос на Lab15_01.php, извлекает этот файл и передает на обработку механизму РНР.
Механизм РНР приступает к разбору сценария. Сценарий содержит команду соединения с базой данных и выполнения запроса (поиска книг). РНР открывает соединение с MySQL-сервером и отправляет соответствующий запрос.
Сервер MySQL принимает запрос к базе данных, обрабатывает его и отправляет результат (список книг) обратно механизму РНР.
Механизм РНР завершает выполнение сценария, что обычно включает в себя форматирование результатов запроса в HTML файл. После этого результат в виде HTML возвращается Web-серверу.
245
6. Web-сервер пересылает HTML в браузер, и пользователь имеет возможность просмотреть запрошенный список книг.
База данных MySQL с именем BOOKS создана в предыдущей лабораторной работе, поэтому создадим поисковую HTML форму и подготовим код РНР для обработки формы, чтобы проиллюстрировать шаги алгоритма работы архитектуры Web-баз данных.
Начнем с поисковой HTML формы (рис. 3.266). Код для этой формы показан на рис. 3.267 (http://localhost/php/lab15_00.php).
Поисковая страница для базы данных BOOKS:

Рис. 3.266. Начальное содержимое формы (а) и форма с информацией (б).

Рис. 3.267. Листинг Lab15_00.php HTML формы для рис. 3.266.
246
После
того как пользователь нажмет на кнопке
,
вызывается сценарий Lab15_01.php. Все это
представлено в листинге (рис. 3.268). Здесь
мы рассмотрим, что делает упомянутый
сценарий и как он работает.

Рис. 3.268. Листинг сценария обработчика Lab15_01.php формы для рис. 3.266.
247
Lab15_01.php - извлекает результаты запроса в базе данных MySQL и форматирует их для целей отображения.
Если в форму будет введена информация, как показано на рис. 3.266 (б), то результат показан на рис. 3.269.

Рис. 3.269. Результат вывода на экран обработчика Lab15_01.php
Если пользователь в качестве аргумента поиска укажет символ ―М‖ (рис. 3.270), то результат показан на рис. 3.271.

Рис. 3.270. Исходные данные для обработчика Lab15_01.php

Рис. 3.271. Результат вывода на экран обработчика Lab15_01.php
Установка соединения
Для подключения к серверу MySQL в сценарии (рис. 3.268) присутствует такая строка:
@ $db = mysql_pconnect($Host, $User, $Password);
248
Потребуется указать имя узла (Host), на котором размещен сервер MySQL, имя пользователя (User), чтобы войти в него, и пароль (Password). Все это в принципе необязательно и если не указать все вышеперечисленное, функция воспользуется значениями по умолчанию — локальная машина вместо узла, имя пользователя, под которым запущен РНР, и пустой пароль.
В случае успеха функция вернет идентификатор связи с базой данных (который следует сохранить для дальнейшего использования), а в случае неудачи — значение false. Результат не стоит игнорировать, поскольку без соединения с базой данных работа невозможна. Это делает следующий код:

Как альтернативу, можно использовать другую функцию, которая делает практически то же самое — mysql_connect(). Единственное отличие состоит в том, что mysql_pconnect() устанавливает постоянное соединение с базой данных.
Обычное соединение с базой данных закрывается, когда сценарий завершает свое выполнение или когда обращается к функции mysql_close(). Постоянное соединение остается открытым и после того, как сценарий выполнен, а функцией mysql_close() его закрыть нельзя.
Может возникнуть вопрос, для чего это нужно. Ответ таков: соединение с базой данных предполагает некоторые непроизводительные затраты, что требует времени. Когда вызывается mysql_pconnect(), прежде чем она попытается подключиться к базе данных, она автоматически проверит, нет ли уже открытого постоянного соединения. Если есть, она не станет открывать новое. Это и время экономит, и предотвращает перегрузку сервера.
Однако если РНР выполняется как CGI, то постоянное соединение окажется не таким уж и постоянным. (Каждый вызов сценария РНР запускает новую копию механизма РНР и закрывает ее, когда сценарий завершает свою работу. Это, в свою очередь, также закрывает любое постоянное соединение.)
Помните, что количество соединений в MySQL, которые существуют одновременно, ограничено. Границу устанавливает параметр max_connections. Его задача (как и родственного ему параметра Apache MaxClients) — заставить сервер отвергать новые запросы на соединение,
249
когда ресурсы узла заняты или когда программное обеспечение не функционирует.
Значения этих параметров можно изменять, редактируя файл конфигурации. Чтобы настроить MaxClients в Apache, следует править файл httpd.conf. Настройка max_connections в MySQL осуществляется за счет редактирования файла my.conf. Если вы пользуетесь постоянными соединениями, и практически каждой странице на вашем сайте требуется доступ к базе данных, вам понадобится постоянное соединение для каждого процесса Apache. Если же используются значения параметров, принятые по умолчанию, могут возникнуть определенные сложности. По-умолчанию Apache допускает до 150 соединений, a MySQL — только 100. В особо напряженное время соединений может не хватить. Поэтому лучше всего настроить параметры так, чтобы у каждого процесса Web-сервера было свое соединение, конечно, с оглядкой на технические возможности применяемых аппаратных средств.
Выбор базы данных
Работая с MySQL из командной строки (см. предыдущею лабораторную работу), необходимо указывать, какая база данных нужна:
use books;
То же самое необходимо и при подключении из Web. Это может сделать РНР-функция

В результате будет использоваться база данных с именем BOOKS. Можно также использовать соединение с базой данных, для которого требуется выполнить эту операцию (в нашем случае $db), однако, если его не указать, будет использоваться последнее открытое соединение. Если открытое соединение не существует, оно открывается по умолчанию, как если бы вызывалась mysql_connect().
Выполнение запроса к базе данных
Чтобы осуществить запрос, можно воспользоваться функцией mysql_query(). Однако прежде запрос необходимо настроить:

В этом случае будет отыскиваться значение, введенное пользователем ($term), в поле, которое указал пользователь ($search). Вы, наверное, обратили внимание на то, что мы употребили like, отдав ему предпочтение перед equal — толерантность никогда не бывает излишней.
250
Не забывайте, что запрос, отправляемый вами в MySQL, не требует в конце точки с запятой, в отличие от запроса, который вводится в среде монитора MySQL.
Теперь можно выполнить запрос:

В функцию передается запрос, который должен быть выполнен; можно также передать еще и соединение с базой данных (в нашем случае $db). Если его не указать, будет использоваться последнее открытое соединение. Если такового нет, функция откроет соединение точно так же, как при выполнении mysql_connect().
Возможно, вместо функции mysql_query() воспользоваться функцией mysql_db_query(). Рассмотрим ее прототип:
int mysql_db_query(string database, string query, [int database_connection] ) ;
Почти то же самое, только здесь можно указать базу данных, в которой требуется производить поиск. В каком-то смысле это комбинация функций mysql_select_db() и mysql_query().
Обе функции возвращают идентификатор результата (что позволяет получить результаты поиска) в случае успеха и значение false в случае неудачи. Идентификатор результата следует сохранить (так же, как в нашем случае с $result), чтобы извлечь из него некоторую пользу.
Получение результатов запроса
Разнообразие функций дает возможность получить результат различными способами. Идентификатор результата — это ключ доступа к строкам, возвращенным запросом, которых может быть нуль, одна и более.
В нашем примере использовались две функции: mysql_num_rows()

и mysql_fetch_array().

Функция mysql_numrows() сообщает количество строк, которые возвращает запрос. В нее следует передать идентификатор результата.
Это полезно знать, если планируется обрабатывать или отображать результаты. Зная их количество, можно организовать цикл:
251
for ($i=0; $i <$num_results; $i++num ){
// обработка результатов
}
На каждой итерации цикла происходит вызов mysql_fetch_array(). Цикл не будет выполняться, если нет строк. Эта функция берет каждую строку из списка результата и возвращает ее в виде ассоциативного массива, с ключом как именем атрибута и значением как соответствующим значением массива:
$row = mysql_fetch_array($result);
Имея $row в ассоциативном массиве, можно пройти каждое поле и должным образом его отобразить:

Задание 2. Проверка и фильтрация данных, исходящих от пользователя. Использование объектно-ориентированного синтаксиса PHP
Представленный на рис. 3.268 обработчик ввода в форму на рис. 3.266, обладает рядом недостатков, которые проявляются в процессе эксплуатации системы. Преобразуем форму на рис. 3.266 к виду показанному на рис. 3.272 (http://localhost/php/lab15_02.php).

Рис. 3.272. Модифицированная форма ввода информации.
252
В
форме показанной на рис. 3.272(a) добавлена
кнопка
,
а на рис. 3.272(б) для примера раскрыт список
типов возможного поиска.
Код HTML формы для рис. 3.272, отличается от кода формы представленного на рис. 3.267 строкой объявления добавления кнопки (рис. 3.273):

Листинг кода формы для рис. 3.272:

Рис. 3.273. Код HTML создания формы. Файл Lab15_02.php.
Обработчик приведенной формы представлен в файле Lab15_03.php, содержимое которого показано на рис. 3.274.
Листинг обработчика HTML формы (файл Lab15_03.php).

253

254

Рис. 3.274. Код обработчика формы. Файл Lab15_03.php.
Если
пользователь нажмет кнопку
,
то сработает условие в строке 16 и будет
сформирован запрос к базе в виде следующей
строковой переменной (строка 18, рис.
3.274):

На основании этого запроса будет сформирован ответ, показанный на рис. 3.275.

Рис. 3.275. Результат запроса на показ всех книг.
255
Если
пользователь нажмет кнопку
(рис. 3.272(a)), и не заполнит поле для ввода
информации:
,
то сработает условие в строках 19, 20
обработчика формы (рис. 3.274):
и
будет сформировано следующее сообщение
для пользователя (строка 21-24, рис. 3.274):

Рис. 3.276. Результат запроса без указания аргумента поиска.
В
операторе вывода сообщения на экран
(для закрепления материала по использованию
тегов в PHP) использован тег установки
цвета (font
color=‖red‖),
перевода строки (br)
и тег вывода жирного шрифта
(strong).

Ниже приведен пример заполненной формы и результат работы обработчика формы.

Рис. 3.277. Результат запроса c указанием аргумента поиска.
256
Для того чтобы обработчик корректно обрабатывал вводимые значения пользователя, в теле обработчика использован ряд стандартных функций и приемов PHP.
В начале необходимо объявить все переменные использованные в программе, во избежании фокусов со стороны используемых браузеров.

Напомним, что для доступа к переменным можно использовать также глобальный массив с именем $_REQUEST.
Далее необходимо убрать все лишние пробелы по краям слова, которые мог случайно набрать пользователь в поисковом значении переменной term. Для этого использована функция trim(), применяемая к переменной term (критерий поиска).

Следующий этап — убедиться, что пользователь указал критерий и тип поиска. Заметьте, это проверяется лишь тогда, когда критерий поиска не содержит лишние пробелы. Если поменять эти этапы местами, может возникнуть ситуация, когда критерий вроде и введен, сообщения об ошибке быть не должно, однако критерий содержит только пробелы, которые полностью удаляются функцией trim().
этом случае выдается сообщение о том, что критерий поиска не введен (рис. 3.276). Мы проверили переменную $search (имя поля по которому ведется поиск) даже в том случае, когда она поступает из оператора SELECT. Вас может заинтересовать, зачем проверять входные данные. Не забывайте, что база данных может иметь не один интерфейс. Например, фирма по продаже книг может располагать большим количеством филиалов, которые используют свои поисковые интерфейсы. Вследствие того, что пользователи могут заходить с разных рабочих станций, возникает и потенциальная угроза безопасности.
случае задействования данных, которые вводят другие пользователи, необходимо тщательно фильтровать вводимые данные от управляющих символов. Для этого используются стандартные функции addslashes() и stripslashes(). Если записывать данные, введенные пользователем, в базу данных типа MySQL, следует вызывать addslashes(), а при возврате пользователю выходных данных — stripslashes().
257
В нашем случае к критерию поиска применяется функция addslashes():

К данным, исходящим из базы, применяется stripslashes(). Введенные данные не содержат косых линий, равно как и управляющих символов. То есть вызов stripslashes() не поможет. При построении Web-интерфейса для базы данных велики шансы того, что потребуется вносить данные о новых книгах, а детали, внесенные пользователем, могут содержать специальные символы. Сохраняя их в базе данных, мы обращаемся к addslashes(), а это означает, что при извлечении данных необходимо будет вызывать stripslashes().
Функцию htmlspecialchars() применяют для кодировки символов, которые имеют специальное значение в HTML. В наших тестовых данных нет амперсандов (&), знаков "меньше" (<), "больше" (>), двойных кавычек ("), однако в названиях многих книг может повстречаться амперсанд. Использование этой функции застраховывает от грядущих ошибок.
Как уже упоминалось, stripslashes() вызывают для того, чтобы "подчистить" значение, прежде чем отображать его пользователю, иначе косые черты будут видны на экране.
В нашем примере в обработчике (Lab15_03.php, рис. 3.274) использована функция get_magic_quotes_gpc (), которая указывает, выполняется ли автоматическое взятие в кавычки. Буквы ―gpc‖ в имени функции (директивы) означают GET, POST и COOKIE. Это означает, что все переменные, поступающие из упомянутых источников, автоматически помещаются в кавычки.

Установка соединения в объектно–ориентированном PHP
В данном задании применяется синтаксис объектно-ориентированного PHP, в отличие от процедурного, использованного во всех предыдущих заданиях.
Если
пользователь нажмет кнопку
(рис. 3.272(a)), и заполнит поле для ввода
информации, то будет сформирована строка
запроса $query:

258
Сконструированное значение переменной $query, далее используется
для получения результата (строка 45, рис. 3.274
или строка 45 в файле
Lab15_03.php), сформированного операцией (методом)
экземпляра объекта класса
, который
создается строкой 37
рассматриваемого сценария.



В
приведенной строке создается экземпляр
объекта класса
и предпринимается попытка соединения
с хостом
с использованием
имени
пользователя
и пароля
.
Соединение будет использовать базу
данных
.
В нашем случае имя базыBOOKS.
PHP5 появилась новая библиотека для подключения к MySQL, называемая mysqli (―i‖ означает ―improved‖ - улучшенная). Данная библиотека позволяет использовать как объектно-ориентированный, так и процедурный синтаксис.
Если использовать процедурный синтаксис PHP5, то подключение к MySQL должно быть записано в виде следующей строки:
@ $db =mysqli_connect ($Host, $User, $Password, $DBName);
отличие от результата функции (приведенной в строке 37), функция mysqli_connect () возвращает ресурс, а не объект.
Этот ресурс при использовании процедурного интерфейса должен передаваться во все использованные функции mysqli (данный подход напоминает работу с файловыми функциями наподобие Fopen()).
Обратите внимание, что строка, в которой выполняется попытка подключения к базе данных, начинается с операции подавления выдачи ошибок @.
Как и в процедурном подходе, так и в объектно-ориентированном интерфейсе результат попытки подключения к базе данных должен быть проверен (0 – если результат соединения успешен, иначе номер ошибки).

Следующая строка сценария (рис. 3.274) возвращает результат построенного запроса:

Если Вы предпочитаете процедурный интерфейс, то запрос следует записать в виде:
$result = mysqli_query ($db, $query);
В любом случае возвращаемое значение сохраняется в переменной $result для дальнейшего использования.
259
Существуют несколько вариантов получения результата из идентификатора результата. В нашем примере, использующим объектно-ориентированный подход, количество возвращаемых строк хранится в
переменной
класса объекта результата с именем


При процедурном подходе для получения количества возвращаемых строк используется функция mysqli_num_rows($result), которой необходимо передать идентификатор результата:
$num_res = mysqli_num_rows($result);
В задании 1 данной темы, аналогичный результат получен функцией: mysql_num_rows($result) (рис. 3.268).
Зная значение $num_res, можно отобразить результаты запроса используя цикл (строки 49-61).
В каждой итерации этого цикла происходит вызов метода класса $row=$result->fetch_assoc() (строка 51). Именно этот метод извлекает из результирующего набора запись и преобразует ее в ассоциативный массив, в котором каждый ключ является именем атрибута, а каждое значение – элементом ячейки массива

Естественно, если использовать процедурный подход в строке с номером 51, должна быть указана функция:
$row = mysqli_fetch_assoc($result);
Используя массив $row можно пройти по всем полям и должным образом отобразить каждое из них (строки 52-59).
Кроме рассмотренных вариантов получения результата из идентификатора запроса можно вместо ассоциативного массива воспользоваться нумерованным массивом, применив при процедурном подходе функцию mysqli_fetch_row():
$row = mysqli_fetch_row($result);
260
При объектном подходе используется метод $row = $result -> fetch_row ();
Значения атрибутов будут храниться в каждом порядковом значении $row[0], $row[l] и т.д.
С помощью функции mysqli_fetch_object() можно выбрать строку внутрь объекта и получать доступ к атрибутам как к свойствам объекта $row-> title, $row-> author и так далее.
$row = mysqli_fetch_object($result);
При объектном подходе используется метод: $row = $result -> fetch_object ();
После этого к каждому атрибуту можно получить доступ через $row->title, $row->author и так далее.
Каждый из этих вариантов подразумевает выборку строки за раз. Другой вариант — получить доступ, используя mysql_result(). Для этого потребуется указать номер строки (от 0 до количества строк минус 1) и название поля, например:
$row = mysqli_result($result, $i, "title");
Название поля можно задать в виде строки (либо в форме "title" либо в форме "books.title") или номером (как в mysqli_fetch_row()). He стоит смешивать mysqli_result() с другими функциями выборки.
Строчно-ориентированные функции выборки намного более эффективны, нежели mysqli_result(), так что лучше использовать одну из них.
Отсоединение от базы данных
Для закрытия (уничтожения) результирующего набора применяется метод:

При процедурном подходе используется функция: mysqli_free_result($result) ;
Закрытие соединения при объектно-ориентированном подходе производится методом (строка 63, рис. 3.274):

При процедурном подходе используется функция: mysqli_close($db);
Однако в этом нет особой необходимости, поскольку с завершением выполнения сценария соединение закроется автоматически.
261
Задание 3. Внесение новой информации в базу данных. Проверка и фильтрация данных, исходящих от администратора
Внесение новой информации очень похоже на получение существующей. Нужно пройти те же шаги — установить соединение, отправить запрос и проверить результаты. Только в данном случае вместо SELECT будет использоваться INSERT.
На рис. 3.278 показана HTML форма для помещения новых книг в базу BOOKS. HTML-код этой страницы приведен на рис. 3.279 и продублирован в файле http://localhost/php/lab15_04.php.

Рис. 3.278. Интерфейс для добавления новых книг.
Результаты заполнения этой формы передаются в Lab15_05.php, а сценарий, занимающийся деталями, выполняет определенную аутентификацию и пытается записать данные в базу данных.
Листинг Lab15_04.php – HTML код страницы ввода информации о новых книгах.
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/> <title>Lab15_04 Форма ввода новой книги</title>
</head><body>
<h1>Форма ввода новой книги</h1><!--Заголовок HTML-->
<!--Обработка вводимой информации производится в файле Lab15_05.php --> <form action="Lab15_05.php" method="post">
<table border="0"> <tr>
<td>ISBN</td>
<td><input type="text" name="isbn" maxlength="13" size="13"></td> </tr>
262
<tr>
<td>Автор</td>
<td> <input type="text" name="author" maxlength="30" size="30"></td> </tr>
<tr> <td>Название</td>
<td> <input type="text" name="title" maxlength="60" size="30"></td> </tr>
<tr>
<td>Цена, $</td>
<td><input type="text" name="price" maxlength="7" size="7"></td> </tr>
<tr>
<td colspan="2"><input type="submit" value="Зарегистрировать"></td>
</tr>
</table>
</form>
</body></html>
Рис. 3.279. HTML-код страницы добавления новых книг.
Листинг Lab15_05.php — сценарий записи новой книги в базу данных. (для удобства строни кода пронумерованы)
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"
/>
<title>Lab15_05 Обработчик формы ввода для Lab15_04.php </title>
<h1>Магазин "Книг"</h1><h2> Результаты ввода</h2>
<body>
<?php
// Проверяем не пустой ли суперглобальный массив $_POST
if(empty($_POST)) exit("Означьте элементы формы");
// создание коротких имен переменных
10 $isbn=trim($_POST['isbn']); //Trim - убираем пробелы в
$author=trim($_POST['author']);//начале и в конце строки.
$title = trim($_POST['title']);
$price=trim($_POST['price']);//формат хранения Float(4.2)
//Означиваем необходимые компоненты для связи с базой
$Host="localhost"; $User="root"; $DBName="books"; $Password="";
if (!$isbn || !$author || !$title || !$price):
echo 'Вы ввели не все необходимые сведения.<br />'
.'Пожалуйста, вернитесь на предыдущую страницу и повторите ввод.<br>';
//Внимание! Если $price=0 - то считаем, что цена не означена.
exit; //выход из программы
endif;
263
$lenprice=strlen($price); //длина введенной строки символов в поле цены
$formatted = sprintf ("%01.2f", $price);
$tochka=substr($price, $lenprice-1, 1);
//echo "<br>Введено ".$price." formatted=".$formatted." strlen=
".strlen($price).",tochka=".$tochka."<br>"; // отладочный оператор
/*Начиная с версии 5.2.0 в PHP присутствуют специальные функции для фильтрации данных. Одна из таких функций - filter_var. Сначала нам необходимо убедиться, что нужные нам функции установлены и доступны. Для этого используются операторы: */
if (function_exists('filter_list')):
//echo 'список фильтров установлен!';
else:
die('Ошибка: фильтры не найдены. '); // выход из программы
endif;
//FILTER_VALIDATE_FLOAT — проверка на число с плавающей точкой
$valid_float = filter_var($price, FILTER_VALIDATE_FLOAT);
if ($valid_float !== false):
// проверка прошла успешно, $price - число
//echo "проверка Float прошла успешно <br>";
if (strpos($price, ".")===false): // символ точки в $price не найден
echo "<br> Точки нет. Введено ".$price." strlen ".strlen($price)."<br>";
if ($lenprice>2):
echo "Указаная цена ".$price." превышает формат хранения в базе. В базе
указан формат хранения Float(4.2). <br>Исправьте ввод данных.";
exit;
endif;
else://точку указали
echo "<br> Точка есть. Позиция ".strpos($price, ".")." Введено ".$price."
strlen ".strlen($price)."<br>";
if ($lenprice>5):
echo "Указаная цена ".$price." превышает формат хранения в базе. В базе
указан формат хранения Float(4.2). <br>Исправьте ввод данных.";
exit;
endif;
if (strpos($price, ".") >2):
//Точка есть. Например, позиция 3 в введенной Цене 333.5 Длина strlen =5
//Внимание! Если пропустить в базу пропишется число 99.99
exit ("Указаная цена ".$price." превышает формат хранения в базе. В базе указан формат хранения Float(4.2). <br>Исправьте ввод данных, иначе в базу запишется 99.99 .");
endif;
endif;
else: // проверка на число не прошла
echo "В поле Цена указано ".$price." В поле есть недопустимый символ ! <br>Исправьте ввод данных.";
264
exit;//выход из программы
endif;
59
if (preg_match("/^[0-9].+$/",$price)):
//echo "Ввели число <br>";
else:
//echo "Во вводе есть символ <br>";
endif;
65
if (substr($price, 0, 1)=="-"):
echo "В поле Цена не должно быть отрицательного числа! <br> Исправьте ввод данных.";
exit;//выход из программы
endif;
70
if (!get_magic_quotes_gpc())://директива в Php.ini = off выключена
$isbn = addslashes($isbn);
$author = addslashes($author);
$title = addslashes($title);
$price = doubleval($price);//фильтрации всех
неподходящих символов для числового поля.
else: //В нашем PHP.ini установлена по умолчанию включенной
//get_magic_quotes_gpc включена = on.
endif;
78
@ $db = new mysqli($Host, $User, $Password, $DBName);
if (mysqli_connect_errno()):
echo 'Ошибка: Не удалось установить соединение с базой данных.<br />
Пожалуйста, повторите попытку позже.';
exit;
endif;
85
86 $sql = "insert into books values('".$isbn."', '".$author."', '".$title."', '".$price."')";
$result = $db->query($sql);
if ($result):
echo "<br>".$db->affected_rows." Книга добавлена в базу данных.";
else://есть ошибки при добавлении записи (книги)
echo "<br> <font color=red>Книга Не добавлена в базу данных.<br>";
echo "<br>Ошибка MySql= ".mysqli_error($db).",result= ".$result.", affected_rows= ".$db->affected_rows ;
//exit() // для тестирования
if ($db->errno==1062)://нарушение первичного ключа
95//Номер ошибки=1062, описание Duplicate entry '1' for key 1,sqlstate 23000 96 // echo("<br>Номер ошибки=".$db->errno.", описание ".$db->error.",sqlstate ".$db->sqlstate);
265
echo("<br> Ошибка! Подобный isbn= ".$isbn." уже Вами был использован! <br>db->error ".$db->error);
//запрос к базе
//Используется Объектно-ориентированный стиль и библиотека
MYSQLI
$sql ="SELECT * FROM books WHERE isbn='".$isbn."'";
$q = $db->query($sql);
if (!$q):
103 exit ('Ошибка: запроса.<br>');
endif;
// Выводим заголовок таблицы для записи книги с существующим
ISBN:
echo"<table border=\"1\" width=\"50%\" bgcolor=\"#FFFFE1\">";
echo "<tr><td>ISBN</td><td>Автор</td><td>Название</td>";
echo "<td>Цена</td>";
// Выводим в таблице характеристики книги
for ($c=0; $c<mysqli_num_rows($q); $c++)
{echo "<tr>";
$f = mysqli_fetch_array($q);
echo "<td>$f[isbn]</td><td>$f[author]</td><td>$f[title]</td>";
echo "<td>$f[price]</td>";
echo "</tr>";}//конец цикла вывода таблицы
echo "</table>";
117
echo "<h3> Сведения о полях</h3>";
$field_cnt = $q->field_count;//
//printf("В результате %d поля (ей).\n", $field_cnt);
//На экране: В результате 4 поля (ей).
echo("В результате field_cnt=".$field_cnt." поля (ей) mysqli_num_fields=".mysqli_num_fields($q));
//На экране:/В результате field_cnt=4 поля (ей) mysqli_num_fields=4
echo"<table border=\"1\" width=\"50%\" bgcolor=#33FFFF\">";
echo "<tr><td>Номер</td><td>Имя</td><td>Тип</td>";
echo "<td>Ширина столбца</td><td>Факт.дл.</td><td>Флаги поля</td>";
for ($i = 0; $i < mysqli_num_fields($q); $i++)
{echo "<tr>";
$finfo = $q -> fetch_field ();//Object oriented style (method)
$j = $q -> current_field ; //порядковый номер поля
131
$c =$finfo -> name;
//имя поля
132
$t= $finfo -> type;
//тип поля
133
$fl=$finfo -> flags;
//строка флагов поля
$dm=$finfo -> max_length;//фактически использовано в базе
$dl=$finfo -> length;//отведено в базе
//$c =mysqli_field_name($q, $i); -эти три функции в
266
//$f l=mysqli_field_flags($q,$i); объектно-ориентированном
//$t = mysqli_field_type($q,$i); подходе не работают
echo "<td>$j</td><td>$c<td>$t</td><td>$dl</td><td>$dm</td><td>$fl</td>";
echo "</tr>";}
echo "</table>";
142 //Процедурный подход
@ $dbb = mysql_pconnect($Host, $User, $Password);
mysql_select_db( "books");//открытие базы
$result=mysql_db_query("books","select * from books");// запрос к базе
echo "<BR>";
for($i=0;$i<mysql_num_fields($result);$i++)
{
echo "Свойства поля ".($i+1).":<BR>";
$param=mysql_fetch_field($result);
if(!$param) echo "Нет информации о свойствах!";
echo "<PRE>
name: $param->name
table: $param->table
max_length: $param->max_length
not_null: $param->not_null
primary_key: $param->primary_key
unique_key: $param->unique_key
multiple_key: $param->multiple_key
numeric: $param->numeric
161
blob:
$param->blob
162
type:
$param->type
unsigned: $param->unsigned
zerofill: $param->zerofill
</PRE>";
}
167
if (!$db=mysql_connect($Host, $User, $Password))
{echo "<h2>MySQL Error!</h2>"; exit; }//неудача
// Выбираем базу данных:-mysql_select_db($db);
if (!@mysql_select_db("books",$db) )
{echo "<p>К сожалению, не доступна база данных</p>"; exit();}
endif;
$q=mysql_db_query("books","select * from books");
echo "<h2> Сведения о полях</h2>";
echo"<table border=\"1\" width=\"50%\" bgcolor=#33FFFF\">";
echo "<tr><td>Номер</td><td>Имя</td><td>Тип</td>";
echo "<td>Длина</td><td>Флаги поля</td>"; //td
for ($i = 0; $i < mysql_num_fields($q); $i++)
{echo "<tr>";
$c =mysql_field_name($q, $i);
267
$fl=mysql_field_flags($q,$i);
$t =mysql_field_type($q,$i);
$dl = mysql_field_len($q, $i);
$j = $i+1 ; //порядковый номер поля
echo "<td>$j</td><td>$c<td>$t</td><td>$dl</td><td>$fl</td>";
echo "</tr>";}
echo "</table>";
endif; //конец if ($result):
?>
</body></html>
Рис. 3.280. Сценарий Lab15_05.php добавления новых книг.
Результаты успешного добавления книги в базу данных показаны на рис. 3.281.

Рис. 3.281. Сообщение о добавлении новой книги.
После изучения кода C:\WebServers\home\localhost\www\php\lab15_05.php
станет ясно, что он во многом похож на код сценария для извлечения данных из базы. Мы проверяем, чтобы все поля формы были заполнены

и отформатированы с помощью addslashes () перед внесением данных в базу (обратите внимание на требованию к конфигурации PHP.ini, использованного на Вашей машине):
$isbn = addslashes ($isbn) ; $author = addslashes ($author) ; $title = addslashes ($title) ; $price = doubleval ($price) ;
Поскольку цены хранятся в базе в виде чисел с плавающей запятой, символы наклонной черты они содержать не должны. Это же достигается при помощи функции doubleval(), которая отфильтрует все неподходящие символы в числовом поле. Эта же функция позаботится и обо всех символах валюты, которые пользователь может печатать при заполнении формы.
Обратите внимание на особую обработку информации чисел с плавающей запятой.
268
Пусть, например, пользователь в поле цены ввел следующую информацию (рис. 3.282).

Рис. 3.282. Информация о новой книге.
Если в коде сценария (рис. 3.280) закомментарить строку 52 (фрагмент закомментаренного кода показан на рис. 3.283):

Рис. 3.283. Модифицированное тело программы Lab15_05.php.
то
нажатие кнопки
приведет к результату (рис. 3.284)

Рис. 3.284. Состав таблицы books после добавления новой книги. Естественно наличие подобной ошибки может привести к
нежелательным последствиям.
Также из семантических соображений, понятно почему надо использовать оператор указанный в 66-ой строке кода, представленного на рис. 3.280.
269

Рис. 3.285. Фрагмент кода непозволяющий вводить отрицательную цену.
Мы соединяемся с базой данных, создавая экземпляр
,
и настраиваем запрос. В данном случае
это
INSERT
.

Рис. 3.286. Фрагмент кода обеспечивающий соединение с базой и вставку данных.
Запрос выполняется в базе данных как обычно:
При
процедурном подходе следует использовать
оператор $result = mysqli_query($sql);
Одно существенное различие между INSERT и SELECT заключается в использовании mysqli_affected_rows(). В процедурной версии это функция, а
объектно-ориентированной версии это переменная-член класса
,
которая хранит количество строк
модифицированых в запросе.
В предыдущем сценарии функция mysql_num_rows() применялась для определения количества строк, которые будет возвращать SELECT. При написании запросов, которые изменяют базу данных, например, INSERT, DELETE, UPDATE, следует использовать mysql_affected_rows().
270
Чтобы раскрыть назначение строк кода с 90 по 189 на рис. 3.280 рассмотрим ситуацию, когда пользователь пытается ввести информацию в
базу
с уже существующим реляционным ключом
(рис. . 3.287). В нашем случае, в таблице с
именемbooks,
реляционным ключом является атрибут
ISBN.
Для проведения эксперимента раскомментарим строку 93 в коде программы Lab15_05.pp.

и введем информацию показанную на рис. 3.287 14.22.

Рис. 3.287. Форма с исходной информацией.
Если соединение с базой данных пройдет коррекстно, то при вставке информации о новой книге MySql выполняя запрос присвоит значение
переменной
равное False и будет выведено сообщение
показанное на рис. 3.288.

Рис. 3.288. Сообщение о дублировании ключа.
Для пользователя подобное сообщение является недостаточно информативным, поэтому если закоментарить оператор EXIT (строка 93) получим более информативное сообщение (рис. 3.289).
271

Рис. 3.289. Сообщение раскрывающее суть ошибки.
Для целей обучения, далее приводятся сообщения из кода программы, описывающие сведения о полях (строки 99-141) при использовании объектно-ориентированного синтаксиса PHP (рис. 3.290) и процедурного синтаксиса PHP (строки 142-189 рис. 3.280) результат которого приведен на рис. 3.291.

Рис. 3.290. Сообщение о составе и свойствах полей, использованных в запросе.

272

Рис. 3.291. Сообщение о составе и свойствах полей при использовании процедурного подхода.
Возвращаемый объект имеет следующие свойства:
name - имя поля
table - имя таблицы, которой принадлежит поле
max_length - максимальная длина поля
not_null - 1, если полю разрешено пустое значение
primary_key - 1, если поле является ключевым
unique_key - 1, если в поле допускаются только уникальные значения
multiple_key - 1, если в поле допустимо иметь повторяющиеся значения
numeric - 1, если поле числовое
blob - 1, если поле имеет тип BLOB
type - тип поля
unsigned - 1, если поле числовое беззнаковое
zerofill - 1, есле поле заполняется нулями
Мы рассмотрели основы использования баз данных MySQL из РНР. В следующем задании рассматриваются еще некоторые полезные функции, не упомянутые ранее.
273
Задание 4. Создание и удаление баз данных
Для создания новой базы данных MySQL из PHP-сценария применяется функция mysql_create_db(), а для удаления базы данных — mysql_drop_db().
Рассмотрим прототипы этих функций:
int mysql_create_db(string database, [int database_connection] ); int mysql_drop_db(string database, [int database_connection] ) ;
Обе функции используют имя базы данных и соединение. Если соединения нет, будет использоваться последнее открытое. Функции создают либо удаляют указанную базу данных. В случае успеха функции возвращают значение true, а в случае неудачи — false.
Обратите внимание ! В зависимости от версии PHP, функция mysql_create_db() может быть не включена в библиотеки PHP. Поэтому рекомендуется использовать SQL запрос.

274

Рис. 3.292. Исходный код С:\WebServers\home\localhost\www\php\Lab15_06.php.
Результат работы программы Lab15_06.php представлен на рис. 3.293.

Рис. 3.293. Результат работы Lab15_06.php.
275
Код программы Lab15_07.php показан на рис. 3.294, а результат представлен на рис. 3.295.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Форма ввода Lab15_07.php</title></head>
<body>
<?php
$host="localhost"; $user="root"; $DBName="proba"; $password="";
// Производим попытку подключения к серверу MySQL: if (!$db=mysql_connect($host, $user, $password))
{echo "<h2>MySQL Error!</h2>"; exit(); }//неудача //echo "<align='center'> Соединение с Mysql успешно"; echo "<p align='center'> Соединение с Mysql успешно "; $TableName="Table1";
$Link=mysql_connect($host, $user, $password); $query="SELECT * FROM $TableName";
$query_result=mysql_db_query($DBName,$query,$db) or die("Display error".mysql_error());
print("<table border=1 width=50% align=center>\n"); print("<tr><td>Name</td><td>Email</td><td>Comments</td></tr>"); while($Row=mysql_fetch_array($query_result))
{
print("<tr><td>$Row[FirstName] $Row[LastName]</td><td>$Row[Email]</td><td>$Row[Comments]</td></tr>\n ");
}
print("</table>"); mysql_free_result($query_result); mysql_close($Link);
?>
</body></html>
Рис. 3.294. Исходный код C:\WebServers\home\localhost\www\php\Lab15_07.php.

Рис. 3.295. Результат работы Lab15_07.php.
276
Другие интерфейсы PHP-баз данных
РНР поддерживает различные библиотеки, что дает возможность подключаться к огромному количеству баз данных, включая Oracle, Microsoft SQL Server, mSQL и PostgreSQL.
В целом принципы подключения и подачи запросов любой из этих баз данных одни и те же. Названия функций могут быть разными, разные базы данных могут иметь разную функциональность, но если вы можете подключиться к MySQL, то другие СУБД вряд ли поставят Вас в безвыходное положение.
Дополнительные темы.
Переменные окружения HTTP
Когда Web-браузер выполняет запрос к Web-серверу, он вместе с запросом посылает еще дополнительный список переменных. Эти переменные называются переменными окружения и могут использоваться для отображения динамического содержимого или авторизации пользователей.
Функция phpinfo () выводит большое количество информации о программном обеспечении Web-сервера, версии РНР, который вы запустили, и об основных переменных окружения HTTP. Чтобы посмотреть эту информацию, выполните следующие действия:
Создайте новый файл с помощью текстового или HTML редактора. Введите строку РНР-кода:
<?
phpinfo();
?>
Сохраните созданный файл с именем phpinfo.php в папке для документов вашего Web-сервера.
Запустите браузер, в поле Адрес (Address) введите
http://localhost/php/phpinfo.php
Настройка сервера
Вы считаете что все сделали правильно, но у Вас что-то не работает. Может, у Вас неправильно сконфигурирован сервер?
Если Вы "все сделали правильно", но Ваш код неработоспособен, или работает неправильно, не спешите отчаиваться. Возможно проблема не в Ваших руках, а в неверных настройках сервера. Вот список директив, которые имеют отношения к загрузке файлов:
277
В файле php.ini:
Если Вы хотите узнать, где расположен Ваш php.ini, выполните
<?php phpinfo(); ?>
file_uploads - возможность запретить или разрешить загрузку файлов в целом. По умолчанию On.
upload_max_filesize - максимальный размер файла, который может быть загружен. Если Вам необходимо работать с большими файлами, измените эту настройку. По умолчанию 2М. Не забудьте изменить post_max_size.
post_max_size - общее ограничение сверху на размер данных, передаваемых в POST запросе. Если Вам необходимо работать с большими файлами, или передавать несколько файлов одновременно, измените эту настройку. Значение по умолчанию 8М.
upload_tmp_dir - временная директория на сервере, в которую будут помещаться все загружаемые файлы. Проверьте, какие на нее выставлены права(если на данном этапе у Вас возникли сложности, смотрите пояснения в конце статьи). Такая директория должна существовать и у пользователя, под которым выполняется Apache, также должны быть права на запись в эту директорию. Если Вы работаете с включенным ограничением open_basedir - то временный каталог должен находиться внутри. Вам не нужно заботиться о ее чистке или об уникальности имен, PHP решает эту проблему за Вас.
В файле httpd.conf:
Прежде всего, убедитесь, что Вы используете веб-сервер Apache 1.3 (последняя версия на момент написания - 1.3.27). Если Вы используете Apache 2.0, Вам следует прочитать следующий отрывок из документации:
Do not use Apache 2.0 and PHP in a production environment neither on Unix nor on Windows.
Если Вы получили сообщение "POST Method Not Allowed", это означает, что надо искать что-то похожее на следующие директивы, и использовать ключевое слово Allow:
<Limit POST >
Order allow,deny Allow from all
</Limit>
Проблемы с загрузкой бинарных файлов - классический вопрос "почему бьются файлы при upload". Вот способ решения, предложенный Димой Бородином (http://php.spb.ru): В директории, где лежит скрипт, делаем файл .htaccess, в котором пишем: CharsetDisable On. В файл httpd.conf
дописать строки:
<Location /> CharsetRecodeMultipartForms Off
</Location>
278
Небольшие пояснения, к этому рецепту: вышеописанная проблема, когда загруженные на сервер архивы не распаковываются и картинки не отображаются, может возникать из-за того, что используется веб-сервер
Russian Apache. Директива CharsetDisable отключает модуль charset-processing module, т.е. никакой перекодировки при скачивании файлов, находящихся в данной папке, происходить не будет. Директива CharsetRecodeMultipartForms выключает перекодировку данных, переданных методом POST с заголовком Content-Type: multipart/form-data. Т.е. двоичные данные, переданные с такой настройкой, будут оставлены в первоначальном виде, а все остальное наполнение сайта будет перекодировано согласно текущим настройкам сервера.
Но при этом могут возникнуть осложнения: будьте готовы к тому, что в некоторых случаях текстовые части запросов вам придется перекодировать самостоятельно. Вот что по этому поводу говорится в документации:
Коротко о правах на файлы
Проблемы с правами на сервере (upload_tmp_dir)
В *nix-подобных операционных системах каждой папке, файлу, ссылке выставлены соответствие права доступа. Они могут выглядеть как rwx-rw-r-или же как число 754.
Доступность файла или каталога зависят от идентификатора пользователя и идентификатора группы, в которую он входит. Режим в целом описывается в терминах трех последовательностей, по три буквы в каждой:
Владелец Группа Прочие
(u) (g) (o) rwx rwx rwx
Здесь владелец, члены группы и все прочие пользователи обладают правами чтения файла, записи в него и его выполнения. Права - любая осмысленная комбинация следующих букв:
r Право на чтение. (4)
Право на запись. (2)
Право на выполнение (поиск в каталоге). (1)
Для того, что бы загрузка файлов на сервер работала корректно, необходимо реализовать один из двух вариантов.
Установить владельцем каталога пользователя, с чьими привелегиями выполняется apache. Это можно узнать из файла httpd.conf или просмотрев список процессов на сервере. Права на каталог должны быть 700 (rwx------).
Независимо от того, кто является владельцем каталога, установить права 777 (rwxrwxrwx).
279
Cписок литературы
Основной:
1. Веллинг Л., Томсон Л. Разработка Web-приложений с помощью PHP
и MySQL. 3-е издание. – М.: Издательский дом ―Вильямс‖. 2008. – 875 c.
Дополнительный:
2. Копейкин М. В., Спиридонов В. В., Шумова Е. О. Базы данных. Основы SQL реляционных баз данных: Учеб. пособие. – СПб.: СЗТУ, 2006.
– 177 c.
3. Базы данных: Метод. указ. к курсовому проектированию. / Сост.: М.В. Копейкин, В.В. Спиридонов, Е.О. Шумова – СПб.: СЗТУ, 2005. - 172 c.
4. Базы данных: Методический комплекс по курсу и указания к выполнению лабораторных работ. / Сост.: М.В. Копейкин, В.В. Спиридонов, Е.О. Шумова – СПб.: СЗТУ, 2005. - 172 c.– Спб.: СЗТУ. 2004. – 100 с.
Лабораторные работы в среде ORD представлены в [4. Лабораторные работы в среде MySQL представлены ниже.
