| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| = Урок 2. Проектирование приложения. Чтение из базы данных |
| :jbake-type: tutorial |
| :jbake-tags: tutorials |
| :jbake-status: published |
| :icons: font |
| :syntax: true |
| :source-highlighter: pygments |
| :toc: left |
| :toc-title: |
| :description: Урок 2. Проектирование приложения. Чтение из базы данных - Apache NetBeans |
| :keywords: Apache NetBeans, Tutorials, Урок 2. Проектирование приложения. Чтение из базы данных |
| |
| В этом уроке рассматривается создание и настройка проекта PHP для разработки приложения, создание списка страниц в приложении и определение отношений между ними. Кроме того, основная функциональность разрабатывается и тестируется на данных, введенных в пример базы данных в уроке 1. |
| |
| Создаваемый в этом уроке код PHP выполняет следующие функции. |
| |
| 1. Получает имя лица, введенного пользователем. |
| 2. Проверяет наличие этого лица в базе данных. Если лицо отсутствует в базе данных, выполняется выход с сообщением об ошибке. |
| 3. Отображение таблицы пожеланий этого лица. |
| |
| Текущий документ является частью краткого учебного курса "Создание приложения, управляемого базой данных, в IDE NetBeans для PHP". |
| |
| |
| |
| == Создание проекта PHP |
| |
| Выберите 'Файл' > 'Создать проект' (Ctrl-Shift-N в Windows и Linux, ⌘-Shift-N в ОС Mac). Создайте новый проект PHP с именем "wishlist". После создания проекта PHP по умолчанию он будет содержать файл индекса ``index.php`` . Для получения информации о создании и настройке проекта PHP см. link:project-setup.html[+Настройка проекта PHP+]. |
| |
| |
| == Определение блок-схемы страницы |
| |
| В рамках приложения возможны следующие варианты использования: |
| |
| 1. Пользователь просматривает список "Wish list" другого пользователя. |
| 2. Пользователь регистрируется в качестве нового пользователя. |
| 3. Пользователь входит в систему и создает собственный список пожеланий "Wish list". |
| 4. Пользователь входит в систему и редактирует свой список пожеланий. |
| |
| Для реализации этих базовых функциональных возможностей потребуется добавить следующие файлы PHP. |
| |
| 1. Первая страница index.php для входа в систему, регистрации и перехода к спискам "Wish list" других пользователей. |
| 2. Страница wishlist.php для просмотра списка "Wish list" конкретного пользователя. |
| 3. Страница createNewWisher.php для регистрации в качестве автора пожеланий. |
| 4. Страница editWishList.php для редактирования списка его владельцем. |
| 5. Страница editWish.php для создания и редактирования пожеланий. |
| |
| image::images/page-flow-diagram.png[] |
| |
| После выполнения предварительных действий можно приступить к реализации базовой функциональности приложения. Начать следует с просмотра списка "Wish list" одного из пользователей. Для этой функции не требуется выполнять проверку допустимости, ее можно легко протестировать, поскольку в базу данных уже внесены тестовые данные. Функциональность компонента реализуются на двух страницах – index.php и wishlist.php. |
| |
| |
| == Добавление формы к index.php |
| |
| Файл index.php не содержит код PHP, таким образом, можно просто удалить следующий блок: |
| |
| Файл ``index.php`` используется в двух целях. |
| |
| * Отображение страницы с элементами управления для ввода данных. |
| * Передача введенных данных в другой файл PHP для обработки данных. В этом учебном курсе данные передаются в файл с именем ``wishlist.php`` , который создается в следующем разделе. |
| |
| Эти действия выполняются с использованием формы HTML. Каждая форма HTML содержит следующее. |
| |
| * Набор полей, соответствующих элементам управления на странице. |
| * "Действие", выполняемое после отправки пользователем данных в форме. Действие представлено путем к странице для обработки данных. |
| |
| *Для добавления формы к index.php выполните следующее.* |
| |
| 1. Перейдите к окну "Проекты", разверните узел проекта и узел "Файлы исходного кода", затем дважды щелкните файл ``index.php`` . Файл ``index.php`` откроется в основной области редактора IDE. Файл содержит шаблон для ввода кодов PHP и HTML. |
| |
| NOTE: Можно пропустить предупреждения от средства проверки HTML. |
| |
| |
| . Удалите блок PHP. Файл index.php не содержит код PHP. |
| |
| image::images/remove-php-block.png[] |
| |
| |
| |
| . Откройте "Палитру" из меню "Окно" или нажав Ctrl-Shift-8. |
| |
| |
| . Из раздела *Формы HTML* палитры перетащите форму в раздел <body> файла ``index.php`` . |
| |
| image::images/form-dnd.png[] |
| |
| |
| |
| . Откроется диалоговое окно "Вставить форму". В поле "Действие" введите путь к файлу, в которой форма будет передавать данные. В данном случае введите ``wishlist.php`` . (Этот файл будет создан в том же местоположении, что и файл ``index.php`` . См. <<createNewFile,Создание wishlist.php и тестирование приложения>>.) Выберите метод GET для передачи данных. Присвойте форме произвольное имя, например, ``wishList`` . Нажмите кнопку "ОК" после выполнения действия. |
| |
| image::images/insert-form-dialog.png[] |
| |
| Теперь файл выглядит следующим образом: |
| |
| image::images/blank-form.png[] |
| |
| |
| |
| . Между открывающим и закрывающим тегами формы введите текст "Показать список пожеланий: ". |
| |
| |
| . Перетащите компонент "Ввод текста" из раздела *Формы HTML* палитры в пространство после текста "Показать список пожеланий: ". Откроется диалоговое окно "Вставка ввода текста". |
| |
| |
| . Присвойте вводу название ``user`` . Выберите тип ввода ``text`` . Оставьте все поля пустыми и нажмите кнопку "ОК". |
| |
| image::images/insert-text-input.png[] |
| |
| Теперь файл выглядит следующим образом: |
| |
| image::images/form-with-text-input.png[] |
| |
| |
| |
| . Добавьте пустую сроку над тегом </form>. В эту пустую строку перетащите компонент "Кнопка" из раздела * Формы HTML* палитры. |
| |
| |
| . Откроется диалоговое окно "Вставить кнопку". Введите ``Go`` в поле "Метка" и нажмите кнопку "ОК". |
| |
| image::images/insert-button-dialog.png[] |
| |
| |
| |
| . Теперь форма выглядит так, как показанный ниже код, с одним отличием. В коде ниже атрибут ``method`` явно указан в теге <form>. IDE NetBeans не добавил атрибут метода к используемой форме, поскольку значением по умолчанию этого атрибута является GET. Однако явное указание атрибута ``method`` упрощает понимание кода. |
| |
| [source,xml] |
| ---- |
| <form action="wishlist.php" method="GET" name="wishList"> |
| Show wish list of: |
| <input type="text" name="user" value=""/> |
| <input type="submit" value="Go" /> |
| </form> |
| ---- |
| |
| Обратите внимание на следующие элементы формы. |
| |
| * Открывающий тег <form> содержит атрибут ``action`` . Атрибут action указывает файл, в который форма передает данные. В данном случае файл имеет имя ``wishlist.php`` и находится в той же папке, что и файл ``index.php`` . (Этот файл будет создан в разделе <<createNewFile,Создание wishlist.php и тестирование приложения>>.) |
| * Открывающий тег <form> также содержит метод для применения к переданным данным (GET). PHP использует массив ``$_GET`` или ``$_POST`` для значений, переданных этой формой, в зависимости от значения атрибута ``method`` . В данном случае PHP использует ``$_GET`` . |
| * Компонент ввода ``text`` . Этот компонент — текстовое поле для ввода имени пользователя, список пожеланий которого необходимо просмотреть. Начальное значение текстового поля — пустая строка. Имя этого поля — ``user`` . PHP использует имя поля при создании массива для значений поля. В данном случае массив для значений этого поля — ``htmlentities($_GET["user"])`` . |
| * Компонент ввода ``submit`` со значением "Go". Тип "submit" означает, что поле ввода отображается на странице как кнопка. Значение "Go" — это метка поля. При нажатии пользователем кнопки данные в компоненте ``text`` передаются в файл, указанный в атрибуте ``action`` . |
| |
| |
| == [[Создание wishlist.php и тестирование приложения]] |
| |
| В разделе <<transferDataFromIndexToWishlist,Добавление формы к index.php>> была создана форма, с помощью которой пользователь отправляет имя лица, список пожеланий которого необходимо просмотреть. Имя передается странице ``wishlist.php`` . Однако этой страницы не существует. Если выполнить ``index.php`` , при отправке имени возникнет ошибка "404: Файл не найден". В этом разделе будет создан файл ``wishlist.php`` , затем будет выполнено тестирование приложения. |
| |
| *Для создания wishlist.php и тестирования приложения выполните следующее.* |
| |
| 1. В созданном проекте 'wishlist' щелкните правой кнопкой мыши узел 'Исходные файлы' и выберите 'Создать > Файл PHP' в контекстном меню. Откроется мастер создания веб-страниц PHP. |
| 2. Введите ``wishlist`` в поле "Имя файла" и нажмите кнопку "Готово". |
| 3. Щелкните правой кнопкой мыши узел 'Источники' и выберите 'Выполнить проект' в контекстном меню или щелкните значок 'Выполнить главный проект' image:images/run-main-project-button.png[]на панели инструментов, если проект задан как главный. |
| |
| image::images/index-php-works.png[] |
| |
| |
| |
| . В поле "Show wish list of" введите "Tom" и нажмите "Go". Появится пустая страница со следующим URL-адресом: http://localhost:90/Lesson2/wishlist.php?user=tom. Наличие этого URL-адреса означает, что главная страница функционирует правильно. |
| |
| |
| == Установка подключения и получение идентификатора автора пожеланий |
| |
| В этом разделе сначала к файлу ``wishlist.php`` будет добавлен код для создания подключения к базе данных. Затем будет добавлен код для получения идентификатора автора пожеланий, который был введен в форме ``index.php`` . |
| |
| 1. Дважды щелкните файл wishlist.php. Открывшийся шаблон отличается от index.php. Файл должен начинаться и заканчиваться тегами <html></html> и <body></body>, поскольку файл будет содержать также код HTML. |
| |
| [source,php] |
| ---- |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title></title> |
| </head> |
| <body> |
| <?php |
| // put your code here |
| ?> |
| </body> |
| </html> |
| ---- |
| |
| |
| . Для отображения заголовка после тега открытия <body> и перед генерируемым тегом <?php введите следующий блок кода: |
| |
| [source,php] |
| ---- |
| |
| Wish List of <?php echo htmlentities($_GET["user"])."<br/>";?> |
| ---- |
| |
| Теперь код должен выглядеть следующим образом: |
| |
| |
| [source,php] |
| ---- |
| <body> |
| Wish List of <?php echo htmlentities($_GET["user"])."<br/>"; ?> |
| <?php |
| // put your code here |
| ?> |
| </body> |
| ---- |
| |
| Блок кода PHP выводит на экран данные, которые поступают посредством метода GET в поле "user". Это данные передаются со страницы ``index.php`` , где имя владельца списка "Wish list" – "Tom" – было введено в текстовом поле "user". Повторите действия, указанные на странице <<createNewFile,Testing index.php>>, для проверки того, что wishlist.php функционирует правильно. |
| |
| image::images/wishlist-php-title-works.png[] |
| |
| |
| |
| . Удалите раздел в шаблоне блока PHP с комментарием. В этом месте введите или вставьте следующий код. Этот код открывает подключение к базе данных. |
| |
| *Для базы данных MySQL* |
| |
| |
| [source,php] |
| ---- |
| $con = mysqli_connect("localhost", "phpuser", "phpuserpw"); |
| if (!$con) { |
| exit('Connect Error (' . mysqli_connect_errno() . ') '. mysqli_connect_error()); |
| } |
| //set the default client character |
| set mysqli_set_charset($con, 'utf-8'); |
| ---- |
| |
| *Для базы данных Oracle* |
| |
| |
| [source,php] |
| ---- |
| $con = oci_connect("phpuser", "phpuserpw", "localhost/XE", "AL32UTF8"); |
| if (!$con) { |
| $m = oci_error(); |
| exit('Connect Error ' . $m['message']); |
| } |
| ---- |
| |
| В соответствии с кодом производится попытка подключения к базе данных и выдается сообщение об ошибке в случае неудачи. |
| |
| NOTE: Может потребоваться изменить подключение к базе данных в команде ``oci_connect`` . Стандартный синтаксис — "hostname/service name". Подключение к базе данных Oracle XE в этом фрагменте — "localhost/XE" в соответствии с этим синтаксисом. |
| |
| NOTE: Автозавершение кода IDE NetBeans можно использовать для функций mysqli или OCI8. |
| |
| image::images/codecompletion.png[]image::images/codecompletion-oci.png[] |
| |
| |
| |
| . |
| Под фрагментом кода, описывающим подключение к базе данных, в том же блоке PHP укажите следующий код. Этот код получает идентификатор автора пожеланий, чей список был запрошен. Если автор пожеланий отсутствует в базе данных, код уничтожает/завершает процесс и отображает сообщение об ошибке. |
| |
| *Для базы данных MySQL* |
| |
| |
| [source,php] |
| ---- |
| mysqli_select_db($con, "wishlist"); |
| $user = mysqli_real_escape_string($con, htmlentities($_GET["user"])); |
| $wisher = mysqli_query($con, "SELECT id FROM wishers WHERE name='" . $user . "'"); |
| if (mysqli_num_rows($wisher) < 1) { |
| exit("The person " . htmlentities($_GET["user"]) . " is not found. Please check the spelling and try again"); |
| } |
| $row = mysqli_fetch_row($wisher); |
| $wisherID = $row[0]; |
| mysqli_free_result($wisher); |
| ---- |
| |
| *Для базы данных Oracle.* (Имейте в виду, что oci8 не имеет эквиваленту ``mysqli_num_rows`` ) |
| |
| |
| [source,php] |
| ---- |
| |
| $query = "SELECT id FROM wishers WHERE NAME = :user_bv"; |
| $stid = oci_parse($con, $query); |
| $user = $_GET['user']; |
| |
| oci_bind_by_name($stid, ':user_bv', $user); |
| oci_execute($stid); |
| |
| //Because user is a unique value I only expect one row |
| $row = oci_fetch_array($stid, OCI_ASSOC); |
| if (!$row) { |
| exit("The person " . $user . " is not found. Please check the spelling and try again" ); |
| } |
| $wisherID = $row['ID']; |
| oci_free_statement($stid); |
| ---- |
| |
| Осуществляется выбор данных из базы данных ``wishlist`` с помощью подключения $con. Критерием выбора является имя, полученное со страницы index.php как "user". |
| |
| Синтаксис оператора SQL ``SELECT`` может быть кратко описан следующим образом: |
| |
| * После выполнения оператора SELECT укажите поля, из которых должны быть получены данные. Все поля отмечены звездочкой (*). |
| * После блока FROM укажите имя таблицы, из которой требуется извлечь данные. |
| * Блок WHERE является необязательным. Укажите в нем условия фильтрации. |
| |
| Запрос mysqli возвращает объект результата. OCI8 возвращает выполненное выражение. В любом случае выполняется выборка строки из результатов выполненного запроса и извлекается значение строки идентификатора, которое сохраняется в переменной ``$wisherID`` . |
| |
| Наконец, освобождается результат mysqli или оператор OCI8. Для физического закрытия подключения необходимо освободить все ресурсы, использующие подключение. В противном случае внутренняя система подсчета ссылок PHP сохранит нижележащее подключение к базе данным открытым, даже если ``$con`` неприменимо после вызова ``mysqli_close()`` или ``oci_close()`` . |
| |
| NOTE: Для MySQL параметр ``htmlentities($_GET["user"])`` используется с с escape-символом для предотвращения SQL-инъекций. См. link:http://en.wikipedia.org/wiki/SQL_injection[+статью энциклопедии Wikipedia о введении SQL +] и link:http://us3.php.net/mysql_real_escape_string[+документацию mysql_real_escape_string+]. Несмотря на то, что в контексте этого руководства риск возникновения опасных атак внедрения SQL маловероятен, рекомендуется исключить из участия в запросах MySQL такие строки, которые могли бы быть подвержены подобной атаке. OCI8 позволяет избежать этого благодаря переменным привязки. |
| |
| На данный момент блок PHP готов. При использовании базы данных MySQL файл ``wishlist.php`` теперь выглядит следующим образом. |
| |
| |
| [source,php] |
| ---- |
| |
| Wish List of <?php echo htmlentities($_GET["user"]) . "<br/>"; ?><?php$con = mysqli_connect("localhost", "phpuser", "phpuserpw"); |
| if (!$con) { |
| exit('Connect Error (' . mysqli_connect_errno() . ') ' |
| . mysqli_connect_error()); |
| }//set the default client character set |
| mysqli_set_charset($con, 'utf-8'); |
| mysqli_select_db($con, "wishlist"); |
| $user = mysqli_real_escape_string($con, htmlentities($_GET["user"])); |
| $wisher = mysqli_query($con, "SELECT id FROM wishers WHERE name='" . $user . "'"); |
| if (mysqli_num_rows($wisher) < 1) { |
| exit("The person " . htmlentities($_GET["user"]) . " is not found. Please check the spelling and try again"); |
| } |
| $row = mysqli_fetch_row($wisher); |
| $wisherID = $row[0]; |
| mysqli_free_result($wisher); |
| ?> |
| ---- |
| |
| При использовании базы данных Oracle файл ``wishlist.php`` выглядит следующим образом: |
| |
| |
| [source,php] |
| ---- |
| |
| Wish List of <?php echo htmlentities($_GET["user"]) . "<br/>"; ?> |
| <?php |
| $con = oci_connect("phpuser", "phpuserpw", "localhost/XE", "AL32UTF8"); |
| if (!$con) { |
| $m = oci_error(); |
| exit('Connect Error ' . $m['message']; |
| exit; |
| } |
| $query = "SELECT id FROM wishers WHERE name = :user_bv"; |
| $stid = oci_parse($con, $query); |
| $user = htmlentities($_GET["user"]); |
| oci_bind_by_name($stid, ':user_bv', $user); |
| oci_execute($stid);//Because user is a unique value I only expect one row |
| $row = oci_fetch_array($stid, OCI_ASSOC); |
| if (!$row) { |
| exit("The person " . $user . " is not found. Please check the spelling and try again" ); |
| } |
| $wisherID = $row["ID"]; |
| oci_free_statement($stid); |
| ?> |
| ---- |
| |
| Если при тестировании приложения было неверно введено имя пользователя, появится следующее сообщение. |
| |
| image::images/wishlist-php-title-user-not-found-works.png[] |
| |
| |
| == Отображение таблицы пожеланий |
| |
| В этом разделе будет добавлен код для отображения таблицы HTML пожеланий, связанных с автором пожеланий. Автор пожеланий определяется идентификатором, полученным в коде предыдущего раздела. |
| |
| 1. Под блоком PHP введите или вставьте следующий блок кода HTML. Этот код открывает таблицу, указывает цвет ее границ (черный) и определяет вид заголовка таблицы, содержащего столбцы "Item" и "Due Date". |
| |
| [source,xml] |
| ---- |
| |
| <table border="black"> |
| <tr> |
| <th>Item</th> |
| <th>Due Date</th> |
| </tr> |
| </table> |
| ---- |
| Тег </table> закрывает таблицу. |
| |
| |
| . Введите следующий код блока PHP над закрывающим тегом </table>. |
| |
| *Для базы данных MySQL* |
| |
| |
| [source,php] |
| ---- |
| <?php |
| $result = mysqli_query($con, "SELECT description, due_date FROM wishes WHERE wisher_id=" . $wisherID); |
| while ($row = mysqli_fetch_array($result)) { |
| echo "<tr><td>" . htmlentities($row["description"]) . "</td>"; |
| echo "<td>" . htmlentities($row["due_date"]) . "</td></tr>\n"; |
| } |
| mysqli_free_result($result);mysqli_close($con); |
| ?> |
| ---- |
| |
| *Для базы данных Oracle* |
| |
| |
| [source,php] |
| ---- |
| <?php |
| $query = "SELECT description, due_date FROM wishes WHERE wisher_id = :id_bv"; |
| $stid = oci_parse($con, $query); |
| oci_bind_by_name($stid, ":id_bv", $wisherID); |
| oci_execute($stid); |
| while ($row = oci_fetch_array($stid)) { |
| echo "<tr><td>" . htmlentities($row["DESCRIPTION"]) . "</td>"; |
| echo "<td>" . htmlentities($row["DUE_DATE"]) . "</td></tr>\n"; |
| } |
| oci_free_statement($stid); |
| oci_close($con); |
| ?> |
| ---- |
| |
| Внутри кода: |
| |
| * Посредством запроса SELECT пожелания со сроками их выполнения для указанного пользователя извлекаются в соответствии с идентификатором, который, в свою очередь был извлечен в действии 4; кроме того, пожелания и соответствующие сроки выполнения сохраняются в массиве $result. |
| * С помощью цикла отдельные элементы массива $result выводятся на экран в качестве строк таблиц, пока массив непуст. |
| * Теги <tr></tr> формируют строки, теги <td></td> – ячейки внутри строк, а после символа \n начинается новая строка. |
| * Функция ``htmlentities`` преобразует все символы, имеющие эквивалентные сущности HTML, в сущности HTML. Это помогает предотвратить link:http://en.wikipedia.org/wiki/Cross-site_scripting[+межсайтовые сценарии+]. |
| * В конце функции освобождают все ресурсы (результаты mysqli и выражения OCI8) и закрывают подключение к базе данных. Имейте в виду, что для физического закрытия подключения необходимо освободить все ресурсы, использующие подключение. В противном случае внутренняя система подсчета ссылок PHP сохранит нижележащее подключение к базе данным открытым, даже если подключение неприменимо после вызова ``oci_close()`` или ``mysqli_close()`` . |
| |
| *Предостережение. *Убедитесь, что названия полей базы данных введены точно так, как они указаны при создании таблицы базы данных. Для Oracle по умолчанию названия столбцов возвращаются в верхнем регистре. |
| |
| |
| |
| . Для тестирования приложения выполните проект, как описано в разделе <<createNewFile,Тестирование index.php>>. |
| |
| image::images/wishlist-php-works.png[] |
| |
| |
| == Исходный код приложения на момент завершения текущего урока |
| |
| Для пользователей MySQL: щелкните link:https://netbeans.org/files/documents/4/1928/lesson2.zip[+здесь+] для загрузки исходного кода, отражающего состояние проекта по завершении данного урока. |
| |
| Для пользователей Oracle Database: щелкните link:https://netbeans.org/projects/www/downloads/download/php%252Foracle-lesson2.zip[+сюда+] для загрузки исходного кода, отражающего состояние проекта по завершении данного урока. |
| |
| |
| == Что дальше? |
| |
| link:wish-list-lesson1.html[+<<Предыдущий урок+] |
| |
| link:wish-list-lesson3.html[+Следующий урок >>+] |
| |
| link:wish-list-tutorial-main-page.html[+Назад на главную страницу учебного курса+] |
| |
| |