Отсоединение от базы данных

Для закрытия (уничтожения) результирующего набора применяется метод:

При процедурном подходе используется функция:

mysqli_free_result($result) ;

 

Закрытие соединения при объектно-ориентированном подходе производится методом (строка 63, рис. 3.274):

 

При процедурном подходе используется функция:

mysqli_close($db);

Однако в этом нет особой необходимости, поскольку с завершением выполнения сценария соединение закроется автоматически.

 

Задание 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>

<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

8 if(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="";

16 if (!$isbn || !$author || !$title || !$price):

17 echo 'Вы ввели не все необходимые сведения.<br />'

18 .'Пожалуйста, вернитесь на предыдущую страницу и повторите ввод.<br>';

19 //Внимание! Если $price=0 - то считаем, что цена не означена.

20 exit; //выход из программы

21 endif;

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. Сначала нам необходимо убедиться, что нужные нам функции установлены и доступны. Для этого используются операторы: */

26 if (function_exists('filter_list')):

27 //echo 'список фильтров установлен!';

28 else:

29 die('Ошибка: фильтры не найдены. '); // выход из программы

30 endif;

31 //FILTER_VALIDATE_FLOAT — проверка на число с плавающей точкой

32 $valid_float = filter_var($price, FILTER_VALIDATE_FLOAT);

33 if ($valid_float !== false):

34 // проверка прошла успешно, $price - число

35 //echo "проверка Float прошла успешно <br>";

36 if (strpos($price, ".")===false): // символ точки в $price не найден

37 echo "<br> Точки нет. Введено ".$price." strlen ".strlen($price)."<br>";

38 if ($lenprice>2):

39 echo "Указаная цена ".$price." превышает формат хранения в базе. В базе

40 указан формат хранения Float(4.2). <br>Исправьте ввод данных.";

41 exit;

42 endif;

43 else://точку указали

44 echo "<br> Точка есть. Позиция ".strpos($price, ".")." Введено ".$price."

strlen ".strlen($price)."<br>";

45 if ($lenprice>5):

46 echo "Указаная цена ".$price." превышает формат хранения в базе. В базе

указан формат хранения Float(4.2). <br>Исправьте ввод данных.";

47 exit;

48 endif;

49 if (strpos($price, ".") >2):

50 //Точка есть. Например, позиция 3 в введенной Цене 333.5 Длина strlen =5

51 //Внимание! Если пропустить в базу пропишется число 99.99

52 exit ("Указаная цена ".$price." превышает формат хранения в базе. В базе указан формат хранения Float(4.2). <br>Исправьте ввод данных, иначе в базу запишется 99.99 .");

53 endif;

54 endif;

55 else: // проверка на число не прошла

56 echo "В поле Цена указано ".$price." В поле есть недопустимый символ !

<br>Исправьте ввод данных.";

57 exit;//выход из программы

58 endif;

60 if (preg_match("/^[0-9].+$/",$price)):

61 //echo "Ввели число <br>";

62 else:

63 //echo "Во вводе есть символ <br>";

64 endif;

66 if (substr($price, 0, 1)=="-"):

67 echo "В поле Цена не должно быть отрицательного числа! <br>

Исправьте ввод данных.";

68 exit;//выход из программы

69 endif;

71 if (!get_magic_quotes_gpc())://директива в Php.ini = off выключена

72 $isbn = addslashes($isbn);

73 $author = addslashes($author);

74 $title = addslashes($title);

75 $price = doubleval($price);//фильтрации всех

// неподходящих символов для числового поля.

76 else: //В нашем PHP.ini установлена по умолчанию включенной

//get_magic_quotes_gpc включена = on.

77 endif;

79 @ $db = new mysqli($Host, $User, $Password, $DBName);

80 if (mysqli_connect_errno()):

81 echo 'Ошибка: Не удалось установить соединение с базой данных.<br />

82 Пожалуйста, повторите попытку позже.';

83 exit;

84 endif;

86 $sql = "insert into books values('".$isbn."', '".$author."', '".$title."', '".$price."')";

87 $result = $db->query($sql);

88 if ($result):

89 echo "<br>".$db->affected_rows." Книга добавлена в базу данных.";

90 else://есть ошибки при добавлении записи (книги)

91 echo "<br> <font color=red>Книга Не добавлена в базу данных.<br>";

92 echo "<br>Ошибка MySql= ".mysqli_error($db).",result= ".$result.", affected_rows= ".$db->affected_rows ;

93 //exit() // для тестирования

94 if ($db->errno==1062)://нарушение первичного ключа

95//Номер ошибки=1062, описание Duplicate entry '1' for key 1,sqlstate 23000

96 // echo("<br>Номер ошибки=".$db->errno.", описание ".$db->error.",sqlstate ".$db->sqlstate);

97 echo("<br> Ошибка! Подобный isbn= ".$isbn." уже Вами был использован! <br>db->error ".$db->error);

98 //запрос к базе

99 //Используется Объектно-ориентированный стиль и библиотека MYSQLI

100 $sql ="SELECT * FROM books WHERE isbn='".$isbn."'";

101 $q = $db->query($sql);

102 if (!$q):

103 exit ('Ошибка: запроса.<br>');

104 endif;

105 // Выводим заголовок таблицы для записи книги с существующим ISBN:

106 echo"<table border=\"1\" width=\"50%\" bgcolor=\"#FFFFE1\">";

107 echo "<tr><td>ISBN</td><td>Автор</td><td>Название</td>";

108 echo "<td>Цена</td>";

109 // Выводим в таблице характеристики книги

110 for ($c=0; $c<mysqli_num_rows($q); $c++)

111 {echo "<tr>";

112 $f = mysqli_fetch_array($q);

113 echo "<td>$f[isbn]</td><td>$f[author]</td><td>$f[title]</td>";

114 echo "<td>$f[price]</td>";

115 echo "</tr>";}//конец цикла вывода таблицы

116 echo "</table>";

118 echo "<h3> Сведения о полях</h3>";

119 $field_cnt = $q->field_count;//

120 //printf("В результате %d поля (ей).\n", $field_cnt);

121 //На экране: В результате 4 поля (ей).

122 echo("В результате field_cnt=".$field_cnt." поля (ей) mysqli_num_fields=".mysqli_num_fields($q));

123 //На экране:/В результате field_cnt=4 поля (ей) mysqli_num_fields=4

124 echo"<table border=\"1\" width=\"50%\" bgcolor=#33FFFF\">";

125 echo "<tr><td>Номер</td><td>Имя</td><td>Тип</td>";

126 echo "<td>Ширина столбца</td><td>Факт.дл.</td><td>Флаги поля</td>";

127 for ($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); -эти три функции в

137 //$f l=mysqli_field_flags($q,$i); объектно-ориентированном

138 //$t = mysqli_field_type($q,$i); подходе не работают

139 echo "<td>$j</td><td>$c<td>$t</td><td>$dl</td><td>$dm</td><td>$fl</td>";

140 echo "</tr>";}

