metoda / Ml_ITIn_2013
.pdf
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 — сценарий записи новой книги в базу данных. (для удобства строни кода пронумерованы)
1<html><head>
2<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"
/>
3<title>Lab15_05 Обработчик формы ввода для Lab15_04.php </title>
4<h1>Магазин "Книг"</h1><h2> Результаты ввода</h2>
5<body>
6<?php
7// Проверяем не пустой ли суперглобальный массив $_POST
8if(empty($_POST)) exit("Означьте элементы формы");
9// создание коротких имен переменных
10 |
$isbn=trim($_POST['isbn']); //Trim - убираем пробелы в |
11$author=trim($_POST['author']);//начале и в конце строки.
12$title = trim($_POST['title']);
13$price=trim($_POST['price']);//формат хранения Float(4.2)
14//Означиваем необходимые компоненты для связи с базой
15$Host="localhost"; $User="root"; $DBName="books"; $Password="";
16if (!$isbn || !$author || !$title || !$price):
17echo 'Вы ввели не все необходимые сведения.<br />'
18.'Пожалуйста, вернитесь на предыдущую страницу и повторите ввод.<br>';
19//Внимание! Если $price=0 - то считаем, что цена не означена.
20exit; //выход из программы
21endif;
263
22$lenprice=strlen($price); //длина введенной строки символов в поле цены
22$formatted = sprintf ("%01.2f", $price);
23$tochka=substr($price, $lenprice-1, 1);
24//echo "<br>Введено ".$price." formatted=".$formatted." strlen=
25".strlen($price).",tochka=".$tochka."<br>"; // отладочный оператор
/*Начиная с версии 5.2.0 в PHP присутствуют специальные функции для фильтрации данных. Одна из таких функций - filter_var. Сначала нам необходимо убедиться, что нужные нам функции установлены и доступны. Для этого используются операторы: */
26if (function_exists('filter_list')):
27//echo 'список фильтров установлен!';
28else:
29die('Ошибка: фильтры не найдены. '); // выход из программы
30endif;
31//FILTER_VALIDATE_FLOAT — проверка на число с плавающей точкой
32$valid_float = filter_var($price, FILTER_VALIDATE_FLOAT);
33if ($valid_float !== false):
34// проверка прошла успешно, $price - число
35//echo "проверка Float прошла успешно <br>";
36if (strpos($price, ".")===false): // символ точки в $price не найден
37echo "<br> Точки нет. Введено ".$price." strlen ".strlen($price)."<br>";
38if ($lenprice>2):
39echo "Указаная цена ".$price." превышает формат хранения в базе. В базе
40указан формат хранения Float(4.2). <br>Исправьте ввод данных.";
41exit;
42endif;
43else://точку указали
44echo "<br> Точка есть. Позиция ".strpos($price, ".")." Введено ".$price."
strlen ".strlen($price)."<br>";
45if ($lenprice>5):
46echo "Указаная цена ".$price." превышает формат хранения в базе. В базе
указан формат хранения Float(4.2). <br>Исправьте ввод данных.";
47exit;
48endif;
49if (strpos($price, ".") >2):
50//Точка есть. Например, позиция 3 в введенной Цене 333.5 Длина strlen =5
51//Внимание! Если пропустить в базу пропишется число 99.99
52exit ("Указаная цена ".$price." превышает формат хранения в базе. В базе указан формат хранения Float(4.2). <br>Исправьте ввод данных, иначе в базу запишется 99.99 .");
53endif;
54endif;
55else: // проверка на число не прошла
56echo "В поле Цена указано ".$price." В поле есть недопустимый символ ! <br>Исправьте ввод данных.";
264
57exit;//выход из программы
58endif;
59
60if (preg_match("/^[0-9].+$/",$price)):
61//echo "Ввели число <br>";
62else:
63//echo "Во вводе есть символ <br>";
64endif;
65
66if (substr($price, 0, 1)=="-"):
67echo "В поле Цена не должно быть отрицательного числа! <br> Исправьте ввод данных.";
68exit;//выход из программы
69endif;
70
71if (!get_magic_quotes_gpc())://директива в Php.ini = off выключена
72$isbn = addslashes($isbn);
73$author = addslashes($author);
74$title = addslashes($title);
75$price = doubleval($price);//фильтрации всех
//неподходящих символов для числового поля.
76else: //В нашем PHP.ini установлена по умолчанию включенной
//get_magic_quotes_gpc включена = on.
77endif;
78
79@ $db = new mysqli($Host, $User, $Password, $DBName);
80if (mysqli_connect_errno()):
81echo 'Ошибка: Не удалось установить соединение с базой данных.<br />
82Пожалуйста, повторите попытку позже.';
83exit;
84endif;
85
86 $sql = "insert into books values('".$isbn."', '".$author."', '".$title."', '".$price."')";
87$result = $db->query($sql);
88if ($result):
89echo "<br>".$db->affected_rows." Книга добавлена в базу данных.";
90else://есть ошибки при добавлении записи (книги)
91echo "<br> <font color=red>Книга Не добавлена в базу данных.<br>";
92echo "<br>Ошибка MySql= ".mysqli_error($db).",result= ".$result.", affected_rows= ".$db->affected_rows ;
93//exit() // для тестирования
94if ($db->errno==1062)://нарушение первичного ключа
95//Номер ошибки=1062, описание Duplicate entry '1' for key 1,sqlstate 23000 96 // echo("<br>Номер ошибки=".$db->errno.", описание ".$db- >error.",sqlstate ".$db->sqlstate);
265
97echo("<br> Ошибка! Подобный isbn= ".$isbn." уже Вами был использован! <br>db->error ".$db->error);
98//запрос к базе
99//Используется Объектно-ориентированный стиль и библиотека
MYSQLI
100$sql ="SELECT * FROM books WHERE isbn='".$isbn."'";
101$q = $db->query($sql);
102if (!$q):
103 |
exit ('Ошибка: запроса.<br>'); |
104endif;
105// Выводим заголовок таблицы для записи книги с существующим
ISBN:
106echo"<table border=\"1\" width=\"50%\" bgcolor=\"#FFFFE1\">";
107echo "<tr><td>ISBN</td><td>Автор</td><td>Название</td>";
108echo "<td>Цена</td>";
109// Выводим в таблице характеристики книги
110for ($c=0; $c<mysqli_num_rows($q); $c++)
111{echo "<tr>";
112$f = mysqli_fetch_array($q);
113echo "<td>$f[isbn]</td><td>$f[author]</td><td>$f[title]</td>";
114echo "<td>$f[price]</td>";
115echo "</tr>";}//конец цикла вывода таблицы
116echo "</table>";
117
118echo "<h3> Сведения о полях</h3>";
119$field_cnt = $q->field_count;//
120//printf("В результате %d поля (ей).\n", $field_cnt);
121//На экране: В результате 4 поля (ей).
122echo("В результате field_cnt=".$field_cnt." поля (ей) mysqli_num_fields=".mysqli_num_fields($q));
123//На экране:/В результате field_cnt=4 поля (ей) mysqli_num_fields=4
124echo"<table border=\"1\" width=\"50%\" bgcolor=#33FFFF\">";
125echo "<tr><td>Номер</td><td>Имя</td><td>Тип</td>";
126echo "<td>Ширина столбца</td><td>Факт.дл.</td><td>Флаги поля</td>";
127for ($i = 0; $i < mysqli_num_fields($q); $i++)
128{echo "<tr>";
129$finfo = $q -> fetch_field ();//Object oriented style (method)
130$j = $q -> current_field ; //порядковый номер поля
131 |
$c =$finfo -> name; |
//имя поля |
132 |
$t= $finfo -> type; |
//тип поля |
133 |
$fl=$finfo -> flags; |
//строка флагов поля |
134$dm=$finfo -> max_length;//фактически использовано в базе
135$dl=$finfo -> length;//отведено в базе
136//$c =mysqli_field_name($q, $i); -эти три функции в
266
137//$f l=mysqli_field_flags($q,$i); объектно-ориентированном
138//$t = mysqli_field_type($q,$i); подходе не работают
139echo "<td>$j</td><td>$c<td>$t</td><td>$dl</td><td>$dm</td><td>$fl</td>";
140echo "</tr>";}
141echo "</table>";
142 |
//Процедурный подход |
143@ $dbb = mysql_pconnect($Host, $User, $Password);
144mysql_select_db( "books");//открытие базы
145$result=mysql_db_query("books","select * from books");// запрос к базе
146echo "<BR>";
147for($i=0;$i<mysql_num_fields($result);$i++)
148{
149echo "Свойства поля ".($i+1).":<BR>";
150$param=mysql_fetch_field($result);
151if(!$param) echo "Нет информации о свойствах!";
152echo "<PRE>
153name: $param->name
154table: $param->table
155max_length: $param->max_length
156not_null: $param->not_null
157primary_key: $param->primary_key
158unique_key: $param->unique_key
159multiple_key: $param->multiple_key
160numeric: $param->numeric
161 |
blob: |
$param->blob |
162 |
type: |
$param->type |
163unsigned: $param->unsigned
164zerofill: $param->zerofill
165</PRE>";
166}
167
168if (!$db=mysql_connect($Host, $User, $Password))
169{echo "<h2>MySQL Error!</h2>"; exit; }//неудача
170// Выбираем базу данных:-mysql_select_db($db);
171if (!@mysql_select_db("books",$db) )
172{echo "<p>К сожалению, не доступна база данных</p>"; exit();}
173endif;
174$q=mysql_db_query("books","select * from books");
175echo "<h2> Сведения о полях</h2>";
176echo"<table border=\"1\" width=\"50%\" bgcolor=#33FFFF\">";
177echo "<tr><td>Номер</td><td>Имя</td><td>Тип</td>";
178echo "<td>Длина</td><td>Флаги поля</td>"; //td
179for ($i = 0; $i < mysql_num_fields($q); $i++)
180{echo "<tr>";
181$c =mysql_field_name($q, $i);
267
182$fl=mysql_field_flags($q,$i);
183$t =mysql_field_type($q,$i);
184$dl = mysql_field_len($q, $i);
185$j = $i+1 ; //порядковый номер поля
186echo "<td>$j</td><td>$c<td>$t</td><td>$dl</td><td>$fl</td>";
187echo "</tr>";}
188echo "</table>";
189endif; //конец if ($result):
190?>
191</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).