141 echo "</table>";

142 //Процедурный подход

143 @ $dbb = mysql_pconnect($Host, $User, $Password);

144 mysql_select_db( "books");//открытие базы

145 $result=mysql_db_query("books","select * from books");// запрос к базе

146 echo "<BR>";

147 for($i=0;$i<mysql_num_fields($result);$i++)

148 {

149 echo "Свойства поля ".($i+1).":<BR>";

150 $param=mysql_fetch_field($result);

151 if(!$param) echo "Нет информации о свойствах!";

152 echo "<PRE>

153 name: $param->name

154 table: $param->table

155 max_length: $param->max_length

156 not_null: $param->not_null

157 primary_key: $param->primary_key

158 unique_key: $param->unique_key

159 multiple_key: $param->multiple_key

160 numeric: $param->numeric

161 blob: $param->blob

162 type: $param->type

163 unsigned: $param->unsigned

164 zerofill: $param->zerofill

165 </PRE>";

166 }

168 if (!$db=mysql_connect($Host, $User, $Password))

169 {echo "<h2>MySQL Error!</h2>"; exit; }//неудача

170 // Выбираем базу данных:-mysql_select_db($db);

171 if (!@mysql_select_db("books",$db) )

172 {echo "<p>К сожалению, не доступна база данных</p>"; exit();}

173 endif;

174 $q=mysql_db_query("books","select * from books");

175 echo "<h2> Сведения о полях</h2>";

176 echo"<table border=\"1\" width=\"50%\" bgcolor=#33FFFF\">";

177 echo "<tr><td>Номер</td><td>Имя</td><td>Тип</td>";

178 echo "<td>Длина</td><td>Флаги поля</td>"; //td

179 for ($i = 0; $i < mysql_num_fields($q); $i++)

180 {echo "<tr>";

181 $c =mysql_field_name($q, $i);

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 ; //порядковый номер поля

186 echo "<td>$j</td><td>$c<td>$t</td><td>$dl</td><td>$fl</td>";

187 echo "</tr>";}

188 echo "</table>";

189 endif; //конец 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(), которая отфильтрует все неподходящие символы в числовом поле. Эта же функция позаботится и обо всех символах валюты, которые пользователь может печатать при заполнении формы.

Обратите внимание на особую обработку информации чисел с плавающей запятой.

Пусть, например, пользователь в поле цены ввел следующую информацию (рис. 3.282).

Рис. 3.282. Информация о новой книге.

 

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

Рис. 3.283. Модифицированное тело программы Lab15_05.php.

 

то нажатие кнопки приведет к результату (рис. 3.284)

 

Рис. 3.284. Состав таблицы books после добавления новой книги.

Естественно наличие подобной ошибки может привести к нежелательным последствиям.

Также из семантических соображений, понятно почему надо использовать оператор указанный в 66-ой строке кода, представленного на рис. 3.280.

Рис. 3.285. Фрагмент кода непозволяющий вводить отрицательную цену.

 

Мы соединяемся с базой данных, создавая экземпляр , и настраиваем запрос. В данном случае это INSERT .

 

Рис. 3.286. Фрагмент кода обеспечивающий соединение с базой и вставку данных.

 

Запрос выполняется в базе данных как обычно:

При процедурном подходе следует использовать оператор $result = mysqli_query($sql);

 

Одно существенное различие между INSERT и SELECT заключается в использовании mysqli_affected_rows(). В процедурной версии это функция, а в объектно-ориентированной версии это переменная-член класса , которая хранит количество строк модифицированых в запросе.

 

В предыдущем сценарии функция mysql_num_rows() применялась для определения количества строк, которые будет возвращать SELECT. При написании запросов, которые изменяют базу данных, например, INSERT, DELETE, UPDATE, следует использовать mysql_affected_rows().

 

Чтобы раскрыть назначение строк кода с 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).

Рис. 3.289. Сообщение раскрывающее суть ошибки.

 

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

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

Рис. 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 из РНР. В следующем задании рассматриваются еще некоторые полезные функции, не упомянутые ранее.

 

 

Задание 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 запрос.

 

 

 

Рис. 3.292. Исходный код С:\WebServers\home\localhost\www\php\Lab15_06.php.

 

Результат работы программы Lab15_06.php представлен на рис. 3.293.

 

Рис. 3.293. Результат работы Lab15_06.php.

Код программы 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.